优化:Toc小程序猜你喜欢功能

引言:来自自创的小程序中热点接口,本小程序专为在校学生自提点餐使用

一、功能描述

该功能作为一个推荐的职责,根据用户最近行为给用户推荐用户可能喜欢去吃的店铺,可能比较简洁,但是需要设计的方面挺多的,需要有三个方面去走:

设计架构如下:

  1. 用户行为采集
  2. 冷热数据隔离
  3. 推荐店铺缓存的预热
  4. 猜你喜欢接口查询(核心)

从这些设计上就能保证在使用接口查询的时候,就不需要花很多时间去分析,保证了热点接口的响应时间处于较低的一个状态,不过对于一个热点接口,不止要保证他的高性能,还需要保证他的高可用,这就需要涉及到降级策略,这些都是一个考量的标准。

二、接口功能实现

用户行为采集

这里我使用到的技术栈有美团的mzt-Biz-Log框架做类似AOP的切面功能,保证用户进店行为日志优雅的实现,加上redis进行统计猜你喜欢服务的用户,使用rocketmq进行日志的统计,实现进店异步化,并且达到削峰限流的效果。

消息队列的异步化,保证了用户正常去访问一个店铺详细的体验,达到日志记录无感化。

由于消息队列是异步线程去处理的,传递用户的消息过来很重要,更加方便去获取到用户线程id

  • 这里使用到的就是美团的mzt-Biz-Log框架,进行优雅的日志记录,后续可以新增一个实现类进行高内聚的做具体的日志完善逻辑
  • 注意这里使用了全局唯一自增的id,后续在分表冷热隔离中会被用到进行删除数据的操作

使用类似AOP的思想对日志的完善,这里我对用户数据分了16个表,保证热点查询不会聚集在单表中,具体的分表学习可以移步到我这篇文章进行学习:

SpringBoot中使用Sharding-JDBC实战(实战+版本兼容+Bug解决)_springboot shardingjdbc-CSDN博客文章浏览阅读3.2k次,点赞23次,收藏37次。这里整理的是使用SpringBoot3.2.4和ShardingSphere-JDBC5.5.0进行分表操作,里面有遇到的bug并且解决的流程,还有结合自己之前做的秒杀博客进行测试分表,很详细_springboot shardingjdbc https://blog.csdn.net/qq_73440769/article/details/143992138?spm=1001.2014.3001.5502

冷热数据隔离

这个功能主要由另外的一个博主进行实现,欢迎参考他的文章进行详细学习:

优化:将针对单一日志表的冷热数据分离类改造成通用类-CSDN博客文章浏览阅读283次,点赞5次,收藏4次。文章介绍了店铺推荐系统中日志数据存储方案的优化过程。原方案将热数据存入Elasticsearch,现改为存储冷数据,并针对代码冗余问题进行重构。通过引入泛型机制实现通用处理类,将固定代码参数化,同时为不同日志类型提供定制化ES处理逻辑。优化后的方案提升了代码复用性,支持多日志表并行处理,并通过线程池提高执行效率。文中详细展示了改进后的代码实现,包括通用日志处理方法、任务创建机制和重试策略等核心功能模块。 https://blog.csdn.net/2401_88959292/article/details/148619523?spm=1001.2014.3001.5502其实思想就是:使用定时任务进行隔离一个月之前的数据,将冷数据进行归档,保证热数据才会被用来进行分析,这样就能极大的削减db的承重,提升查询效率、释放 MySQL 压力,这里隔离的数据库可以不适用es,可以使用一些实时数仓比较合适。

  • 每天凌晨执行,支持分页游标 + 泛型处理;
  • 支持所有进店日志的通用迁移;
  • 使用多线程 + 重试机制处理批量插入,保障稳定性。
  • 每类日志各跑一个线程任务,互不干扰

对于怎么不给时间加索引也能保证比较快速的查询需要隔离的店铺,首先id是自增的,查16个表中最靠近一个月的最小的id,比这个id小的就是一定需要进行删除的,或者给时间字段加上索引也是可以的,实现也是使用类似的思想。

推荐店铺缓存的预热

目的:为了保证用户的体验,将复杂的分析过程放在了凌晨,使用定时任务进行分析,将分析好的结果放进redis,这样子用户体验感就极佳,欢迎参考这位博主的思路:

优化日志分析店铺推荐方案:用户范围的精确度以及ES与MySQL的查询效率差异-CSDN博客文章浏览阅读785次,点赞6次,收藏15次。本文针对原有店铺推荐方案的两个核心问题提出优化方案。问题一是用户范围不精确,通过Redis记录用户每月首次进店行为作为登录标识,并统计热点用户(月登录≥14天);问题二是数据处理效率低,改用MySQL存储热数据(建立用户-店铺映射),ES仅作冷备份。方案采用Lua脚本确保原子性操作,并优化了权重计算模型(店铺50%、分类30%、分区20%)。最终实现通过分批并行处理用户日志数据,结合个性化推荐与热门店铺补充机制,显著提升了10万级用户日志场景下的推荐效率和精准度。 https://blog.csdn.net/2401_88959292/article/details/148618437?spm=1001.2014.3001.5502

