在电商系统中,分类树查询是一个基础且高频的功能,然而这个看似简单的功能背后却隐藏着不小的性能挑战。本文将分享我们在实际项目中对分类树查询功能进行五次优化的全过程,看如何将查询耗时从 2 秒缩短至 0.1 秒,为用户提供更流畅的体验。

一、初始版本:从数据库直接查询

我们的项目采用 Spring Boot 框架,前端使用 Thymeleaf 模板引擎进行动态渲染。在项目初期,为了快速开发功能,分类树查询接口直接从数据库中查询分类数据,组装成分类树后返回给前端。

这种简单直接的方式虽然快速实现了功能,但随着分类数据的不断增加,性能问题很快暴露出来。在开发环境中,当分类数量较多时,接口响应时间逐渐变长,甚至达到了 2 秒,严重影响了用户体验。

二、第一次优化:引入 Redis 缓存

面对性能瓶颈,我们首先想到的是添加 Redis 缓存。优化后的流程如下:

  1. 用户访问接口获取分类树时,先从 Redis 中查询数据。
  2. 如果 Redis 中有数据,直接返回。
  3. 如果 Redis 中没有数据,从数据库中查询数据,拼接成分类树返回。
  4. 将从数据库中查到的分类树数据保存到 Redis 中,设置过期时间为 5 分钟。

通过这种方式,大部分请求可以直接从 Redis 中获取数据,减少了数据库的访问压力。经过测试,开发环境的接口响应时间得到了明显改善,联调和自测顺利完成。

三、第二次优化:异步定期更新缓存

将功能部署到测试环境后,初期测试没有发现问题,但随着测试的深入,隔一段时间就会出现首页访问很慢的情况。分析发现,当 Redis 缓存过期时,大量请求同时访问数据库,导致数据库压力过大,从而影响了性能。

为了解决这个问题,我们决定使用 Job 定期异步更新分类树到 Redis 中。具体优化措施如下:

  1. 增加一个 Job,每隔 5 分钟执行一次,从数据库中查询分类数据,封装成分类树,更新到 Redis 缓存中。
  2. 保留原来的分类树同步写入 Redis 的逻辑,以防止 Redis 突然挂掉。
  3. 将 Redis 的过期时间改为永久。

这次优化后,测试环境再也没有出现分类树查询的性能问题。

四、第三次优化:添加内存缓存

在网站即将上线前,我们对首页进行了压力测试,发现最大 QPS 只有 100 多,性能瓶颈依然存在。经过分析,我们发现每次都从 Redis 获取分类树是导致性能问题的主要原因。

于是,我们决定添加内存缓存。考虑到分类数据更新频率较低,即使不同服务器节点的内存缓存数据存在短暂的不一致,也不会对用户造成太大影响,因此选择使用 Spring 推荐的 Caffeine 作为内存缓存。优化后的流程如下:

  1. 用户访问接口时,先从本地内存缓存中查询分类树数据。
  2. 如果本地缓存有数据,直接返回。
  3. 如果本地缓存没有数据,从 Redis 中查询数据。
  4. 如果 Redis 中有数据,将数据更新到本地缓存中,然后返回。
  5. 如果 Redis 中也没有数据(说明 Redis 挂了),从数据库中查询数据,更新到 Redis 中,然后更新到本地缓存中,返回数据。
  6. 设置本地缓存的过期时间为 5 分钟,以便获取新的数据。

这次优化效果显著,再次进行压力测试时,QPS 提升到了 500 多,满足了上线要求。

五、第四次优化:开启 GZip 压缩

使用了很长一段时间都没有出现问题。但两年后的一天,有用户反馈网站首页有点慢。经过排查,我们发现分类树的数据已经增加到了上万个,一次性返回的数据量太大,导致网络传输耗时较长。

针对这个问题,我们想到了开启 Nginx 的 GZip 功能,让数据在传输之前先进行压缩。之前调用接口返回的分类树数据大小为 1MB,开启 GZip 压缩后,数据大小缩小到了 100KB,一下子缩小了 10 倍,性能得到了明显提升。

六、第五次优化:优化 Redis 存储

在一次 Redis 大 key 排查中,分类树数据被揪了出来。原来,我们一直使用简单的 key/value 结构在 Redis 中保存分类树数据,随着分类数量的增加,这个 value 变得越来越大,成为了 Redis 中的大 key,影响了 Redis 的性能。

为了解决这个问题,我们从以下几个方面进行了优化:

  1. 数据瘦身:只保存需要用到的字段,去除了如 inDate、inUserId 和 inUserName 等不必要的字段。
  2. 修改字段名称:在 JSON 序列化时,将字段名称改为简短的名称,减少数据量。例如,将 id 改为 i,name 改为 n 等。
  3. 数据压缩:使用 GZip 工具类将 JSON 字符串压缩成 byte 数组,然后保存到 Redis 中。获取数据时,再将 byte 数组解压并转换成 JSON 字符串。

