《BPF( 伯克利数据包过滤器 ) Performance Tools》 第三章 性能分析

MarkDown编辑语法
本书介绍的各种工具可用于性能分析、故障排查、安全分析以及其他很多方面。为了帮助你理解如何运用这些工具,本章提供了一份针对性能分析的快速入门指南。
学习目标:
■理解性能分析的工作目标和工作内容。
■对业务负载进行定性分析。
■实施USE方法论。
■实践下钻分析方法论。
■理解清单分析方法论。
■使用传统工具和60秒Linux清单快速初步定位性能问题。
■使用BCC/BPF工具清单快速定位性能问题。

本章将首先描述性能分析的工作目标和工作内容,接着对相关方法论做总体介绍,然后再介绍一些可以首先尝试使用的传统(非BPF)工具。这类传统工具可以帮助你快速上手初步定位性能问题,或者为后续使用BPF工具分析提供线索和上下文。本章最后会给出一个BPF工具的清单,在之后的章节中则会引入更多BPF工具。

3.1 概览

3.1 概览
在开始具体的性能分析工作之前,先思考一些问题是有益处的:性能分析的目标是什么?开展哪些工作对达到这个目标是有帮助的?

3.1.1目标

一般来说,性能分析的目标是改进最终用户的体验以及降低运行成本。最好能将性能分析的目标进行量化定义;这种量化能够表明是否已经达到性能优化目标,还可以用来定义距离目标还有多少差距。可以测量的指标包括如下几项。

  • 延迟:多久可以完成一-次请求或操作,通常以毫秒为单位。
  • 速率:每秒操作或请求的速率。
  • 吞吐量:通常指每秒传输的数据量,以比特(bit) 或者字节(byte)为单位。
  • 利用率:以百分比形式表示的某资源在一 段时间内的繁忙程度。
  • 成本:开销/性能的比例。

最终用户眼中的性能,可以通过用户请求从发出到被响应之间所花费的时间来衡量,性能优化的目标就是缩短这个时间。这个等待的时间常被冠以术语“延迟”。针对延迟的改进可以通过分析请求时间的组成,将其细分为各个组成部分,例如,CPU. 上运行代码的时间;等待某个资源,比如磁盘I0、网络以及锁的时间;还有等待CPU调度的时间等。可以编写一个BPF工具,直接跟踪应用的总体请求延迟以及各个部分的单独开销。不过这样的工具会和具体应用相关,并且由于同时对多个事件进行跟踪会带来显著的运行开销。在实践中,更普遍的方法是使用小而专的工具来研究特定组件的时间开销和延迟。本书包含了许多这样小而专的工具。

降低运行成本需要观测软件和硬件资源是如何被使用的,以及从中定位可优化的部分,目标是降低公司在云和数据中心方面的开支。这可能会涉及另一种类型的分析,比如对不同组件的使用情况进行日志记录和汇总统计,而非分析它们的时间开销和响应延迟。本书中的不少工具也支持这种类型的分析。

在开展性能分析工作时请牢记上述目标。使用BPF工具,很容易出现这种情况:生成了大量数据,然后又花费了大量时间来理解这些数据,最后却发现该指标并不重要。作为性能优化工程师,笔者经常收到开发者发送过来的各类工具输出截图,这些截图往往展示了某个看起来不是特别健康的指标。笔者的第一反应通常是:“你有一个已知的性能问题吗?”而他们的回答则通常是:“没有,我们就是觉得这个输出看起来…有趣。”有趣也许是有趣,但是首先应该明确工作目标是什么:我们是要降低请求延迟,还是降低运行成本?明确目标后,进一步的分析工作就有了上下文,不至于跑偏。

3.1.2分析工作

BPF性能分析工具,不只用于分析特定类型的问题。表3-1所示的是一个性能分析工作的列表,以及在每项工作中BPF性能分析工具可以发挥的作用。
在这里插入图片描述
在这里插入图片描述
本书中的许多工具最明显的用途是用来研究某个给定的性能问题,但是可以考虑如何能使用它们改进监控、非回归测试,以及其他性能分析活动。

