电商系统分类树查询功能优化方案总结

news2024/12/24 20:51:01

前言

分类树查询功能,在各个业务系统中可以说随处可见,特别是在电商系统中。

但就是这样一个简单的分类树查询功能,我们却优化了5次。

到底是怎么回事呢?

背景

我们的网站使用了SpringBoot推荐的模板引擎:Thymeleaf,进行动态渲染。

它是一个XML/XHTML/HTML5模板引擎,可用于Web与非Web环境中的应用开发。

它提供了一个用于整合SpringMVC的可选模块,在应用开发中,我们可以使用Thymeleaf来完全代替JSP或其他模板引擎,如Velocity\FreeMarker等。

前端开发写好Thymeleaf的模板文件,调用后端接口获取数据,进行动态绑定,就能把想要的内容展示给用户。

由于当时这个是从0-1的新项目,为了开快速开发功能,我们第一版接口,直接从数据库中查询分类数据,组装成分类树,然后返回给前端。

通过这种方式,简化了数据流程,快速把整个页面功能调通了。

第1次优化

我们将该接口部署到dev环境,刚开始没啥问题。

随着开发人员添加的分类越来越多,很快就暴露出性能瓶颈。

我们不得不做优化了。

我们第一个想到的是:加Redis缓存

流程图如下:

于是暂时这样优化了一下:

  1. 用户访问接口获取分类树时,先从Redis中查询数据。

  2. 如果Redis中有数据,则直接数据。

  3. 如果Redis中没有数据,则再从数据库中查询数据,拼接成分类树返回。

  4. 将从数据库中查到的分类树的数据,保存到Redis中,设置过期时间5分钟。

  5. 将分类树返回给用户。

我们在Redis中定义一个了key,value是一个分类树的json格式转换成了字符串,使用简单的key/value形式保存数据。

经过这样优化之后,dev环境的联调和自测顺利完成了。

第2次优化

我们将这个功能部署到st环境了。

刚开始测试同学没有发现什么问题,但随着后面不断地深入测试,隔一段时间就出现一次首页访问很慢的情况。

于是,我们马上进行了第2次优化。

我们决定使用Job定期异步更新分类树到Redis中,在系统上线之前,会先生成一份数据。

当然为了保险起见,防止Redis在哪条突然挂了,之前分类树同步写入Redis的逻辑还是保留。

于是,流程图改成了这样:

增加了一个job每隔5分钟执行一次,从数据库中查询分类数据,封装成分类树,更新到Redis缓存中。

其他的流程保持不变。

此外,Redis的过期时间之前设置的5分钟,现在要改成永久。

通过这次优化之后,st环境就没有再出现过分类树查询的性能问题了。

第3次优化

测试了一段时间之后,整个网站的功能快要上线了。

为了保险起见,我们需要对网站首页做一次压力测试。

果然测出问题了,网站首页最大的qps是100多,最后发现是每次都从Redis获取分类树导致的网站首页的性能瓶颈。

我们需要做第3次优化。

该怎么优化呢?

答:加内存缓存。

如果加了内存缓存,就需要考虑数据一致性问题。

内存缓存是保存在服务器节点上的,不同的服务器节点更新的频率可能有点差异,这样可能会导致数据的不一致性。

但分类本身是更新频率比较低的数据,对于用户来说不太敏感,即使在短时间内,用户看到的分类树有些差异,也不会对用户造成太大的影响。

因此,分类树这种业务场景,是可以使用内存缓存的。

于是,我们使用了Spring推荐的caffine作为内存缓存。

改造后的流程图如下:

  1. 用户访问接口时改成先从本地缓存分类数查询数据。

  2. 如果本地缓存有,则直接返回。

  3. 如果本地缓存没有,则从Redis中查询数据。

  4. 如果Redis中有数据,则将数据更新到本地缓存中,然后返回数据。

  5. 如果Redis中也没有数据(说明Redis挂了),则从数据库中查询数据,更新到Redis中(万一Redis恢复了呢),然后更新到本地缓存中,返回返回数据。

需要注意的是,需要改本地缓存设置一个过期时间,这里设置的5分钟,不然的话,没办法获取新的数据。

这样优化之后,再次做网站首页的压力测试,qps提升到了500多,满足上线要求。

第4次优化

之后,这个功能顺利上线了。

使用了很长一段时间没有出现问题。

两年后的某一天,有用户反馈说,网站首页有点慢。

我们排查了一下原因发现,分类树的数据太多了,一次性返回了上万个分类。

原来在系统上线的这两年多的时间内,运营同学在系统后台增加了很多分类。

我们需要做第4次优化。

这时要如何优化呢?

限制分类树的数量?

答:也不太现实,目前这个业务场景就是有这么多分类,不能让用户选择不到他想要的分类吧?

这时我们想到最快的办法是开启nginxGZip功能。