为避免推荐实时计算带来性能瓶颈,我们采用“离线计算 + 缓存预热”方式,利用定时任务每天构建用户维度的推荐结果,缓存到 Redis 中。

  • 用户分批处理(活跃用户访问≥7天),每批200人,异步线程池分析;
  • 推荐维度包括:访问频率、店铺分类、分区,采用加权模型打分;
  • 冷热数据分离后,在构建推荐时能快速分析历史行为;
  • 最终结果缓存到 Redis 的 STORE_RECOMMEND_ONE:{userId} 列表中;
  • 未登录用户使用通用热门推荐(Top 打分店铺)。

这里讲一下推荐维度的意义:

我们可以参考先成的推荐系统,比如抖音刷碎片,会有几个考量:

  • 比如你爱刷这个人视频比较多,就会给你很多推荐;
  • 比如你喜欢刷这类型视频比较多,也会给你推荐很多类似的;
  • 比如你比较喜欢刷当前地区的视频,抖音也会给你推荐很多

参考上面的三点,就可以类比到我们的这些维度。我们会拿出日志,取出这些维度的数据,给每个维度进行赋分,各乘于一个百分比,最后相加得到最后得分,取出前四名的放进最后预热的结果中。

这里大家可能会想,是给所有用户进行分析吗。回答是:不是。因为热点分析的消耗成本是很大的,有些用户不是小程序常驻,只是偶尔使用,甚至只是为了体验一次,这些用户的话推荐优先级就不是最高的,所以我们会在日志记录的时候就记录需要被推荐的用户,这些用户的考量标准是:一个月内最少使用一周,这里我使用了redis的自增id进行记录有哪些用户一个月内使用了多少次,用set集合保证一个用户一天最多记录一次就好,这里就可以得到我需要分析的用户。

猜你喜欢接口查询(核心)

这里是重中之重,这里需要保证高性能并且高可用,那就需要避免走db的路线,最好是走缓存。高可用就需要准备一些降级策略,避免服务挂掉。

这个是我对这个接口的设计流程图,使用了多层的降级策略,保证了接口的高可用。

如果登录的用户没有对应的推荐缓存或者没有登录的用户,需要走降级策略:

1、第一层降级

这里会取出默认策略中推荐的缓存店铺,如果有很特殊的情况导致这些缓存失效了,就需要继续服务降级去完善默认推荐的缓存店铺

2、第二层降级

这里如果没有推荐店铺就会去redis里面去随机四个店铺进行填充,这里为啥不用分布式锁保证只有一个用户更新默认推荐店铺,可以这样子理解,在一开始有预检,一家很大程度的避免有不同推荐店铺的行为,即使在短时间内有很多线程过了这个预检测,我基于redis单线程的特性,指令在机器里面是单线程执行的特性,使用lua脚本保证各个线程执行指令的有序性,就能保证只有第一个线程的策略是实施的,后续线程的策略都不会成功,大家可能又会想,还是存在很多用户推荐店铺的数据不一致啊,再换个角度,我们这里的推荐店铺都是一个随机策略,哪怕是不同用户的推荐不同又有什么问题呢吗,下面给出lua脚本的实现:

其实大家会发现,这里使用了redis进行随机,就可能极端情况下会出现缓存一致性的问题,出现这个问题,那就继续服务降级。不过有个情况是不可能出现问题的,出现也会在及其短的时间内进行避免,可以关注下面这段代码:

如果这个店铺ids集合的数据量少于4,就会导致这些线程在不断的更新默认店铺的缓存,这岂不是灾难性的,其实这个redis缓存和店铺详细缓存在小程序各个接口中多多少少都用到了,如果没有了,点开小程序,也会启动别的接口进行redis缓存的重构,对于我们目前小卡拉米小程序,还是不需要考虑这点带来的影响,并发并没美团那么高。

3、第三层降级

根据上一点讲过的缓存不一致问题,也就是和db的不一致,redis中ids缓存和店铺集合缓存不一致的问题,关于和db的不一致问题,很多方案都是加锁,然后只用一个线程进行查db更新缓存,避免缓存击穿;关于第二个不一致问题,我在那个流程图里面有做了解释,大家可以参考一下。

4、第四层降级

可以参考第三层降级里面,如果遇到了缓存穿透,就需要走空缓存的策略进一步一面,继续服务降级,通过上面四层的降级,我觉得整个接口处于相对比较好的高可用状态。