3.1.3 多重性能问题

在使用本书中介绍的各种工具时,要做好同时发现多个性能问题的准备。此时主要问题将变为识别出哪个性能问题才是最重要的:通常是那些对延迟或成本开销影响最大的性能问题。如果你对多重性能影响因素没有概念,可以尝试找一下你所关注的应用程序、数据库、文件系统或者软件组件的bug跟踪列表(bug tracker),并搜索关键词“性能”。通常会有多个尚未解决的性能问题,这当然还没有包括那些没有列出来的问题。最重要的还是找到对性能影响最大的那一个问题。

任何问题的背后都可能会有多重原因。很多时候当你解决了一个问题后,其他的问题才凸显出来。或者说,当解决掉一个瓶颈后,其他某个组件就会成为新的瓶颈。

3.2 性能分析方法论

在拥有了如此多的性能分析工具和能力(比如kprobes. uprobes、 tracepoints.USDT、PMC等,可参见第2章)之后,现在的主要困难是如何处理这些工具提供的所有数据。多年以来,笔者一直在研究、创建并且编写性能分析的方法论。方法论是一个可以遵循的过程:它指导从哪里开始,中间步骤有哪些和到哪里结束。笔者的上一本 书《性能之巅:洞悉系统、企业与云计算》中叙述了十几种性能分析方法论。笔者会在这里简要介绍一下,供你在使用BPF工具时作为参考。

3.2.1业务负载画像

业务负载画像的目的是理解实际运行的业务负载。你不需要对最终的性能结果进行分析,比如系统的延迟到底受到多少影响。“消除不必要的工作”是笔者在性能优化结果中收益最显著的一种,通过研究业务负载的构成就可以找到这样的优化点。开展业务负载画像的推荐步骤如下:

  • 1.负载是谁产生的(比如,进程ID、用户ID、进程名、IP地址) ?
  • 2.负载为什么会产生(代码路径、调用栈、火焰图) ?
  • 3.负载的组成是什么(IOPS、 吞吐量、负载类型) ?
  • 4.负载怎样随着时间发生变化(比较每个周期的摘要信息) ?

本书中提供的许多工具可以帮助你回答上述问题。比如,使用vsstat(8):
在这里插入图片描述
这个输出显示了在虚拟文件系统(virtual file system,VFS) 层面业务负载的细节,并且回答了,上面提出的第3个问题,即负载类型和操作的速率,同时还通过周期性输出摘要信息回答了第4个问题。
作为第1个问题的一个例子,我们来使用bpfrace运行一个单行程序(输出已被截断):
在这里插入图片描述
输出显示了名称为“Web Content”的进程在上述测量期间执行了1725 次vfs_ read()操作。
在本书中可以找到很多应用上述分析过程的示例,包括后续章节会介绍的火焰图,它可供第2个问题的分析使用。
如果你所分析的对象还没有现成可用的分析工具,可以尝试自行创建业务负载画像工具以回答上述问题。

3.2.2下钻分析

下钻分析的工作过程是从一个指标开始,然后将这个指标拆分成多个组成部分,再将最大的组件进一步拆分为更小的组件,不断重复这个过程直到定位出一个或多个根因。可以用一个类比来帮助解释这个过程。设想一下,如果你收到了一笔数额巨大的信用卡账单。为了分析它,需要登录到银行账户中调阅交易记录。在那里你发现了一笔线上书店的大额交易。然后你又登录到线上书店去看哪些书引发了这笔交易,结果有点意外:你发现不小心将此刻正在读的这本书购买了1000 本(多谢 ! )。 这就是下钻分析过程:先找到一个线索,然后拆分以寻找更深一步的线索,如此反复直到问题解决。下钻分析的推荐步骤如下:

  • 1.从业务最高层级开始分析。
  • 2.检查下一个层级的细节。
  • 3.挑出最感兴趣的部分或者线索。
  • 4.如果问题还没有解决,跳转至第2步。

