Java后端性能优化--持续更新

前言

开发后端系统时,随着用户量的增加,并发量会显著提高,如何在有限的硬件资源下让系统响应更多的请求,就是后端性能优化的主要工作。按照系统职责划分,可优化的点可以分为后端应用系统、数据库系统、中间件系统、缓存系统、网关系统等等。本文将会从实战的角度出发,持续更新针对不同系统的优化思路。

系统性的性能调优

系统性的性能调优是指,针对整个系统,优化配置、调优参数。具体操作流程强依赖性能测试的结果,性能测试的用例不针对某一接口或某一类接口,而是模拟正常用户使用系统,对系统的每个功能都要涉及,然后看系统哪些地方会由于配置问题产生性能瓶颈。例如在使用SpringCloud时,如果系统使用了Zuul作为服务网关,那么当用户量变多,系统响应不及时时,会产生大量的SHORT_CIRCUIT异常,这是因为Zuul作为网关时,默认设置了100的信号量,当用完了,就会发生短路,避免下游服务被压垮。其次因为系统性的性能调优不是针对某一个接口调优的,我们需要记录系统每个层级的日志,帮助我们发现系统级的性能问题。例如在数据库层记录慢查询日志,调研慢查询产生的原因;记录应用层的调用链路以及耗时,调查耗时高的操作产生的原因等等。

调优思路

  • 设计性能测试用例,全功能执行性能测试
  • 针对性能测试结果,分析后端应用系统产生500异常的原因,并采取措施解决
  • 针对后端应用系统调用链日志,分析耗时操作的原因并解决
  • 分析数据库系统的慢查询日志,分析原因并解决慢查询语句
  • 分析数据库的参数配置,在有限的硬件资源下,将数据库吞吐量调整到最优
  • 分析中间件系统参数配置,生产者、消费者线程的配置,消息的分片配置等等
  • 分析缓存系统的吞吐量等等
  • 分析网关系统的参数配置,调优吞吐量等等

总而言之,在分析系统性的性能测试结果时,先思考第三方依赖的参数配置是否调到合适的值,然后再分析自己系统应用层面的原因,再者分析自己系统数据库层面的原因。

单一接口的性能调优

单一接口的性能调优来自两方面的原因,一方面是系统性性能测试时,发现个别接口性能有问题,造成系统瓶颈;另一方面则是某些接口在用户使用时,经常性超时,整个接口运行时间非常耗时。

调优思路

  • 静态代码扫描,针对不合理的实现进行优化,例如将网络操作、IO操作并行化
  • 合理使用缓存,能够将数据缓存到内存中的操作,尽量缓存数据
  • 避免N+1问题,需要访问第三方的接口切记不要写在循环中,可提前访问将数据存放到Map中
  • 动态代码扫描,通过visualVM等JVM可视化工具,监控代码执行时的GC日志,排查是否是GC导致的性能问题
  • 动态代码扫描,通过visualVM等JVM可视化工具,查看堆栈信息,调查耗时的方法以及耗时的原因

单一接口的性能调优是比较直观的,常用的方法就是并行化操作、将数据缓存到内存或者加载到内存避免IO或者网络操作。只要能发现瓶颈,就能够快速的通过其他实现方式优化性能。(一定要合理利用JVM可视化工具,排查线程执行慢的原因,并针对性的解决问题)。

已经解决过得问题汇总

  • 将数据库中所有数据导出到Excel表格时,耗时2分钟左右,导致前端超时断连

    静态代码扫描:发现数据库查询不合理,通过主表的Id去从表做范围查询,实际主表的数据已经全部查出来了,从表的数据也可以直接查出来,并且还可以拆断关联,用多线程去查询主表以及多个从表,这样十几个数据库的查询耗时将缩短到最耗时那次数据库查询;其次做数据映射时,在循环中反复调用第三方接口拿数据,产生N+1问题,优化该接口调用方式,提前调用将数据加载至内存;最后数据映射方法时串行执行的,但是所有需要映射的数据之间是没用关联的,所以改成并行执行;动态代码扫描:发现缓存框架在反复执行序列化和反序列化操作,并且是最耗时的操作,因此修改配置不再让缓存框架执行序列化和反序列化操作。

  • mysql慢查询日志记录了执行慢的sql语句,分析sql执行慢的原因

    首先explain每条sql语句,检查是否查询走了索引,没走索引,依据索引最左匹配原则建立索引;建立索引后继续执行是否有优化,如果sql由于lock time耗时太多还是被记录到了慢查询日志中,就需要到应用层分析哪些地方给sql加锁,去除无效锁;最后根据数据特点,如果某些sql无法优化了,但是又执行的多,并且数据变化频率不高,则可以将该sql的执行结果加载到内存缓存起来。

持续更新中。。。

Show Comments