让数据在传输之前,先压缩一下,然后进行传输,在用户浏览器中,自动解压,将真实的分类树数据展示给用户。

之前调用接口返回的分类树有1MB的大小,优化之后,接口返回的分类树的大小是100Kb,一下子缩小了10倍。

这样简单的优化之后,性能提升了一些。

第5次优化

经过上面优化之后,用户很长一段时间都没有反馈性能问题。

但有一天公司同事在排查Redis中大key的时候,揪出了分类树。之前的分类树使用key/value的结构保存数据的。

我们不得不做第5次优化。

为了优化在Redis中存储数据的大小,我们首先需要对数据进行瘦身。

只保存需要用到的字段。

例如:

@AllArgsConstructor
@Data
public class Category {

    private Long id;
    private String name;
    private Long parentId;
    private Date inDate;
    private Long inUserId;
    private String inUserName;
    private List<Category> children;
}

像这个分类对象中inDate、inUserId和inUserName字段是可以不用保存的。

修改自动名称。

例如:

@AllArgsConstructor
@Data
public class Category {
    /**
     * 分类编号
     */
    @JsonProperty("i")
    private Long id;

    /**
     * 分类层级
     */
    @JsonProperty("l")
    private Integer level;

    /**
     * 分类名称
     */
    @JsonProperty("n")
    private String name;

    /**
     * 父分类编号
     */
    @JsonProperty("p")
    private Long parentId;

    /**
     * 子分类列表
     */
    @JsonProperty("c")
    private List<Category> children;
}

由于在一万多条数据中,每条数据的字段名称是固定的,他们的重复率太高了。

由此,可以在json序列化时,改成一个简短的名称,以便于返回更少的数据大小。

这还不够,需要对存储的数据做压缩。

之前在Redis中保存的key/value,其中的value是json格式的字符串。

其实RedisTemplate支持,value保存byte数组

先将json字符串数据用GZip工具类压缩成byte数组,然后保存到Redis中。

再获取数据时,将byte数组转换成json字符串,然后再转换成分类树。

这样优化之后,保存到Redis中的分类树的数据大小,一下子减少了10倍,Redis的大key问题被解决了。

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

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

相关文章

案例5:Java大学生创新创业项目管理设计与实现任务书

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

RK3568|3588|3566处理器属于什么档次?

随着科技的迅猛发展&#xff0c;处理器作为计算机和电子设备的核心组件&#xff0c;其性能的提升对于设备的功能和用户体验起着至关重要的作用。在处理器市场中&#xff0c;不同的处理器被划分为不同的档次&#xff0c;以便用户能够更好地选择适合自己需求的产品。那么&#xf…

解决git clone与git push出现的若干问题:Failed to connect to github.com port 443: Timed out

1 连接github失败问题汇总&#xff1a;Failed to connect to github.com port 443: Timed out 1.1 解决ping不通github.com的问题 1.1.1 查询github的IP的地址 在以下链接找到网页显示github的ip地址http://github.global.ssl.fastly.net.ipaddress.com/&#xff0c;如图所示…

FSW26现金回收RS FSW43 信号和频谱分析仪

Rohde & Schwarz FSW26信号和频谱分析仪&#xff0c;2 Hz - 26.5 GHz 高性能 Rohde & Schwarz (R&S) FSW26 信号和频谱分析仪专为方便、准确和快速而设计。其独特的触摸屏、直观的多视图结果显示和优化的用户指南使 R&S FSW26 分析仪的操作高效方便。凭借其无…

玩转ChatGPT:AskYourPDF插件尝鲜

一、写在前面 首先&#xff0c;吐槽一下&#xff0c;感觉被CloseAI耍了&#xff1a; 上周发文说这一周对PLUS开放联网和插件功能&#xff0c;搞得网络一片狂欢。但是今天通过身边统计学发现&#xff0c;开通了PLUS后&#xff0c;拥有联网和插件功能的只是少数&#xff08;而且…

TCP连接不释放,应用产生大量CLOSE_WAIT状态TCP

一、起源 23年元旦期间&#xff0c;大家都沉浸在一片祥和的过节气氛当中。 “滴滴滴”&#xff0c;这头同事的电话响起&#xff0c;具体说些什么我也没太在意&#xff0c;但见同事接完电话之后展现出了一副懊恼夹杂着些许不耐烦的表情。 我不解问道&#xff1a;“怎么了&…

扇区(sector),块(block),簇(cluster)

1.硬盘(可以认为硬盘就是磁盘) # fdisk -l Disk /dev/cciss/c0d0: 146.7 GB, 146778685440 bytes 255 heads, 63 sectors/track, 17844 cylinders Units cylinders of 16065 * 512 8225280 bytes 可以看到几个名词&#xff1a;heads/sectors/cylinders&#xff0c;分别就是磁…

