1. 陷井
1.1 街灯效应
一天晚上,一个警察看到一个醉汉在路灯下的地面上找东西,问他在找什么。醉汉回答说他钥匙丢了。警察看了看也找不到,就问他:“你确定你钥匙是在这儿丢的,就在路灯下?”醉汉说:“不,但是这儿的光是最亮的”。
我们的对世界的认知有已知的已知,已知的未知,和未知的未知。已知的未知不可怕,即使我们不知道,也可以利用现在的知识网络检索到相关的信息;可怕的是未知的未知,当我们不知道“它”而“它”出现时,我们可能就束手无策了,这也意味着我们要扩充知识广度。
比如如果我们只知道加机器可以解决性能问题,出现性能问题时,我们只知道加机器;当加机器解决不了问题时,我们就不知道怎么办了。
1.2 在取得数据前,不要把事情理论化
在取得数据之前,把事情理论化是一个严重的错误。不理智的人扭曲事实来适应理论,而不是改变理论来适应事实。
《性能之巅》引自《波希米亚丑闻》
同样现象的问题,原因可能有多种,根据问题现象我们会猜测可能的原因。但如果猜测后不加验证就确认,就根据猜测去解决,可能是朝着一个错误的方向,徒劳无功;或是侥幸解决了问题,但可能掩盖了事实的真相。
2. 性能分析的方向
2.1 性能的指标
衡量系统性能的指标有许多,最主要的应该是以下三个
- 延时:从用户角度来说,延时是他们唯一关注的性能指标,低延时即高性能;从服务端角度来看,能为绝大多用户(如99%)提供低延时服务即高性能。
- TPS:对大多系统来说,每秒处理事务的数量是衡量性能的主要标准,TPS越高,意味着系统的处理能力越强,性能也就越好。
- 传输速率:一般来说,TPS与传输速率也越高;但如果两个请求,一个数据大小是100B,一个数据大小是10K,用TPS去对比他们的性能,显然是不公平的;所以一般我们也会通过传输速率来衡量系统性的性能。
2.2 性能问题原因和应对措施
性能问题的出现,主要有四类,缺陷、资源竞争、资源不足、资源利用不充分。我们所要做的对症下药:
- 修复程序缺陷,如使用合适的数据结构和算法,降低非必要的开销
- 降低资源的竞争,如使用合适的调度算法,减小互斥的范围
- 增加资源,通过提升配置和资源转换等手段消灭资源瓶颈
- 资源利用不充分看起来与资源不足互斥,但实际是另一种性能问题。如适合利用多线程加速的场景,使用单线程执行,这时可能就是资源利用不充分的情况。或是在资源闲忙差比较大时,通过合理的资源转换,更充分地利用资源,比如通过内存缓存减少重复IO和计算,利用CPU压缩减少内存或IO。
2.3 发现性能瓶颈
2.3.1 监控
要做性能优化,首先要明白性能问题在哪,只有定位到问题,才能去分析解决。可以借助系统监控工具(如Grafana )、链路追踪工具(如skywalking、Zipkin)去快速发现、追踪问题。
2.3.2 定位瓶颈
现在大多系统基本都是流水线模型,解决性能问题的核心是定位瓶颈,通过解决瓶颈来提升性能。在分析时有两点我们需要注意:
a. 确定什么需要优化,响应时间 × 请求频率
- 优化时首先要考虑的加速比,我们优化时尽量先解决能最大程度提供加速比的性能点。 比如一个请求读数据耗时耗时100ms,处理数据耗时10ms,即使我们将处理数据时间优化为0,对这个请求的提升也不到10%;但如果将数据读取的消耗降至20ms,整个请求就提升了300%。
- 在确定一个问题并解决后,一定要进行再次验证确认。通常旧的问题解决后,可能会让一些之前没出现的问题暴露出来。
性能分析有两种情况:
- 之前性能还ok,最近忽然慢了。
- 大家一直都知道这个很慢,现在我们想让他更快一些。
这两种情况虽然我们最终的分析手段是一样的,但我们的步骤可能会有些差异。
针对第一种情况,我们可以从最近的变更入手,相对精准地缩小分析范围,然后通过回滚等方式去验证。但有时变更导致的性能问题不一定是单独的变更导致的,可能是变更+其他因素共同导致的这个问题, 这时也要我们系统地分析性能的问题。
第二种情况,我们可以借助监控和压测工具,逐步定位性能的瓶颈。
3. 分析工具与方法
出现性能问题,大多可以通过资源的利用率体现出来
3.1 cpu
整体 cpu 使用情况,
top
若需要看具体进程,可执行(可以通过交互方式 H 查看线程分析情况,或执行top -Hp)
top -p
因现在cpu一般是多核,有时看整体cpu,cpu整体利用率可能不高。可能是单核的cpu瓶颈导致的。这时需要观察下单核cpu使用情况,可以使用
mpstat -P ALL 1 100
在发现cpu瓶颈后,可以确定进程和线程。
之后可以借助jps和jstack分析指定线程,准确定位cpu瓶颈的原因。
3.2 内存
free -h 可以查看机器当前内存的使用情况,一般会输出两行
mem表示物理内存,如果剩余内存很低了,那就说明内存不够用或存在内在滥用。若内存不够则升级内存,若使用的内存与期望不符则要考虑从程序原因入手了。
swap表示交换空间,是系统临时使用磁盘做内存的手段,这一行的used列最好为0。若不为0且与期望不符,可查看vm.swappiness,视情况将vm.swappiness设置为0(永远不使用交换空间)或1(当物理内存剩余量小1%时才使用交换空间),尽量避免使用交换空间。
3.3 IO
3.3.1 磁盘
磁盘出现性能问题主要有如下原因:
- 磁盘利用率过高,需要频繁进行碎片整理
- 大量IO
- 内存不足,导致系统文件缓存命中率降低
磁盘利用率,可以通过 df -h 查看磁盘使用情况,若磁盘利用率高,可通过 du -d 1 -h(-d表示查看目深度)各个目录占用的空间大小。当磁盘出现不合理的空间占用时,可以用于定位大文件所在的位置。
磁盘读写情况可以通过 iostat -m 1 100 查看当前一段时间磁盘io读写情况,若出量大io读写,可以进一步通过iotop -oP(可能过左右方向键按磁盘读写排序)定位进程。
文件系统缓存命中率可以通过cachetop查看,若命中率较期望地低,可查看内存是否被其他应用抢占。
3.3.2 网络
网络对性能的影响主要在于带宽和连接
netstat -s 查看网络流量的统计信息
nload 查看当前网络流量速率
nethogs 查看进程的网络流量
磁盘IO和网络IO一般是耗时最多的地方,IO优化的方式主要有以下几点:
- 通过缓存等手段降低重复的IO读取
- 通过适合的策略合并小IO,
3.4 其他
uptime 查看系统负载
dmesg 查看系统事件
sar 系统活动报告
4.一些实践
后续补充