日常工作中, 我们多少都会遇到应用的性能问题. 在阿里面试中, 性能优化也是常被问到的题目, 用来考察是否有实际的线上问题处理经验. 面对这类问题, 阿里工程师齐光给出了详细流程. 来阿里面试前, 先看看这篇文章哦.
性能问题和 Bug 不同, 后者的分析和解决思路更清晰, 很多时候从应用日志 (文中的应用指分布式服务下的单个节点) 即可直接找到问题根源, 而性能问题, 其排查思路更为复杂一些.
对应用进行性能优化, 是一个系统性的工程, 对工程师的技术广度和技术深度都有所要求. 一个简单的应用, 它不仅包含了应用代码本身, 还和容器(虚拟机), 操作系统, 存储, 网络, 文件系统等紧密相关, 线上应用一旦出现了性能问题, 需要我们从多方面去考虑.
与此同时, 除了一些低级的代码逻辑引发的性能问题外, 很多性能问题隐藏的较深, 排查起来会比较困难, 需要我们对应用的各个子模块, 应用所使用的框架和组件的原理有所了解, 同时掌握一定的性能优化工具和经验.
本文总结了我们在进行性能优化时常用的一些工具及技巧, 目的是希望通过一个全面的视角, 去感知性能优化的整体脉络. 本文主要分为下面三个部分:
第一部分会介绍性能优化的一些背景知识.
第二部分会介绍性能优化的通用流程以及常见的一些误区.
第三部分会从系统层和业务层的角度, 介绍高效的性能问题定位工具和高频性能瓶颈点分布.
本文中提到的线程, 堆, 垃圾回收等名词, 如无特别说明, 指的是 Java 应用中的相关概念.
1. 性能优化的背景
前面提到过, 应用出现性能问题和应用存在缺陷是不一样的, 后者大多数是由于代码的质量问题导致, 会导致应用功能性的缺失或出现风险, 一经发现, 会被及时修复. 而性能问题, 可能是由多方面的因素共同作用的结果: 代码质量一般, 业务发展太快, 应用架构设计不合理等, 这些问题处理起来一般耗时较长, 分析链路复杂, 大家都不愿意干, 因此可能会被一些临时性的补救手段所掩盖, 如: 系统水位高或者单机的线程池队列爆炸, 那就集群扩容增加机器; 内存占用高 / 高峰时段 OOM, 那就重启分分钟解决......
临时性的补救措施只是在给应用埋雷, 同时也只能解决部分问题. 譬如, 在很多场景下, 加机器也并不能解决应用的性能问题, 如对时延比较敏感的一些应用必须把单机的性能优化到极致, 与此同时, 加机器这种方式也造成了资源的浪费, 长期来看是得不偿失的. 对应用进行合理的性能优化, 可在应用稳定性, 成本核算获得很大的收益.
上面我们阐述了进行性能优化的必要性. 假设现在我们的应用已经有了性能问题(eg. CPU 水位比较高), 准备开始进行优化工作了, 在这个过程中, 潜在的痛点会有哪些呢? 下面列出一些较为常见的:
对性能优化的流程不是很清晰. 初步定为一个疑似瓶颈点后, 就兴高采烈地吭哧吭哧开始干, 最终解决的问题其实只是一个浅层次的性能瓶颈, 真实的问题的根源并未触达;
对性能瓶颈点的分析思路不是很清晰. CPU, 网络, 内存...... 这么多的性能指标, 我到底该关注什么, 应该从哪一块儿开始入手?
对性能优化的工具不了解. 遇到问题后, 不清楚该用哪个工具, 不知道通过工具得到的指标代表什么.
2. 性能优化的流程
在性能优化这个领域, 并没有一个严格的流程定义, 但是对于绝大多数的优化场景, 我们可以将其过程抽象为下面四个步骤.
准备阶段: 主要工作是是通过性能测试, 了解应用的概况, 瓶颈的大概方向, 明确优化目标;
分析阶段: 通过各种工具或手段, 初步定位性能瓶颈点;
调优阶段: 根据定位到的瓶颈点, 进行应用性能调优;
测试阶段: 让调优过的应用进行性能测试, 与准备阶段的各项指标进行对比, 观测其是否符合预期, 如果瓶颈点没有消除或者性能指标不符合预期, 则重复步骤 2 和 3.
下图即为上述四个阶段的简要流程.
2.1 通用流程详解
在上述通用流程的四个步骤当中, 步骤 2 和 3 我们会在接下来两个部分重点进行介绍. 首先我们来看一下, 在准备阶段和测试阶段, 我们需要做一些什么.
★ 2.1.1 准备阶段
准备阶段是非常关键的一步, 不能省略.
首先, 需要对我们进行调优的对象进行详尽的了解, 所谓知己知彼, 百战不殆.
对性能问题进行粗略评估, 过滤一些因为低级的业务逻辑导致的性能问题. 譬如, 线上应用日志级别不合理, 可能会在大流量时导致 CPU 和磁盘的负载飙高, 这种情况调整日志级别即可;
了解应用的的总体架构, 比如应用的外部依赖和核心接口有哪些, 使用了哪些组件和框架, 哪些接口, 模块的使用率较高, 上下游的数据链路是怎么样的等;
了解应用对应的服务器信息, 如服务器所在的集群信息, 服务器的 CPU / 内存信息, 安装的 Linux 版本信息, 服务器是容器还是虚拟机, 所在宿主机混部后是否对当前应用有干扰等;
其次, 我们需要获取基准数据, 然后结合基准数据和当前的一些业务指标, 确定此次性能优化的最终目标.
使用基准测试工具获取系统细粒度指标. 可以使用若干 Linux 基准测试工具(eg. jmeter,ab,loadrunnerwrk,wrk 等), 得到文件系统, 磁盘 I/O, 网络等的性能报告. 除此之外, 类似 GC,web 服务器, 网卡流量等信息, 如有必要也是需要了解记录的;
通过压测工具或者压测平台 (如果有的话), 对应用进行压力测试, 获取当前应用的宏观业务指标, 譬如: 响应时间, 吞吐量, TPS,QPS, 消费速率(对于有 MQ 的应用) 等. 压力测试也可以省略, 可以结合当前的实际业务和过往的监控数据, 去统计当前的一些核心业务指标, 如午高峰的服务 TPS.
★ 2.1.2 测试阶段
进入到这一阶段, 说明我们已经初步确定了应用性能瓶颈的所在, 而且已经进行初步的调优了. 检测我们调优是否有效的方式, 就是在仿真的条件下, 对应用进行压力测试. 注意: 由于 Java 有 JIT(just-in-time compilation)过程, 因此压力测试时可能需要进行前期预热.
如果压力测试的结果符合了预期的调优目标, 或者与基准数据相比, 有很大的改善, 则我们可以继续通过工具定位下一个瓶颈点, 否则, 则需要暂时排除这个瓶颈点, 继续寻找下一个变量.
2.2 注意事项
在进行性能优化时, 了解下面这些注意事项可以让我们少走一些弯路.
性能瓶颈点通常呈现 2/8 分布, 即 80% 的性能问题通常是由 20% 的性能瓶颈点导致的, 2/8 原则也意味着并不是所有的性能问题都值得去优化;
性能优化是一个渐进, 迭代的过程, 需要逐步, 动态地进行. 记录基准后, 每次改变一个变量, 引入多个变量会给我们的观测, 优化过程造成干扰;
不要过度追求应用的单机性能, 如果单机表现良好, 则应该从系统架构的角度去思考; 不要过度追求单一维度上的极致优化, 如过度追求 CPU 的性能而忽略了内存方面的瓶颈;
选择合适的性能优化工具, 可以使得性能优化取得事半功倍的效果;
整个应用的优化, 应该与线上系统隔离, 新的代码上线应该有降级方案.
3. 瓶颈点分析工具箱
性能优化其实就是找出应用存在性能瓶颈点, 然后设法通过一些调优手段去缓解. 性能瓶颈点的定位是较困难的, 快速, 直接地定位到瓶颈点, 需要具备下面两个条件:
恰到好处的工具;
一定的性能优化经验.
工欲善其事, 必先利其器, 我们该如何选择合适的工具呢? 不同的优化场景下, 又该选择那些工具呢?
首选, 我们来看一下大名鼎鼎的「性能工具 (Linux Performance Tools-full) 图」, 想必很多工程师都知道, 它出自系统性能专家 Brendan Gregg. 该图从 Linux 内核的各个子系统出发, 列出了我们在对各个子系统进行性能分析时, 可使用的工具, 涵盖了监测, 分析, 调优等性能优化的方方面面. 除了这张全景图之外, Brendan Gregg 还单独提供了基准测试工具 (Linux Performance Benchmark Tools) 图, 性能监测工具 (Linux Performance Observability Tools) 图等, 更详细的内容请参考 Brendan Gregg 的网站说明.
- top - 12:20:57 up 25 days, 20:49, 2 users, load average: 0.93, 0.97, 0.79
- Tasks: 51 total, 1 running, 50 sleeping, 0 stopped, 0 zombie
- %CPU(s): 1.6 us, 1.8 sy, 0.0 ni, 89.1 id, 0.1 wa, 0.0 hi, 0.1 si, 7.3 st
- KiB Mem : 8388608 total, 476436 free, 5903224 used, 2008948 buff/cache
- KiB Swap: 0 total, 0 free, 0 used. 0 avail Mem
- PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
- 119680 admin 20 0 600908 72332 5768 S 2.3 0.9 52:32.61 obproxy
- 65877 root 20 0 93528 4936 2328 S 1.3 0.1 449:03.61 alisentry_cli
$ vmstat 1 procs -----------memory---------- ---swap-- -----io---- -system-- ------CPU----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 504804 0 1967508 0 0 644 33377 0 1 2 2 88 0 9
$free -h total used free shared buff/cache available Mem: 125G 6.8G 54G 2.5M 64G 118G Swap: 2.0G 305M 1.7G
$iostat -dx Linux 3.10.0-327.ali2010.alios7.x86_64 (loginhost2.alipay.em14) 10/20/2019 _x86_64_ (32 CPU) Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util sda 0.01 15.49 0.05 8.21 3.10 240.49 58.92 0.04 4.38 2.39 4.39 0.09 0.07
来源: http://www.tuicool.com/articles/ZvyqmuY