1.1 系统性能
系统性能是对整个计算机系统的性能的研究,包括主要硬件组织和软件组织。所有数据路径上和从存储设备到应用软件上所发生的事情都包括在内。显示数据的路径可以帮助你理解所有组件的关系,并确保你不会只见树木不见森林。
系统性能的典型目标是通过减少延迟和降低计算成本来改善终端用户的体验。降低成本可以通过消除低效之外、提高系统吞吐量和进行常规性能调优来实现。
服务器上的通用系统软件栈包括:操作系统OS内核、数据库和应用程序层。术语全栈有时一般仅仅指的是应用程序环境,包括数据库、应用程序,以及网站服务器。而性能考虑时还包括系统库、内核和硬件本身。
1.4 视角
审视性能是可以从不同的视野来进行的:负载分析和资源分析。
系统管理员作为系统资源的负责人,通常采用资源分析视野。应用程序开发人员对最终实现的负载性能负责,通常采用负载分析视野。
1.5 性能工程是充满挑战的
系统性能是主观的、复杂的,而且常常是多问题并存的。
1.5.1 主观性
技术领域往往是客观的。bug的出现总是伴随着错误信息,错误信息通常容易解读,进而你就明白错误为什么会出现了。与此不同,性能常常是主观的。着手解决性能问题的时候,对问题的是否存在的判断都有可能是模糊的。例如磁盘的平均IO响应时间是1ms。从某种程度上说,一个给定指标是“好”或“坏”取决于应用开发人员和最终用户的性能预期。
通过定义清晰的目标,诸如目标平均响应时间,或者对落在一定响应延时范围内的请求统计其百分比,可以把主观的性能变得客观化。
1.5.2 复杂性
因为系统的复杂性,还因为对于性能,常常缺失一个明确的分析起点。起初只是从猜测开始,而性能分析必须对这是不是一个正确的方向做出判断。
性能问题可能出在子系统之间复杂的互联上,即便这些子系统独立工作时表现得都很好。也可能由于连锁故障出现性能问题,指一个出现故障的组件会导致其他组件产生性能问题。要理解这些问题,必须理清组件之间的关系,还要了解它们是怎样协同工作的。
瓶颈往往是复杂的,还会以意想不到的方式互相联系。修复了一个问题只是把瓶颈推向了系统里的其他地方,导致系统的整体性能并没有得到期望的提升。
除了系统的复杂性之外,生产环境的复杂特性也可能会导致性能问题。
解决复杂的性能问题常常需要全局性的方法。整个系统--包括自身内部和外部的交互--都有可能需要被调研。这项工作需要非常广泛的技能,一般不太可能出现在一个人身上。
1.5.3 多个原因
想象一下三个正常的事件同时发生,结合在一起导致了一个性能问题,每个事件都是一个正常的事件,孤立地看并不是根本原因。
1.5.4 多个性能问题
性能分析的又一个难点:真正的任务不是寻找问题,而是辨识问题或者辨识那些是最重要的问题。要做到这一点,性能分析必须量化问题的重要程度。理想情况下,不仅要量化问题,还要估计每个问题修复后能带来的增速。
有一个指标非常适合用来量化性能,那就是延时。
1.6 延时
延时测量的用于等待的时间,广义来说,它可以表示所有操作完成的耗时。例如,一个应用程序请求、一次数据库查询、一次文件系统操作,等等。
作为一个指标,延时可以估计speedup,还对性能问题做了量化。不过对其他的指标类型不一定适用,例如每秒发生的IO操作次数,取决于IO的类型,往往不具备直接可比性。
1.7 可观测性
可观测性是指通过观测来理解一个系统,并对完成这一任务的工具进行分类。这包括使用计数器、剖析和跟踪。它不包括基准测试工具,基准测试工具是通过执行工作负载实验来修改系统的状态。对于生产环境,应尽可能先尝试可观测性工具,因为实验性工具可能会通过资源争夺来扰乱生产工作负载。
1.7.1 计数器、统计数据和指标
应用程序和内核通常提供关于其状态和活动的数据:操作计数、字节计数、延迟测量、资源使用率和错误率。通常是用被称为计数器的整形变量实现的,计数器在软件中哦个是被硬编码的。
指标是为评估或检测一个目标而选择的统计数据。大多数公司使用检测代理,定期记录选定的统计数据(指标),并在图形界面中绘制图表,以查看指标随时间的变化。监测软件还支持从这些指标创建用户警报。
通过性能统计的计算方式,你对性能统计的诠释能力也相应会提高。总结包括平均数、分布、模式和异常值的统计数据。
有时,只用时间序列指标就足以解决性能问题。了解到问题的开始的确切时间可能与一个已知的软件或配置变更有关,变更就可以回滚。其他时候,指标只会指向一个方向,表明有CPU或磁盘问题,但没有具体的原因。这时就需要剖析或跟踪工具,以深入挖掘并找到原因。
1.7.2 剖析
在系统性能方面,术语剖析通常指的是使用工具来进行采样:取一个测量的子集(样本)来描绘目标的粗略情况。剖析CPU的常用方法是对CPU上的代码路径进行时间间隔的采样。
火焰图是CPU剖析的一种有效的可视化形式,其中宽度与花费的CPU时间成正比,纵轴显示了代码路径,横轴无实际意义。与任何其他工具相比,CPU火焰图可以帮助你找到更多的性能优势,仅次于指标。火焰图不仅能揭示CPU的问题;还可以通过寻找自旋路径中的CPU时间来发现锁竞争的问题;通过内存分配函数过多的CPU时间来发现内存问题;通过看到CPU时间花在慢速或历史代码路径上来发现网络错误配置导致的性能问题。
1.7.3 跟踪
跟踪是基于事件的记录,捕获事件数据并保存起来供以后分析,或即时用于自定义总结和其他操作。跟踪器使用各种各样的事件源,特别是静态检测和动态检测,以及可编程的BPF。
静态检测描述的是添加到源代码中的硬编码的软件检测点。
动态检测在软件运行起来后,通过修改内存指令插入检测程序来创建监测点。这类似于调试器可以在运行中的软件的任何函数上插入断点。当断点被触发时,调试器将执行流传递给交互式调试器,而动态检测则运行一个例程,然后继续运行目标软件。这种能力可以在任何运行着的软件中创建自定义的性能统计。
动态检测和传统的观测方法很大不同在于:分析内核就像冒险进入一个黑暗的房间,把蜡烛(计数器)放在内核工程师认为需要的地方。动态检测就像手电筒,可以指向任何地方。
BPF:通用的内核执行环境,安全的能快速访问资源的环境。
1.8 实验
除了观测工具外,还有一些实验工具,其中大多数都是基准测试工具。方式是在对系统施加合成的工作负载的同时测量系统的性能。该实验必须谨慎执行,因为实验会扰乱被测系统的性能。
宏观基准测试工具可以模拟真实世界的工作负载,如客户提出应用请求;微观基准测试工具可以测试特定的组件,如CPU、磁盘和网络。微观基准测试通常更容易调试、重复和理解,而且更为稳定。
要考虑到在生产环境服务器上使用观测工具调试会有性能问题的弊端。在生产环境系统上,应该先尝试观测工具。在解决性能问题时候:你有两只手,观测和实验,只使用一种类型的工具,就像试图单手解决问题。
1.9 云计算
云计算是一种按需部署计算资源的方式,通过在数量不断增加的被称为实例的小型的虚拟系统上部署应用程序,实现了应用程序的快速扩展。该方法降低了对容量规划的精确程度的要求,因为更多的容量可以很便捷地在云端添加。
云计算和虚拟化也带来了新的难题,包括如何管理其他租户带来的性能影响,以及如何让每个租户都能对物理系统座观测。
1.10 方法
方法是将系统性能领域执行各种任务的建议步骤记录下来的方式。如果没有方法,性能调查就会变成一次钓鱼式考察:随意尝试一些东西,希望能获得胜利。
1.10.1 Linux性能分析60秒
# | 工具 | 检查 |
1 | uptime | 平均负载可识别负载的增加和减少 |
2 | dmesg -T | tail | 包括OOM事件的内核错误 |
3 | vmstat -SM 1 | 系统级统计:运行队列长度、交换、CPU总体使用情况 |
4 | mpstat -P all 1 | CPU平衡程度:单个CPU很繁忙,意味着线程扩展性糟糕 |
5 | pidstat 1 | 每个进程CPU使用情况:识别意外的CPU消费者,以及每个进程的用户/系统CPU时间 |
6 | iostat -sxz 1 | 磁盘IO统计:IOPS和吞吐量、平均等待时间、忙碌百分比 |
7 | free -m | 内存使用情况,包括文件系统的缓存 |
8 | sar -n DEV 1 | 网络设备IO:数据包和吞吐量 |
9 | sar -n TCP,ETCP 1 | TCP统计:连接率、重传 |
10 | top | 检查概览 |
1.11 案例研究
1.11.1 缓慢的磁盘
工单说:“磁盘运转缓慢”。此时性能工程师首要任务是多了解情况,收集信息形成完整的问题陈述。收集以下问题:
1. 当前是否存在数据库性能问题?如何度量它?
2. 问题出现至今多长时间了?
3. 最近数据库有什么变动么?
4. 为什么怀疑是磁盘问题?
工单回到:“日志显示有些查询的延迟超过1000ms,这并不常见,但就在过去一周这类查询数目达到每小时几十个。AcmeMon显示磁盘在那段时间很忙。”
性能工程师使用use方法来快速检查资源瓶颈。显示磁盘使用率很高,而其他资源使用率很低。历史数据显示磁盘的使用率在过去的一周内稳步上升,CPU的使用率则与之前持平。在/sys目录检查磁盘错误数为零。
为了进一步确认这就是阻塞数据库的原因。使用offcputime工具说明,在数据库被内核取消调度的时候捕捉了栈踪迹,以及offcpu时间。栈踪迹显示,在读取文件系统的时候数据库查询经常出现阻塞。
接下来的问题是为什么。磁盘性能统计显示负载持续很高。性能工程师对负载进行了特征归纳以便作更多了解,使用iostat来测量IOPS、吞吐量、平均磁盘IO延时和读写比u。信息表明该问题是一个磁盘高负载情况,而非磁盘本身的问题。从而使得IO延时增加,进一步延缓了查询。但是,对于这些负载,这些磁盘看起来工作得很正常。难道数据库的负载增加了?
工单回到:“负载没有增加,而且CPU使用率也是稳定的”。
工程师思考还会有司马因素会导致磁盘的高IO负载而不引起CPU可见的使用率增加。同事推测可能是文件系统碎片,碎片预计会在文件系统空间使用接近100%时出现。但磁盘的使用率仅仅为30%。
尽管可以使用深入分析来了解磁盘IO问题的根源,但这样作太耗时。磁盘IO可能是由于文件系统缓存(页缓存)未命中导致的。工程师使用cachestat检查了文件系统花奴才年的命中率,发现当前是91%。其他服务器的缓存命中率超过97%,同时还发现问题服务器的文件系统缓存比其他服务器要大的多。于是把注意力转移到了文件系统缓存大小和服务器内存使用情况上,发现之前忽视事情:一个开发项目的原型应用程序在不断地消耗内存,虽然他并不处于生产负载之下。这些被占用的内存原本可以用来作文件系统缓存,这使得缓存命中率降低,让磁盘IO负载升高,损害了生产数据库服务器的性能。