0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

从2s优化到0.1s,这周班没白加!

CodeSheep 来源:CodeSheep 2023-06-28 17:03 次阅读

大家好,今天我们继续来分享一个在项目开发过程中遇到的实际问题,这里也来梳理并总结一下我们是如何对它进行持续优化的,希望能对大家有所帮助。

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

b2a0caea-1588-11ee-962d-dac502259ad0.png

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

这其中到底经历了什么呢?

背 景

我们的一个老项目使用了SpringBoot推荐的模板引擎:Thymeleaf,进行动态渲染。

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

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

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

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

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

第1次优化

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

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

我们不得不做优化了。

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

流程图如下:

b2c6e8ce-1588-11ee-962d-dac502259ad0.png

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

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

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

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

第2次优化

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

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

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

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

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

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

b2f15a96-1588-11ee-962d-dac502259ad0.png

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

其他的流程保持不变。

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

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

第3次优化

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

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

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

我们需要做第3次优化。

该怎么优化呢?

答:加内存缓存。

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

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

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

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

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

改造后的流程图如下:

b320f4b8-1588-11ee-962d-dac502259ad0.png

  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
publicclassCategory{

privateLongid;
privateStringname;
privateLongparentId;
privateDateinDate;
privateLonginUserId;
privateStringinUserName;
privateListchildren;
}

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

修改自动名称。

例如:

@AllArgsConstructor
@Data
publicclassCategory{
/**
*分类编号
*/
@JsonProperty("i")
privateLongid;

/**
*分类层级
*/
@JsonProperty("l")
privateIntegerlevel;

/**
*分类名称
*/
@JsonProperty("n")
privateStringname;

/**
*父分类编号
*/
@JsonProperty("p")
privateLongparentId;

/**
*子分类列表
*/
@JsonProperty("c")
privateListchildren;
}

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

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

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

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

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

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

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

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

小 结

所以回过头来看,这样一个看似并不复杂的功能需求,但是要想把它做到稳定、高效、可用,一路下来还是需要考虑不少问题的。而这其中遇到的任何一个问题,一旦解决并复盘了,它也就汇聚成我们的经验了,希望这篇文章的梳理能对大家有所帮助。

好了,今天的内容分享就到这里了,感谢大家的收看,我们下篇见。



声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数据库
    +关注

    关注

    7

    文章

    3795

    浏览量

    64366
  • 模板
    +关注

    关注

    0

    文章

    108

    浏览量

    20561
  • 分类树
    +关注

    关注

    0

    文章

    3

    浏览量

    5740

原文标题:从2s优化到0.1s,这周班没白加!

