问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

性能优化实践:一行代码性能提升几十倍?

创作时间:
作者:
@小白创作中心

性能优化实践:一行代码性能提升几十倍?

引用
CSDN
1.
https://blog.csdn.net/xiexiaojing/article/details/138267055

本文分享了一个核心接口的性能优化实践,通过采用科学法、USE方法和向下挖掘分析法,将响应时间从几百毫秒降低至几十毫秒,实现了数量级上的质变。文章详细描述了优化的背景、方法、分析过程和最终的解决方案,具有较高的技术价值和参考意义。

问题背景

手头有一个很重要的性能优化工作,需要静下心来不被打扰地进行分析。对于这个性能优化,提出了以下硬性要求:

  1. 效果要明显
  2. 改动要小,最好能用上之前同事做优化时添加代码的一些成果

性能优化方法

在《性能之巅》这本书中,印象最深的性能优化方法包括三种推荐的方法和三种要避免的方法,即“三正三反”。

三正

  • 科学法:采用问题->假设->预测->实验->分析的框架
  • USE方法:检查每个资源的使用率、饱和程度和错误情况
  • 向下挖掘分析法:从高级别检查问题,然后缩小关注范围

三反

  • 街灯讹:随意选择工具进行性能分析
  • 随机变动讹:随机猜测问题位置并进行改动
  • 责怪他人讹:将问题归咎于其他团队

分析过程

问题描述

有一个核心接口,一次调用涉及多次数据库查询,返回数据量在几百条的量级。网络正常情况下,第一次请求响应时间在1s3s之间。经过Redis缓存优化后,连续请求响应时间在630ms680ms之间。

假设

通过DBA的配合,将慢查询日志记录时间从1s以上调整为30ms以上。从慢查询日志可以看出,主要的性能瓶颈在数据库。第一次请求走数据库时耗时在500ms左右,后续走Redis缓存时调用耗时在200ms左右。

预测

为了降低网络开销,可以将使用Redis集中式缓存改成使用本地内存缓存。通过观察日志计算,抛去从数据库和缓存取数据的开销,其他时间开销在20多毫秒。据此预测,如果用内存缓存响应延迟可维持在35ms以下。

实验

通过修改Spring的Cacheable注解中的cacheManager实现,将Redis缓存改为本地内存缓存。运行结果显示响应时间从几百毫秒降低至几十毫秒,效果显著。

分析

  • 本地缓存效果很好,但需要考虑数据一致性和持久化存储的需求
  • 本次场景允许一定的数据不一致,不需要持久化存储
  • 测试发现缓存数据量不会太大,对内存影响不大
  • 还可以进一步优化异步获取数据等环节

总结

这次性能优化整体采用科学法的框架,结合USE方法排查隐患和向下挖掘分析法进行问题分析。过程中使用了业界常用的分析工具比如慢日志、JProfiler来做数据支撑。很多工作可以本地编写完了直接扔到服务器上测试。但是使用本地调试和扔到服务器上测试,养成的习惯和解决问题的方式,思考问题的缜密程度都截然不同。这些最终都决定了一个人的编程能力。

本篇文章中缓存使用的是ConcurrentMap。这个从性能上要比咱们耳熟能详的本地缓存大咖:Caffeine、Guava Cache要好。但只适用于测试,不建议生产环境使用。因为生产环境要考虑长期运行时的内存管理等问题。ConcurrentMap将存储所有存入的数据(本次测试场景入参是笛卡尔积之后也只有不到1千种情况,所以可以用),如果不引进额外的管理机制会导致OOM等问题。

以下是生产环境常用的本地缓存类库性能对比:

性能最好的Caffeine,业界是这样评价的:Caffeine是基于Java 1.8的高性能本地缓存库,由Guava改进而来,而且在Spring5开始的默认缓存实现就将Caffeine代替原来的Google Guava,官方说明指出,其缓存命中率已经接近最优值。实际上Caffeine这样的本地缓存和ConcurrentMap很像,即支持并发,并且支持O(1)时间复杂度的数据存取。二者的主要区别在于:

  • ConcurrentMap将存储所有存入的数据,直到你显式将其移除
  • Caffeine将通过给定的配置,自动移除“不常用”的数据,以保持内存的合理占用

因此,一种更好的理解方式是:Cache是一种带有存储和移除策略的Map。即:业界生产使用的最好的本地缓存组件的性能标杆是ConcurrentMap。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号