altium Designer22 AD22 CAD电子绘图员三级知识点操作说明

文章目录 AD22一、解决局域网中多台电脑冲突&#xff1a;禁用license的网络功能二、添加库文件三、库的使用四、库绘制1、原理图库绘制2、PCB封装库绘制 五、动态标题栏六、原理图模板的使用七、层次电路图设计1、在母图上放置页面符2、给sheet symbol添加Entry,名字与子图原理…

案例4:Java宠物管理系统设计与实现开题报告

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

后端返回文件流,前端实现点击按钮自动导出Excel文件

首先封装接口&#xff0c;此接口需要传Excel目标数据中的主键id&#xff0c;注意要加上responseType: blob import request from /utils/request; const prefix xxxxx /test;export async function exportExcel(id: any) {return request(prefix /export-excel/ id,{metho…

同科医药×实在智能丨数字员工“进驻”上市企业,让健康服务更近、更快、更优惠!

数字化浪潮构成了新世界跳动的脉搏&#xff0c;在医药行业转型的大环境下&#xff0c;实现数字化升级已经成为医药企业走向未来、拓展全球市场的必由之路。 近日&#xff0c;济南同科医药物流有限公司&#xff08;简称“同科医药”&#xff0c;系同科股份全资子公司&#xff0c…

用“平面两点距离”求三角形面积及多边形面积

大于 32 边的多边形&#xff0c;都可以任一顶点发出的边切分为 n-2 个三角形。 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程》&#xff0c;不仅仅是基础那么简单…… 地址&#…

IIC通信理解

前言 就个人对IIC通信的理解&#xff0c;通过用图文的方式&#xff0c;尽量简洁的记录下此文。希望能对大家理解IIC通信协议有所帮助。 理解IIC 对于IIC协议的理解&#xff0c;我个人是将完整的IIC时序协议&#xff0c;分成六大块理解。分别是开始条件,结束条件,发送字节,发送字…

数智赋能,专精特新 | 数说故事揽获多项荣誉认定

迈进2023崭新的节点&#xff0c; 数说故事秉持着数据驱动智能决策的使命&#xff0c; 专精特新&#xff0c;砥砺深耕&#xff0c; 拥抱大模型&#xff0c;算法技术迈上新台阶&#xff1b; 推陈出新&#xff0c;产品线持续迭代升级&#xff1b; 以行业领先的技术、专业的数…

基础IO(三)

软硬链接和动静态库 1.软硬链接2.动态库和静态库2.1理解现象2.2静态库的设计2.3动态库2.4动态库的配置2.5动态库的理解 &#x1f31f;&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f;&#x1f31f; &#x1f680;&#x1f680;系列专栏&#xff1a;【Linux…

Kafka中时间轮算法的使用

简介&#xff1a; Kafka的心跳处理机制竟然用到了时间轮算法&#xff1f; Broker端与客户端的心跳在Kafka中非常的重要&#xff0c;因为一旦在一个心跳过期周期内(默认10s)&#xff0c;Broker端的消费组组协调器(GroupCoordinator)会把消费者从消费组中移除&#xff0c;从而触…

U盘数据丢失怎么恢复?优盘数据恢复,看这4个方法!

案例&#xff1a;U盘数据丢失怎么恢复&#xff1f; 【我的U盘里真的存了很多重要的视频和图片&#xff0c;但是前段时间U盘好像中病毒了&#xff0c;导致我很多的图片都丢失了&#xff01;大家有什么好方法可以帮我恢复U盘中的重要数据吗&#xff1f;真的超级感谢&#xff01;…

ZED使用指南(五)

六、其他 1、相机 &#xff08;1&#xff09;选择视频模式 左右视频帧同步&#xff0c;以并排格式作为单个未压缩视频帧流式传输。 在ZED Explorer或者使用API可以改变视频的分辨率和帧率。 &#xff08;2&#xff09;选择输出视图 ZED能以不同的格式输出图像&#xff0c;…

基于Java+SpringBoot+Mybaties+Layui 小区物业管理系统设计与实现

一.项目介绍 小区物业管理系统分为两类&#xff0c;一类是业主、一类是管理员 业主的功能有&#xff1a;小区首页、房屋购买、车位购买、公告通知、出入登记、投诉服务、报修服务、关于我们 管理员的功能有&#xff1a;楼宇管理、住房管理、车位管理、物业管理、收费项目管理、…

yolov8seg模型转onnx转ncnn

yolov8是yolo的最新版本&#xff0c;可做图像分类&#xff0c;目标检测&#xff0c;实例分割&#xff0c;姿态估计。 主页地址 这里测试一个分割模型。 模型如下 选yolov8n-seg模型&#xff0c;转成onnx&#xff0c;再转ncnn测试。 yolov8s-seg的ncnn版可以直接用这个 如果用…