文章出处:【微信号:CodeSheep,微信公众号:CodeSheep】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    用RK3128输出I2S信号TAS5707,噪音大怎么优化

    我用 RK3128 输出 I2S 信号 TAS5707,现在噪音大,请问有什么方法可以优化吗? 目前整机的音量是在 RK3128里面调整,TAS5707音量是设为最大的。 谢
    发表于 10-30 07:26

    S2S(Services To Signal)测试问答#S2S测试 #SOA

    S2S
    北汇信息POLELINK
    发布于 :2023年01月19日 17:37:52

    请问按键2S如何实现啊

    请问按键2S如何实现啊我现在用的定时器时间为25MS如何实现按键2S请高手给予指点 最好是简单的代码
    发表于 05-10 11:31

    0.1S~6小时定时电路图

    0.1S~6小时定时电路图:本定时器电路由基准脉冲产生器,分频电路和执行电路组成,分单步定时和循环定时。
    发表于 10-27 09:28 1154次阅读
    <b class='flag-5'>0.1S</b>~6小时定时电路图

    全“芯”升级 小米手机2S详细拆解

    小米手机在国产智能手机中一直是人们关注的焦点,除了1999元经典的平民价格外,其旗舰机水准的配置总能在第一时间抓住人眼球。小米手机2S 是小米手机2的升级版本,就外观而言,消费者根本无从分辨二者
    的头像 发表于 04-14 15:45 3.6w次阅读

    好高兴又可以用小米2S啦!你的小米2S还在吗?

    小米2S可以说是小米系列手机里最经典的手机,没有之一。如今小米更迭很快,依旧为发烧而生,可是却再也没有一款像当年小米2S那样经典之作
    发表于 03-03 08:16 4960次阅读
    好高兴又可以用小米<b class='flag-5'>2S</b>啦!你的小米<b class='flag-5'>2S</b>还在吗?

    s=surprise,发布会后大家都这样评价nova 2s

    12月7日下午,华为正式发布了华为 nova 2s,作为nova系列的最新一代产品,华为 nova 2s继承了高颜值的外观设计以及强大的自拍、拍照性能,并且加入了很多最新的时尚元素,比如说采用全面屏
    发表于 12-08 16:17 1093次阅读

    来了来了!最新小米MIX 2S曝光

    近日,小米发布预告称将于3月27日发布小米MIX 2S,目前有爆料为我们揭露了这款新机的谜团。
    的头像 发表于 03-02 14:16 3151次阅读

    小米MIX 2S评测:全面屏好看,但惊喜难以勾起购买的欲望

    小米MIX 2S在配置方面,依然是走了性能路线,拥有“高通845+8GB”这目前国产机当中顶尖的配置。然而这次小米MIX 2S的出现,并没有当初小米MIX出现时候的那种惊艳,外观设计没有大的进步,而背面类似于iPhone X的设计在大众评价当中,甚至有退步的感觉。
    的头像 发表于 04-05 15:00 5367次阅读

    小米 MIX 2S 与 MIX 2 对比图赏

    小米在 3 月底给我们带来了全新的旗舰——MIX 2S,延续了 MIX 系列的全面屏设计,这一次除完成国内厂商首发骁龙 845 的任务外,更是大幅度提升了以往 MIX 系列的拍照弱项。在详细评测出来之前,我们先来看看小米 MIX 2S 与 MIX
    的头像 发表于 04-13 10:19 9218次阅读

    谷歌ARCore登陆中国市场 小米Mix 2S应用商店首发

    在小米8发布之前,小米MIX 2S可以说是小米目前旗舰手机的最佳代表,这款产品发布于3月27日,凭借着小米史上最好拍照手机的头衔,MIX 2S一经发售就受到了用户的追捧,不过由于刚发售时候的产能原因,小米MIX 2S经常出现断货
    发表于 05-30 09:56 1275次阅读

    小米Air 2s无线耳机固件更新

    。 本次固件更新优化弹窗问题;优化声音卡顿、音质、LHDC;优化误触、提示灯等其它问题,提高稳定性。 IT之家了解,小米真无线蓝牙耳机 Air 2
    的头像 发表于 11-18 11:47 9221次阅读

    小米Air 2s已修复电量10%时概率无法充电问题

    据IT之家网友反馈,小米 Air 2s 真无线蓝牙耳机现已推送 2.1.5.2 版本固件,优化了当耳机电量为 10% 时,概率性无法充电的问题。 此前,小米 Air 2s 耳机还优化
    的头像 发表于 12-01 09:15 5211次阅读

    Tinker Board 2S嵌入式系统开箱介绍

    本次取得的是Tinker Board 2S / 2GB的版本,单板微电脑就外观来看,Tinker Board 2S与Tinker Board 2这两个版本的各种外接界面规划其实没有差异
    的头像 发表于 11-07 16:07 1619次阅读

    Tinker Board 2S系统与软件安装设定

    Tinker Board 2S在官方网站上提供了Debian10 Linux操作系统给用户进行安装,相关LXDE桌面环境的套件软件程序,都有相当完整的支持,本文将会着眼在Tinker Board 2S应用在AI范畴中
    的头像 发表于 11-14 16:06 2224次阅读