分类树查问配置,在各个业务系统中可以说随处可见,特意是在电商系统中。
但就是这样一个便捷的分类树查问配置,我们却优化了5次。
究竟是怎样回事呢?
我们的网站经常使用了SpringBoot介绍的模板引擎:Thymeleaf,进执行态渲染。
它是一个XML/XHTML/HTML5模板引擎,可用于Web与非Web环境中的运行开发。
它提供了一个用于整合SpringMVC的可选模块,在运行开发中,我们可以经常使用Thymeleaf来齐全替代JSP或其余模板引擎,如Velocity\FreeMarker等。
前端开发写好Thymeleaf的模板文件,调用后端接口失掉数据,进执行态绑定,就能把想要的内容展现给用户。
由于过后这个是从0-1的新名目,为了开加快开发配置,我们第一版接口,间接从数据库中查问分类数据,组装成分类树,而后前往给前端。
经过这种方式,简化了数据流程,加快把整个页面配置调通了。
我们将该接口部署到dev环境,刚开局没啥疑问。
随着开发人员参与的分类越来越多,很快就暴显露性能瓶颈。
我们不得不做优化了。
我们第一个想到的是:加Redis缓存。
流程图如下:
于是临时这样优化了一下:
我们在Redis中定义一个了key,value是一个分类树的json格局转换成了字符串,经常使用便捷的key/value方式保管数据。
经过这样优化之后,dev环境的联和谐自测顺利成功了。
我们将这个配置部署到st环境了。
刚开局测试同窗没有发现什么疑问,但随着前面始终地深化测试,隔一段期间就产生一次性访问很慢的状况。
于是,我们马上启动了第2次优化。
我们选择经常使用Job活期异步更新分类树到Redis中,在系统上线之前,会先生成一份数据。
当然为了保险起见,防止Redis在哪条突然挂了,之前分类树同步写入Redis的逻辑还是保管。
于是,流程图改成了这样:
参与了一个job每隔5分钟执行一次性,从数据库中查问分类数据,封装成分类树,更新到Redis缓存中。
其余的流程坚持不变。
此外,Redis的过时期间之前设置的5分钟,如今要改成终身。
经过这次优化之后,st环境就没有再产生过火类树查问的性能疑问了。
测试了一段期间之后,整个网站的配置快要上线了。
为了保险起见,我们须要对网站做一次性压力测试。
果真测出疑问了,网站最大的qps是100多,最后发现是每次都从Redis失掉分类树造成的网站的性能瓶颈。
我们须要做第3次优化。
该怎样优化呢?
答:加内存缓存。
假设加了内存缓存,就须要思考数据分歧性疑问。
内存缓存是保管在主机节点上的,不同的主机节点更新的频率或者有点差异,这样或者会造成数据的不分歧性。
因此,分类树这种业务场景,是可以经常使用内存缓存的。
于是,我们经常使用了Spring介绍的caffine作为内存缓存。
变革后的流程图如下:
这样优化之后,再次做网站的压力测试,qps优化到了500多,满足上线要求。
之后,这个配置顺利上线了。
经常使用了很长一段期间没有产生疑问。
两年后的某一天,有用户反应说,网站有点慢。
我们排查了一下要素发现,分类树的数据太多了,一次性性前往了上万个分类。
我们须要做第4次优化。
这时要如何优化呢?
限度分类树的数量?
答:也不太事实,目前这个业务场景就是有这么多分类,不能让用户选用不到他想要的分类吧?
这时我们想到最快的方法是开启nginx的GZip配置。
让数据在传输之前,先紧缩一下,而后启动传输,在用户阅读器中,智能解压,将实在的分类树数据展现给用户。
之前调用接口前往的分类树有1MB的大小,优化之后,接口前往的分类树的大小是100Kb,一下子增加了10倍。
这样便捷的优化之后,性能优化了一些。
经过上方优化之后,用户很长一段期间都没有反应性能疑问。
但有一天公司共事在排查Redis中大key的时刻,揪出了分类树。之前的分类树经常使用key/value的结构保管数据的。
我们不得不做第5次优化。
为了优化在Redis中存储数据的大小,我们首先须要对数据启动瘦身。
只保管须要用到的字段。
例如:
@AllArgsConstructor@Datapublic 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@Datapublic 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疑问被处置了。
性能优化疑问,无论在面试,还是上班中,都会经常遇到。
本网站的文章部分内容可能来源于网络和网友发布,仅供大家学习与参考,如有侵权,请联系站长进行删除处理,不代表本网站立场,转载联系作者并注明出处:https://duobeib.com/diannaowangluoweixiu/6390.html