三、优化

可以看到上面第一版的方案中,我是拿到一个店铺id就去redis查一个店铺,这种就会带来一个问题,无法充分利用redis的性能,对于传输网络的开销还是很大的,就会导致大部分时间浪费在网络上了,所以我把多次用单个id去查redis改为一次用多个id去查redis。

1、优化方案实现

完善前:

完善后:

优化了多次网络带来的开销:

第一次降级前代码不变。

具体修改为多次查询的逻辑:

具体使用:

默认策略修复:

2、性能测试

这里博主已经做了多次测试,下面的数据大致是均值的水平,所以只提供了一份测试数据(测试默认缓存带来的优化)

(1)响应测试(ABtest):

优化前:

缓存重构的时候(203ms):

缓存不重构的时候(135ms):

优化后:

缓存重构的时候(155ms):

缓存不重构的时候(75ms):

在对推荐缓存逻辑进行优化后,系统整体响应时间得到了明显改善。

  • 缓存不重构的场景下,响应时间从 135ms 降至 76ms,优化幅度约为 43.7%
  • 缓存重构的场景中,响应时间从 203ms 降至 155ms,优化幅度约为 23.6%

(2)jmeter测吞吐量

这里博主jmeter配置有些问题,虽然是异常,但是是正常走代码逻辑的。

1000用户qps1000测试(225.6/sec):

1用户qps1000测试(654.9/sec): 

四、最后

欢迎大家给更多的建议,toc菜鸟希望可以得到更多好的方案进行学习,期待大家指点。

大家也可以关注一下这个博主,这个功能是由我们两个共同进行一个实现和完善:

Yilena-CSDN博客Yilena擅长八股轻松学,业务场景方案分析以及优化方案,解决方案,等方面的知识 https://blog.csdn.net/2401_88959292?type=blog

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/90819.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/90819.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Datawhale AI 夏令营:让AI理解列车排期表 Notebook(Baseline拆解)

Step1、读取数据 import pandas as pd import requests import re import json from tqdm import tqdm# 读取数据 data pd.read_excel(data/info_table.xlsx) data data.fillna(无数据) dataStep2、注册硅基流动https://cloud.siliconflow.cnQwen/Qwen3-8B 模型可以免费使用&…

vue写的app设置角标

原生App角标(UniApp示例)调用plus.runtime.setBadgeNumber方法设置安卓/iOS角标:javascriptCopy Code// 设置角标 plus.runtime.setBadgeNumber(99); // 清除角标(部分平台需特殊处理) plus.runtime.setBadgeNumber(0)…

GAN/cGAN中到底要不要注入噪声

MelGAN论文MelGAN针对的是从mel谱生成语音,里面说当条件很强的时候,随机噪声就没啥用了,因此没将noise注入到生成器中;运用的判别器也仅有1个输入,不是cGAN的形式image-to-image translation with conditional adversa…

备份一下我的 mac mini 的环境变量配置情况

export PATH“/opt/homebrew/bin:$PATH” #THIS MUST BE AT THE END OF THE FILE FOR SDKMAN TO WORK!!! export SDKMAN_DIR“HOME/.sdkman"[[−s"HOME/.sdkman" [[ -s "HOME/.sdkman"[[−s"HOME/.sdkman/bin/sdkman-init.sh” ]] && so…

JVM学习日记(十)Day10

G1回收器 这一篇是详细说明G1回收器的,因为他相对来说确实是个缝合怪,上篇的内容又太多了所不清楚,所有这一篇进行详细的说明, 第一个呢就是其实G1是兼顾并行和并发的,简单来说就是既可以并行也可以并发,…

使用IP扫描工具排查网络问题

随着企业的发展,网络中会新增各类设备,从台式机、服务器到物联网设备和虚拟机(VMs),所有这些设备都通过复杂的子网和虚拟局域网(VLAN)相连。 这种复杂性给 IT 团队带来了压力,他们需…

Wireshark TS | 发送数据超出接收窗口

前言 来自于测试中无意发现到的一个接收窗口满的案例,特殊,或者可以说我以前都没在实际场景中见过。一开始都没整太明白,花了些精力才算是弄清楚了些,记录分享下。 问题说明 在研究拥塞控制的慢启动阶段时,通过 packet…

C语言自定义数据类型详解(四)——联合体

好的,接下来我们来学习最后一个自定义数据类型——联合体。 一、什么是联合体: 联合体又叫共用体,用关键字union来进行定义。又因为所有的成员变量共用同一段内存空间(关于这一点,我们不久就会加以验证)&…

[python][flask]Flask-Login 使用详解

1. 简介Flask-Login 是 Flask 的一个扩展,专门用于处理用户认证相关的功能。它提供了用户会话管理、登录/注销视图、记住我功能等常见认证需求,让开发者能够快速实现安全的用户认证系统。2. 安装与基础配置首先,需要安装 Flask-Login&#xf…