下钻分析可能会涉及对工具进行定制,此时bpfrace比BCC更加适合。
有一种类型的下钻分析涉及将延迟分解为各个组成部分。想象一下下面的分析过程:

  • 1.请求延迟是100ms (毫秒)。
  • 2.有10ms在CPU. 上运行,90 ms消耗在脱离CPU的等待过程。
  • 3.在脱离CPU等待的部分中,有89ms阻塞于文件系统上。
  • 4.文件系统的部分,有3ms阻塞于锁上,而86 ms阻塞于存储设备上。

到此为止,你可能已经得出结论:存储设备是问题所在——这确实是一种答案。但是下钻分析可以使问题的上下文更清晰。设想另一种可能的分析过程:

  • 1.一个应用花费了89 ms被阻塞在文件系统上。
  • 2.文件系统花费了78 ms被阻塞在写操作上,11 ms被阻塞在读操作上。
  • 3.在文件系统写操作中,77 ms被阻塞在时间戳的更新上。

此时,可以得出的结论是:文件系统访问时间戳是延迟的根源,它们可以被禁止(通过改变挂载选项)。这个分析结果要比“我们需要更快的磁盘”好得多。

3.2.3 USE方法论

笔者开发了USE方法论用来对资源的使用情况进行分析。针对每一个资源,分别去检查:

  • 1.使用率
  • 2.饱和度
  • 3.错误

使用本方法的第一步是找出或者绘制一幅软件和硬件资源图,然后依次针对所有资源检查上述3个指标。图3-1展示了一个通用系统中的资源示例图,其中包含了可能需要分析的组件和总线。
在这里插入图片描述
请思考一下你目前正在使用的监控工具,它们是否具备显示图3-1中每项资源的使用率、饱和度、错误情况的能力?目前有多少个监控的盲区?

这个方法论的优势之一是,它以重要的问题作为开始,而非以某种指标形式的答案作为开始,反过来再去找出为什么它重要。这个方法论同时会帮助发现盲区:从你需要回答的问题开始,而不管是否已有工具能够方便测量。

3.2.4检查清单法

性能分析检查清单可以列出一系列工具和指标,用于对照运行和检查。这些工具和指标可以聚焦于那些唾手可得的性能问题:列出十几个常见的问题,以及对应的分析方法,这样让每个人都能参照检查。这个方法论适用于指导公司各个层次的工程师实施操作,允许你将个人的技能应用于更广的范围内。

下面会给出两个清单,一个使用了传统(非BPF)工具,比较适合于快速分析(开始的60秒);另一个清单是适合及早使用的BCC工具列表。

3.3 Linux 60秒分析

下面这个清单适用于任何性能问题的分析工作,也反映了笔者在实际工作中,当登录到一台表现不佳的Linux系统中后,在最初60秒内通常会进行的操作。笔者本人和Netflix的性能工程团队之前曾发表过这部分内容。

要运行的工具是:

    1. uptime
    1. dmesg | tail
    1. vmstat 1
    1. mpstat -P ALL 1
    1. pidstat 1
    1. iostat -XZ 1
    1. free -m
    1. sar-nDEV1
    1. sar-nTCP,ETCP1
    1. top

下面的小节中会依次介绍每个工具。一本讲述BPF的图书描述这些非BPF工具好像有点奇怪,但是如果不这样做的话,我们将会错失一类现成可用的重要资源。这些命令有可能会帮助你快速直接定位出性能问题。即便不能的话,这些工具也能暴露问题根源的线索,以便指引你后续使用BPF工具进一步定位真正的问题。

3.3.1 uptime