例如

@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;
}

例如

@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;
}

经过这些优化,保存到 Redis 中的分类树数据大小减少了 10 倍,成功解决了 Redis 的大 key 问题。

七、优化成果总结

通过这五次优化,分类树查询的性能得到了显著提升:

  • 初始版本:响应时间约 2 秒
  • 最终版本:响应时间约 0.1 秒
  • QPS 从 100 多提升到 500 多
  • 数据传输量从 1MB 减少到 100KB 左右
  • Redis 中的数据存储量减少了 10 倍

八、经验启示

  1. 性能优化是一个持续的过程:随着业务的发展和数据量的增加,原来的优化措施可能会逐渐失效,需要持续关注性能问题并进行优化。
  2. 缓存策略的选择很重要:根据数据的特点和业务需求,选择合适的缓存策略,如 Redis 缓存、内存缓存等,并合理设置缓存过期时间。
  3. 数据压缩不容忽视:在数据传输和存储过程中,合理使用数据压缩技术可以有效减少数据量,提高性能。
  4. 数据库操作要谨慎:数据库是系统的瓶颈之一,应尽量减少对数据库的访问,避免大量并发请求同时访问数据库。
  5. 代码优化细节决定成败:在实际开发中,一些看似微小的优化,如字段名称的简化、不必要字段的去除等,累积起来也能带来显著的性能提升。

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

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

相关文章

Ansible 介绍及安装

简介 Ansible 是一款开源的自动化工具&#xff0c;广泛应用于配置管理、应用部署、任务自动化以及多节点管理等领域。它由 Michael DeHaan 于 2012 年创建&#xff0c;ansible 目前已经已经被红帽官方收购&#xff0c;是自动化运维工具中大家认可度最高的&#xff0c;并且上手…

超光谱相机的原理和应用场景

超光谱相机是光谱成像技术的尖端形态&#xff0c;具备亚纳米级光谱分辨率与超千波段连续覆盖能力&#xff0c;通过“图谱合一”的三维数据立方体实现物质的精准识别与分析。其核心技术架构、应用场景及发展趋势如下&#xff1a;一、核心技术原理1、‌分光机制‌‌干涉分光‌&am…

掌握MySQL函数:高效数据处理指南

​ 在 MySQL 数据库管理系统中&#xff0c;函数扮演着极为重要的角色。它们就像是数据库操作的得力助手&#xff0c;能够帮助开发者高效地完成各种数据处理任务。本文将深入探讨 MySQL 函数的方方面面&#xff0c;从其基本概念到实际应用&#xff0c;帮助读者全面掌握这一强大的…

10.SpringBoot的统一异常处理详解

文章目录1. 异常处理基础概念1.1 什么是异常处理1.2 为什么需要统一异常处理1.3 Spring异常处理机制2. SpringBoot默认异常处理2.1 默认错误页面2.2 自定义错误页面3. 全局异常处理器3.1 基础全局异常处理器3.2 统一响应格式3.3 使用统一响应格式的异常处理器4. 自定义异常4.1 …

No Hack No CTF 2025Web部分个人WP

No Hack No CTF 2025 Next Song is 春日影 hint&#xff1a;NextJS Vulnerability at /adminCVE-2025-29927Next.js 中间件权限绕过漏洞 访问admin路由发现跳转利用CVE&#xff1a; curl -i \-H "x-middleware-subrequest: middleware:middleware:middleware:middleware:m…

STM32第十八天 ESP8266-01S和电脑实现串口通信

一&#xff1a; ESP和电脑实现串口通信1. 配置 WiFi 模式 ATCWMODE3 // softAPstation mode 响应 : OK 2. 连接路路由器器 ATCWJAP"SSID","password" // SSID and password of router 响应 : OK 3. 查询 ESP8266 设备的 IP 地址 ATCIFSR 响应 : CIFSR:APIP…

STM32第十七天ESP8266-01Swifi模块

ESP8266-01S wifi模块1&#xff1a;ESP8266是实现wifi通讯的一个模块种类&#xff0c;有很多分类包含esp8266-12、esp8266-12E、ESP8266-01S、esp32等等。esp8266-01S由一颗esp8266作为主控再由一块flash作为存储芯片组成&#xff0c;带有板载芯片供电采用3.3V电压使用串口进行…

ProCCD复古相机:捕捉复古瞬间

在数字摄影盛行的今天&#xff0c;复古胶片相机的独特质感和怀旧风格依然吸引着众多摄影爱好者。ProCCD复古相机APP正是这样一款能够满足用户对复古摄影需求的应用程序。它通过模拟复古CCD数码相机的效果&#xff0c;让用户在手机上也能轻松拍出具有千禧年风格的照片和视频。无…

Spring Boot 应用启动时,端口 8080 已被其他进程占用,怎么办