【WebGPU学习杂记】WebAssembly中的relaxed_madd指令到底做了什么?

relaxed_madd 这条指令到底做了什么核心&#xff1a;relaxed_madd 是一个分量级别 (Component-wise) 的操作 首先&#xff0c;最重要的一点是&#xff1a;v128.relaxed_madd<f32>(a, b, c) 不是矩阵乘法。它是一个在三个向量 a, b, c 之间进行的、逐个分量的、并行的融合…

【全新上线】境内 Docker 镜像状态监控

境内 Docker 镜像状态监控&#xff1a;您的 Docker 加速伴侣 在当今云计算和容器化技术飞速发展的时代&#xff0c;Docker 已成为开发者不可或缺的工具。然而&#xff0c;对于身处国内的用户而言&#xff0c;访问境外 Docker Hub 等镜像仓库时常会遭遇网络延迟和连接不稳定的困…

Visual Studio中部署PaddleOCRv5 (借助ncnn框架)

PaddleOCRv5_ncnn PaddleOCRv5 在Visual Studio中进行图片OCR检测&#xff08;ncnn框架open-mobile实现)&#xff0c;尝试对nihui的ncnn-android-ppocrv5检测算法的剥离与移植。 本项目Github链接如下&#xff1a;PaddleOCRv5_ncnn 写在前面 本仓库代码是基于nihui的ncnn-a…

中级全栈工程师笔试题

解释ACID特性&#xff0c;如何在node.js中实现事务操作针对React单页应用&#xff0c;请提供至少5种性能优化方案&#xff0c;并解释其原理&#xff1a; 减少首屏加载时间优化渲染性能资源加载策略状态管理优化代码分割方案 如何防止以下攻击&#xff1a; JWT令牌挟持Graph QL查…

Windows---动态链接库Dynamic Link Library(.dll)

DLL的“幕后英雄”角色 在Windows操作系统的生态中&#xff0c;有一类文件始终扮演着“幕后英雄”的角色——它们不像.exe文件那样直接呈现为用户可见的程序窗口&#xff0c;却支撑着几乎所有应用程序的运行&#xff1b;它们不单独执行&#xff0c;却承载着系统与软件的核心功…

深入分析计算机网络传输层和应用层面试题

三、传输层面试题&#xff08;Transmission Layer&#xff09;传输层位于 OSI 七层模型的第四层&#xff0c;它的核心任务是为两个主机之间的应用层提供可靠的数据传输服务。它不仅承担了数据的端到端传输&#xff0c;而且还实现了诸如差错检测、数据流控制、拥塞控制等机制&am…

【RH134 问答题】第 2 章 调度未来任务

目录crontab 文件中的用户作业时间格式怎么解释&#xff1f;如果需要以当前用户身份计划周期性作业&#xff0c;在上午 8 点到晚上 9 点之间每两分钟一次输出当前日期和时间&#xff0c;该作业只能在周一到周五运行&#xff0c;周六或周日不能运行。要怎么做&#xff1f;要计划…

【ee类保研面试】通信类---信息论

25保研er&#xff0c;希望将自己的面试复习分享出来&#xff0c;供大家参考 part0—英语类 part1—通信类 part2—信号类 part3—高数类 part100—self项目准备 文章目录**面试复习总纲****Chap2: 熵、相对熵和互信息 (Entropy, Relative Entropy, and Mutual Information)****…

vue2+node+express+MongoDB项目安装启动启动

文章目录 准备环境 安装MongoDB 安装 MongoDB Compass(图形化数据库管理工具) 安装 Postman(接口测试工具) 项目结构 配置项目代理 项目启动 提交项目 生成Access Token 准备环境 默认含有node.js、npm 安装MongoDB 下载地址:https://www.mongodb.com/try/download/com…

JavaEE初阶第十二期:解锁多线程,从 “单车道” 到 “高速公路” 的编程升级(十)

专栏&#xff1a;JavaEE初阶起飞计划 个人主页&#xff1a;手握风云 目录 一、多线程案例 1.1. 定时器 一、多线程案例 1.1. 定时器 定时器是软件开发的一个重要组件&#xff0c;是一种能够按照预设的时间间隔或在特定时间点执行某个任务或代码片段的机制。你可以把它想象成…

EDoF-ToF: extended depth of field time-of-flight imaging解读, OE 2021

1. 核心问题&#xff1a;iToF相机的“景深”死穴我们之前已经详细讨论过&#xff0c;iToF相机的“景深”&#xff08;有效测量范围&#xff09;受到光学散焦的严重制约。问题根源&#xff1a; 当iToF相机的镜头散焦时&#xff0c;来自场景不同深度的光信号会在传感器像素上发生…