在这里插入图片描述
这个工具可以快速检查平均负载,也就是有多少个任务(进程)需要执行。在Linux系统中,这些数字包含了想要在CPU上运行的进程,同时也包含了阻塞在不可中断I/O (通常是磁盘I/O)上的进程。 这给出了一个高层次视角的资源负载(或者说资源,需求),在此之后可以通过其他工具进行进一步检查。

这3个数字分别是指数衰减的1分钟/5分钟/15分钟滑动窗口累积值。通过这3个值可以大致了解负载随时间变化的情况。上面的例子显示负载最近有小幅的提升。负载的平均值值得在排障过程中被首先进行检查,以确认性能问题是否还存在。在一个容错的环境中,一台存在性能问题的服务器,在你登录到机器上时,也许已经自动从服务列表中下线了。一个较高的15分钟负载与一个较低的1分钟负载同时出现,可能意味着已经错过了问题发生的现场

3.3.2 dmesg | tail

在这里插入图片描述
这个命令显示过去10条系统日志,如果有的话。注意在这里寻找可能导致性能问题的错误。这个例子显示了内存不足引发0OM和TCP的丢弃请求的记录。TCP的相关日志甚至指引了我们下一步的分析方向:查看SNMP计数器值。

3.3.3vmstat 1

在这里插入图片描述
这个虚拟内存 统计工具最早源于BSD(Berkeley Software Distribution,伯克利软件套件),同时还展示了一些其他的系统指标。当执行时带着命令行参数1时,会隔1秒打印一次摘要信息;注意,第1行输出的数字是自系统启动后的统计值(内存相关的计数器除外)。

需要检查的列包括如下几个。

  • r:CPU上正在执行的和等待执行的进程数量。相比平均负载来说,这是一个更好的排查CPU饱和度的指标,因为它不包含I/O。可以这样解释:一个比CPU数量多的r值代表CPU资源处于饱和状态。
  • free:空闲内存,单位是KB。如果数字位数一眼数不过来,那么内存应该是够用的。使用3.3.7节中介绍的free -m 命令,可以更好地解释空闲内存。
  • si和so:页换入和页换出。如果这些值不是零,那么意味着系统内存紧张。这个值只有在配置开启了交换分区后才会起作用。us、sy、id、wa和st:这些都是CPU运行时间的进一步细分,是对所有的CPU取平均之后的结果。它们分别代表用户态时间系统态时间(内核)、空闲等待I/O,以及被窃取时间(stolen time,指的是虚拟化环境下,被其他客户机所挤占的时间;或者是Xen环境下客户机自身隔离的驱动域运行时间)。

上面的例子显示了CPU时间主要花在用户态上。这指引我们下一步将主要针对用户态代码进行剖析。

3.3.4 mpstat-P ALL 1

在这里插入图片描述
这个命令将每个CPU分解到各个状态下的时间打印出来。上面的输出暴露了一个问题: CPU0的用户态的占比高达100%,这是单个线程遇到瓶颈的特征。对于比较高的%iowait时间也要注意,可以使用磁盘IO工具进一步分析:如果出现较高的%sys值,可以使用系统调用(syscall) 跟踪和内核跟踪,以及CPU剖析等手段进一步分析。

3.3.5 pidstat 1

在这里插入图片描述
pidstat(1)命令按每个进程展示CPU的使用情况。top(1)命令虽然也很流行,但是pidstat(1)默认支持滚动打印输出,这样可以采集到不同时间段的数据变化。这个输出显示了一个Java进程每秒使用的CPU资源在变化:这个百分比是对全部CPU相加的和,因此500%相当于5个100%运行的CPU。

3.3.6 iostat ->xz 1

在这里插入图片描述
在这里插入图片描述
这个工具显示了存储设备的IO指标。上面的每个磁盘设备输出行由于过长进行了换行,阅读起来稍显不便。