1、修改application.yml配置文件&#xff0c;将端口号更改为未被占用的端口&#xff08;例如9090&#xff09;2、以管理员身份运行命令提示符在命令提示符窗口中输入命令netstat -ano | findstr :8080”输出结果可能如下&#xff1a;“TCP 0.0.0.0:8080 0.0.0.0:0 LISTENING xx…

使用Jenkins完成springboot项目快速更新

✨重磅&#xff01;盹猫的个人小站正式上线啦&#xff5e;诚邀各位技术大佬前来探秘&#xff01;✨ 这里有&#xff1a; 硬核技术干货&#xff1a;编程技巧、开发经验、踩坑指南&#xff0c;带你解锁技术新姿势&#xff01;趣味开发日常&#xff1a;代码背后的脑洞故事、工具…

HDLBits刷题笔记和一些拓展知识(九)

文章目录HDLBits刷题笔记CircuitsFsm1Fsm1sFsm2Fsm3onehotExams/ece241 2013 q4Lemmings1Lemmings2Lemmings3Lemmings4Fsm onehotFsm ps2Fsm ps2dataFsm serialFsm serialdataFsm serialdpFsm hdlc未完待续HDLBits刷题笔记 以下是在做HDLBits时的一些刷题笔记&#xff0c;截取一…

CD46.【C++ Dev】list的模拟实现(1)

目录 1.STL库的list 2.模拟实现 节点结构体 list类 无参构造函数 尾插函数 迭代器★ begin() operator 前置 后置 operator-- 前置-- 后置-- operator! operator end() operator* const修饰的迭代器的设计 1.STL库的list 模拟实现list之前,先看看STL库里的…

数据结构——二叉树的基本介绍

————————————本文旨在讨论与学习计算机知识&#xff0c;欢迎交流————————————上一章&#xff0c;我们讲解了树结构的综述导论&#xff0c;那么&#xff0c;现在我们来深入了解一下树结构中最常用研究的结构——二叉树结构&#xff08;上一章的扩展——…

英伟达发布 Llama Nemotron Nano 4B:专为边缘 AI 和科研任务优化的高效开源推理模型

英伟达推出了 Llama Nem)otron Nano 4B&#xff0c;这是一款专为在科学任务、编程、符号运算、函数调用和指令执行方面提供强大性能与效率而设计的开源推理模型&#xff0c;其紧凑程度足以支持边缘部署。该模型仅包含 40 亿参数&#xff0c;却在内部基准测试中实现了比其他多达…

论文阅读笔记——Autoregressive Image Generation without Vector Quantization

MAR 论文 基于 VQ&#xff08;向量量化&#xff09;的图像生成方法具有显著优势&#xff0c;它通过离散化压缩将原始图像映射到有限的 codebook 空间&#xff0c;从而缩小学习范围、降低建模难度&#xff0c;同时这种离散表示更易于与自回归&#xff08;AG&#xff09;生成方式…

【科普】关于C 语言日志系统实战:如何同时输出到终端和文件?

1.概述 c语言没有现成的日志库&#xff0c;如果要记录日志&#xff0c;需要自己封装一个日志库。如果要实现日志级别和参数打印&#xff0c;还是比较麻烦的&#xff0c;正好在github找到了一个c语言开源日志库&#xff0c;可以实现日志级别打印&#xff0c;参数打印&#xff0…

2025,数字人借直播场景迈过“真假线”丨数智化观察

作者 | 曾响铃文 | 响铃说一夜带货超5500万GMV、观看人次1300万&#xff0c;罗永浩数字人在百度电商的直播首秀正在掀起新的行业浪潮——2025&#xff0c;数字人直播带货成功出圈&#xff0c;加速进入大众视野&#xff0c;被更多的消费者所认可。成就这场热潮的关键点之一&…

HTML表格导出为Excel文件的实现方案

1、前端javascript可通过mime类型、blob对象或专业库&#xff08;如sheetjs&#xff09;实现html表格导出excel&#xff0c;适用于中小型数据量&#xff1b;2、服务器端方案利用后端语言&#xff08;如python的openpyxl、java的apache poi&#xff09;处理复杂报表和大数据&…

企业微信iPad协议端强制拉群漏洞深度分析

正常一次最多邀请40人进群 超过40人的拉群&#xff0c;会变成邀请&#xff0c;需要对方同意 新版本修复了漏洞&#xff0c;但还是可以用老版本进行强制拉群 虽然官方也做了版本过低的限制&#xff0c;但还是有办法绕过 要么修改版本号或者登录几天新版本&#xff0c;之后就可以…

Python编译器(Pycharm Jupyter)

Pycharm下载不过多赘述pycharm导入anaconda创建的python环境选择想要的环境 Jupyter Jupyter 是一个开源的交互式计算环境&#xff0c;能够让用户将代码、文本&#xff08;包括 Markdown&#xff09;、可视化结果等内容整合在一个文档中&#xff0c;非常适合进行数据分析、科学…