一、总体思路
首先明确性能优化的定义和目标。性能优化是指通过持续地分析、实践和测试,确保系统稳定高效运行,从而满足用户的诉求。
1.1 性能优化分类
通用优化
是指针对一些经典的、对于绝大多数情况都适用的优化策略。比如增大服务器的并发处理请求数、使用缓存减少数据库查询、通过负载均衡分摊请求、同步转异步等。
针对性优化
是指结合具体的业务特性和系统现状,想通过性能优化监控工具、压力测试等方式,分析出系统的性能瓶颈,再针对性地选取策略进行优化。比如数据库单次查询超过1s,属于慢查询,根据实际的查询条件给对应的字段增加索引,一般就能够提升查询性能。
在实际的开发中,上述两类性能优化策略通常都要使用。在系统设计和开发阶段,我们要根据⾃⼰的经验,本能地引⼊⼀些性能优化的⼿段,降低后续系统出现问题、需要迭代优化的概率。此外,性能优化⼀定是持续的,随着需求、⽤户、系统⽤量的增多,原本性能符合要求的系统也可能会出现各种新的问题,很难⾯⾯俱到、⼀步到位。
但是,对于复杂的、对可⽤性和稳定性要求极⾼的项⽬,我们可以提前通过压⼒测试来模拟⽤户量极⼤的情况,并提前做好性能优化和应对措施。
1.2 通用性能优化手段
以一个请求的完整生命周期为例。通常,用户从发起请求到最终得到数据,要分别经过以下节点:
对于每个节点,我们都有对应的优化方法:
1)前端:
- 离线缓存:利用浏览器的缓存机制,请求过一次的资源就不用重复请求,提高页面加载速度。
- 请求合并:页面请求过多时,将多个小请求合并成一个大请求,减少网络开销。
- 懒加载:延迟加载页面的图片等元素,提高首屏加载速度。
2)网关:
- 负载均衡:负责接受请求,根据一定的路由算法将请求转发到对应的后端系统,实现多个后端服务器分摊请求、增大并发量。
- 缓存:将后端返回的数据进行缓存,下次前段请求时,直接从网管获取数据,减少后端调用、提高数据获取速度。
3)后端请求层
- 服务器优化:根据业务特性,选择性能更高的服务器并调整参数,比如Nginx、Undertow、Tomcat等。
- 微服务:将大型服务拆分为小型服务,并通过微服务网关进行转发,增大各服务的并发处理能力。
4)业务逻辑层
- 异步化:将同步的业务逻辑改为异步,尽早响应,提高并发处理能力。
- 多线程:将复杂的操作拆分成多个任务,通过多线程并发执行,提高任务处理效率。
5)中间件(第三方依赖):
- 缓存:将数据库查询出的结果数据缓存到性能更高的服务(比如基于内存的Redis或者本地内存),减少数据库的压力,并提高数据查询性能。
- 队列:使用消息队列,对系统业务进行解耦、或者将操作异步化,实现流量的削峰填谷。
6)存储层:
- 分库分表:数据量极大时,对数据库进行垂直或者水平切分,提高数据库并发处理能力。
- 数据清理:定期清理无用或者过期的数据,减少存储压力,必要时可以对数据进行备份转储。
📢注意:虽然有那么多性能优化⽅法,但并不是每⼀种都要⽤、每⼀种都有⽤。在做性能优化时,⼀定要根据实际情况,权衡性价⽐和系统改动⻛险,并且做好充分的测试,不要好⼼优化、结果给系统造成了新的Bug。⽽且⼀般情况下,不建议为了优化盲⽬引⼊新技术,先从成本最低的优化⽅法开始。
二、实际优化历程
优先对项目的核心功能进行性能优化。
整体测试分析 => 分析性能瓶颈 => 优化。
实际优化时:
1)如果是中间件之类的优化,优先遵循最佳实践。
2)如果是针对读多写少的情况,考虑使用缓存(本地或者分布式),多级缓存
缓存的核心四要素:
- 缓存内容
- 缓存key的设计
- 缓存淘汰机制
- 保证缓存一致性
3)针对查询性能的优化:
什么情况下需要对数据查询进行性能优化呢?一般来说,有以下几个场景:
- 数据需要高频访问
- 数据量较大,查询缓慢
- 数据查询实时性要求高,追求用户体验
- 方法一:精简数据,只查询需要的数据
- 方法二:针对于数据库查询,可以采用:
- 减少查询次数,能不查数据库就不查数据库,比如使用缓存
- 优化SQL语句,只查询需要的数据
- 添加合适的索引
4)适当时候,需要对于系统进行压力测试,比如采用 JMeter 这类的工具,测试之前一定要明确测试的环境、条件和基准。比如:
- 环境:16G内存、8核 CPU、近百兆宽带的网速
- 条件:每次请求同样的结果(
v2
接口)、传递相同的参数 - 基准:始终保证接口的异常率为 0%,出现异常需要重新测试
📢注意:压测前保证不会影响系统的正常运行,千万不要在线上压测!
5)计算优化:减少不必要的计算,比如JSON序列化(反序列化)等
6)请求层性能优化:
- 调整服务器(Tomcat等)参数。
- 测试空接口的性能,这个值是当前服务器处理请求的最大性能。
- 使用性能更高的服务器,结合实际场景,比如针对IO操作密集的接口(比如文件下载)可以使用 Vert.x 这样的反应式编程框架。
最后还有一个原则:所有的性能优化都要以实际测试为准!