要检查的列包括如下几个。

  • r/s、w/s、rkB/s和wkB/s:这些是每秒向设备发送的读、写次数,以及读、写字节数。可以用这些指标对业务负载画像。某些性能问题仅仅是因为超过了能够承受的最大负载导致的。
  • await::I/O的平均响应时间,以毫秒为单位。这是应用需要承受的时间,它同时包含了I/O队列时间和服务时间。超过预期的平均响应时间,可看作设备已饱和或者设备层面有问题的表征。
  • avgqu-sz:设备请求队列的平均长度。比1大的值有可能是发生饱和的表征(不过对有些设备,尤其是对基于多块磁盘的虚拟设备来说,通常以并行方式处理请求)。
  • %util:设备使用率。这是设备繁忙程度的百分比,显示了每秒设备开展实际工作的时间占比。不过它展示的并不是容量规划意义下的使用率,因为设备可以并行处理请求’。大于60%的值通常会导致性能变差(可以通过await字段确认),不过这也取决于具体设备。接近100%的值通常代表了设备达到饱和状态。

上面的输出显示了向md0虚拟设备的写入负载约为300MB/s,看起来md0的背后是两块nvme设备。

3.3.7 free -m

在这里插入图片描述
这个输出显示了用兆字节(MB)作为单位的可用内存。检查可用内存(available)是否接近0;这个值显示了在系统中还有多少实际剩余内存可用,包括缓冲区和页缓存区。将一些内存用于缓存可以提升文件系统的性能。

3.3.8 sar-n DEV 1

在这里插入图片描述
将不同的指标进行组合,sar(1)工具有不同的运行模式。在这个例子中,笔者使用它来查看网络设备指标。通过接口吞吐量信息rxkB/s和txkB/s来检查是否有指标达到了上限。

3.3.9 sar -n TCP,ETCP 1

在这里插入图片描述
现在我们使用sar(1)工具来查看TCP指标和TCP错误信息。相关的字段包括如下几个。

  • active/s: 每秒本地发起的TCP连接的数量(通过调用connect()创建)。
  • passive/s:每秒远端发起的TCP连接的数量(通过调用accept()创建)。
  • retrans/s:每秒TCP重传的数量。

主动和被动连接计数对于业务负载画像很有用。重传则是网络或者远端主机有问题的征兆。

3.3.10 top

在这里插入图片描述
至此,你已经使用前面列举的工具看到了很多指标。不过再多做一步会更有益:我们以top命令作为结束,对相关结果进行二次确认,并能够浏览系统和进程的摘要信息。运气好的话,这个60秒分析过程会帮助你找到一些性能问题的线索。在此基础上,可以使用专门的BPF工具开展进一步分析。

3.4 BCC工具检查清单

下面的清单由笔者所作,位于BCC仓库的docstutoral.md文件中。它提供了一个通用的使用BCC工具的检查清单:

    1. execsnoop
    1. opensnoop
    1. ext4slower (或者brtfs*、xfs*、zfs*)
    1. biolatency
    1. biosnoop
    1. cachestat
    1. tcpconnect
    1. tcpaccept
    1. tcpretrans
    1. runqlat
    1. profile

这些工具对于创建新进程、打开文件、文件系统延迟、磁盘I/O延迟、文件系统缓存性能、TCP新建连接与重传、调度延迟,以及CPU使用情况,提供了更多信息。在后续章节中会提供以上工具的更多细节信息。

3.4.1execsnoop

在这里插入图片描述
execsnoop
p(8)通过跟踪每次execve(2)系统调用,为每个新创建的进程打印一行信息。
存活周期短的进程会消耗CPU资源,但通过传统的周期执行的监控工具较难发现,可
使用exeesnoop(8)来检查。第6章会进一步介绍该工具。

3.4.2opensnoop

在这里插入图片描述
opensnoop(8)在每次open(2)系统调用(及其变体)时打印一行信息,包括打开文件的路径打开操作是否成功(“ERR”列)。打开的文件可以透露应用程序工作的很多信息:识别应用程序的数据文件、配置文件和日志文件。有时应用程序在反复尝试打开一个不存在的文件时,会导致异常表现或者性能受损。第8章会进一步 介绍opensnoop(8)。

3.4.3 ext4slower

在这里插入图片描述
ext4slower(8)跟踪ext4文件系统中常见的操作(读、写、打开和同步),并且可以把耗时超过某个阈值的操作打印出来。这可以定位或者排除一类性能问题: 应用程序正在通过文件系统等待某个较慢的磁盘I/O。ext4 之外的其他文件系统,也有类似的工具:btrfsslower(8)、xfsslower(8), 以及zfsslower(8)。第8章将进行更详细的介绍。

3.4.4biolatency

在这里插入图片描述
biolatency(8)跟踪磁盘I/O延迟(也就是从向设备发出请求到请求完成的时间),并且以直方图显示。这种形式可以比用iostat(1)工具的平均值输出更好地解释磁盘I/O性能。可以显示I/O请求的多峰分布,峰指的是在一个分布中出现频次比其他值高的值,在这个例子里面我们看到一个多峰分布,其中一个峰位于0~ 1区间,另一个峰位于8~ 15区间。离群点也很明显,这个截屏显示了512~ 1023亳秒区间有一个离群点。第9章会进一步介绍biolatency(8)。

3.4.5biosnoop

在这里插入图片描述
biosnoop(8)将每一次磁盘I/O请求打印出来,包含延迟之类的细节信息。这允许你对磁盘I/O进行更细致的检查,并搜寻时序模式(比如,写动作之后的读排队)。第9章会进一步 介绍biosnoop(8)。

3.4.6 cachestat

在这里插入图片描述
cachestat(8)每秒(用户可以指定其他时长)打印一行摘要信息,展示文件系统缓存的统计信息。可以使用这个工具发现缓存命中率较低的问题,或者说较高的缓存命空率问题。这可以给你指出性能调优的方向。第8章会进- -步介绍cachestat(8)。

3.4.7 tcpconnect

在这里插入图片描述
tepconnect(8)会在每次主动的TCP连接建立(例如,通过connect()调用)时,打印一行信息,包含源地址、目的地址。在输出中应该寻找不寻常的连接请求,它们可能会暴露出软件配置的低效,也可能暴露入侵行为。
第10章会详细介绍tcpconnect(8)。

3.4.8 tcpaccept

在这里插入图片描述
在这里插入图片描述
tcpaccept(8)是tcpconnect(8)工具的搭档。每当有被动的TCP连接建立时(通过tcpaccept(),就会打印一行信息,同样包含源地址和目的地址。第10章会详细介绍tcpaccept(8)。

3.4.9tcpretrans

在这里插入图片描述
每次TCP重传数据包时,tcpretrans(8)会打印一行记录,包含源地址和目的地址,以及当时该TCP连接所处的内核状态。TCP重传会导致延迟和吞吐量方面的问题。如果重传发生在TCP ESTABLISHED状态下,会进一步寻找外部网络可能存在的问题。如果重传发在SYN_SENT状态下,这可能是CPU饱和的一个征兆,也可能是内核丢包引发的。第10章会进一步介绍tcpretrans(8)。

3.4.10runqlat

在这里插入图片描述
在这里插入图片描述
runqlat(8)对线程等待CPU运行的时间进行统计,并打印为一个直方图。本工具可以定位超出预期的CPU等待时间,就原因来说它可能是CPU饱和、配置错误或者是调度问题引起的。第6章会进一步介绍runqlat(8)。

3.4.11profile

在这里插入图片描述
profile(8)是一个CPU剖析器,这个工具可以用来理解哪些代码路径消耗了CPU资源。它周期性地对调用栈进行采样(抽取调用栈中的某函数地址),然后将消重后的调用栈(应该是消除调用栈中的重复)连同出现的次数(应该是某调用栈被采样到的次数)一起打印出来。上面的输出经过了截断,只显示了一个调用栈,它出现的次数是58次。第6章会详细介绍profile(8)。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值