TSA方法

白昼怎懂夜的黑 提交于 2019-12-22 13:40:32

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

来源

有两种基本的性能分析方法可以应对大部分性能问题。一是面向资源的USE方法,它提供了识别常见瓶颈和错误的检查清单。二是面向线程的TSA方法,用于识别线程性能不佳的原因。我在今年(译者注:时为2014年)Velocity会议的《Stop The Guessing》演讲上总结出了TSA方法。这一方法同时也在我《系统性能》一书的《应用程序》章节里进行了介绍。

作为USE方法的补充,TSA方法具有不同的视角:线程而非资源。TSA提供了分析工作的出发点,并将调查范围缩小到了错误周边。TSA方法可以应用到任何操作系统,它从一个我们想要回答的问题的答案发展而来:每个线程的时间都用到哪里了?

我在近期的系统性能课程上教授了这个方法,课程帮助了我的学生——大多是系统管理员——快速解决一些列性能问题。我使用了这种方法很多年,在企业和云生产环境下,解决了数不清的性能问题。

总结

TSA(Thread State Analysis)方法可以总结为:

  1. 对每个重要线程,度量不同状态下线程花费的总时间。
  2. 使用适当的工具,按频率从高到底逐一分析线程状态。

我使用“线程”这一词汇来表示操作系统运行实体,它可以是线程、任务或进程。重要线程可以是应用线程或内核线程。

线程时间被分割为几个互斥状态。下列6个状态基于通用操作系统内核,被选用于识别关键的性能问题原因:

  • 执行中。在CPU上执行。
  • 可运行。等待分配CPU执行。
  • 匿名页交换。可运行,阻塞等待内存页面持久化。
  • 休眠。等待I/O,包括网络、块设备和数据/代码分页。
  • 锁。等待获取同步锁。
  • 空闲。等待任务。

这些状态可以适配到你的操作系统上,依赖于操作系统提供的度量和分析工具。可能还有一些其他的状态,如果操作系统提供了一些易于获得又有用的状态,并且状态的数量足够小,以便在实践中应用。

为了准备使用TSA方法,你可以识别操作系统中可以度量的线程状态,编写操作系统所提供度量工具,以及如何分析每个状态的文档。这些可以与你的团队分享,为每个人提供一个分析性能问题的快速过程。很快我将提供一个总结,以Solaris为例。

使用示例

下面的简短例子描述了云计算中一个常用的性能问题,并且展示了TSA方法如何为进一步调查提供出发点和方向。

当应用程序遇到性能问题,遵循TSA方法,对6个状态的持续时间进行度量。大约50%的时间处于可运行状态:等待分配CPU执行。现在使用工具分析线程状态,使用 mpstat 查看CPU是否超载,使用一些特殊工具检查CPU资源控制。很快发现应用程序被CPU限额所限流。这种情况常见于云计算环境。随着CPU限额的增加,性能问题得到解决。

时间都去哪了

一些监控软件可以按照程序组件对时间进行分解,比如度量“MySQL使用时间”、“PHP使用时间”等等。这些时间的度量通常从应用组件执行任务开始,到任务执行完毕结束。和面向线程不同,这种方法是面向请求的,将请求使时间分为到应用组件。这种方法可能具有误导性,但是可以通过对每个组件应用TSA方法来识别问题。

例如,为了更好的理解“MySQL使用时间”,使用TSA方法检查MySQL线程。你可能发现MySQL把大量时间消耗在可运行状态,因为另外一个程序或租户正在偷取CPU时间。将这种情况报告为“MySQL使用时间”是具有误导性的,时间没有花费在执行MySQL上,相反,时间是另外一个程序或租户使用的。TSA可以节省因调查方向错误而浪费的时间,也可以解决大量遗留问题。

状态转换图

前面介绍的6个状态受到Unix进程状态转移图启发。下面是一个相似的线程状态图,并将6个状态高亮显示。

这个图可以应用到所有的应用线程,或值得关注的内核线程。

6种状态TSA方法

下面是6种状态的详细分解,可以应用到大部分操作系统。这个表格包括了调查每个状态的建议。

状态 描述 调查建议
执行 在CPU上运行 分为用户时间和系统时间。对于用户时间,使用CPU分析器确认活跃代码路径。对于系统时间,检查系统调用频率,分析内核CPU时间。分析可以包括火焰图。注意CPU时间可能包含锁自旋。
可运行 运行队列延迟 检查系统CPU使用率和饱和度,对每个物理CPU和资源控制。检查处理器绑定,这可能影响CPU调度。
匿名页交换 可运行,但发生页面交换(page out、swap out),等待持久化 检查系统剩余主存。同时检查任何资源控制限制了内存使用。饱和度度量需要进行分析:分页和交换。
休眠 等待I/O,包括网络、块设备和数据/代码页交换(page in) 检查系统调用,资源使用率,线程阻塞。系统调用:确认系统调用时间和相关资源,同时检查mmap使用情况和通过mmap进行的非系统调用I/O。资源使用:使用USE方法确认活跃资源。线程阻塞:使用用户栈及内核栈跟踪off-CPU事件调度来识别原因。
等待获取同步锁 识别线程等待的锁,和获取锁需要时间的原因。锁分析。
空闲 等待任务 检查客户端负载。

术语:

  • 匿名页交换:页交换会移动页面,即小单元(通常是4KB)内存。匿名表示内存页面在文件系统中没有具名位置。Linux把这种类型页面交换叫做swapping。
  • 休眠。这种状态下线程离开CPU等待一个事件。这个属于源自Unix。在6种状态TSA方法中不会区分锁和空闲状态与休眠状态。

操作系统内核直接管理大部分的这些状态。这意味着有一些代码路径可以检测(如果它们还没有检测到的话)为任何线程提供状态计时信息。

空闲状态

在今天的操作系统中,通常没有简单方法来识别空闲状态。应用线程以多种形式等待任务,包括等待新的网络连接、网络I/O、锁、或时钟。从内核的角度,这时应用线程处于休眠或锁状态。经过一些分析,你会发现这时实际是空闲时间。

识别空闲状态很难。

大多数情况下,分析时可以忽略空闲状态,虽然它是最常见的状态。当一个应用程序10%的时间在处理请求,90%的时间在空闲时仍然可能存在性能问题。在TSA方法中,除空闲之外的第二常见状态值得调查。

添加其他状态

增加更多的状态来缩小初次调查范围的想法时吸引人的。这里有些建议用于细分状态:

  • 执行。可以分解为用户时间和系统时间(内核)。
  • 休眠。可以分解为存储、网络和其他等待状态。

从执行状态中分解出内存等待,比如内存暂停周期,将执行状态度量为非暂停指令周期。这种想法很吸引人,但是实现起来有些困难。

检查操作系统可以提供的线程状态,这些状态可以如何使用,是否有其他的有用状态。例如,Mac OS X在指令中提供了多种线程状态,包括等待和不可中断等待。

在实践中,前文的6种状态方法是有效的TSA方法的1级分解。这些状态可以在后续的调查种,根据需要进一步分解。

延迟状态

可运行、匿名页交换、休眠和锁状态表明执行工作的时间,即延迟,用在等待上。优化这些延迟状态通常会提供最大的好处,这依赖于操作系统提供的分析工具。

出于一些原因,如果我发现超过10%的时间处于可运行或匿名页交换状态,通常我会首先调试和评估这些状态。这可以简化对其余状态的分析,由于因素更少了。

TSA方法例子:Solaris

这里是一个关于在Solaris系列操作系统上应用TSA方法的总结指导。Solaris有多种状态,将线程时间分割为10个状态,每个状态使用高精度计时。这已经完成了6种状态TSA方法的大部分工作,并产生了一个简单的例子。我将探究其他操作系统(如Linux),目前这仍需更多的工作。

我们从运行 prstat -mLc 1 开始。prstat是Solaris上一个类似top的工具,使用微状态统计、线程独立统计、不刷新屏幕、并且以1秒为间隔。如果需要,prstat允许以指定进程为目标。

对每个状态,调查状态的工具在本总结中介绍,同时还介绍了为提升性能而执行的操作。

prstat输出显示执行时间占63%(35+28),匿名页交换时间占22%,休眠时间占16%。这些状态应该使用这里描述的工具依顺序调查。

匿名页交换通常可以快速分析和解决,我喜欢首先修复这个问题,然后重新运行 prstat 查看性能表现。匿名页交换通常是由于程序错误配置,使得超过主存,并且操作系统开始将内存页面交换到磁盘上。这个问题可以通过修改应用配置并重启进行修复。

理解执行时间通常可以使用火焰图容易的完成。可以生成用户时间和系统时间火焰图。

16%的休眠时间可能包含空闲状态。用于off-CPU分析的DTrace展示了堆栈跟踪和off-CPU持续时间。这些也可以制作到火焰图中。分解空闲状态需要了解堆栈并识别处理过程中的工作。这通常并不简单,需要理解应用程序内部。

RSTS/E的16种状态

在2000年,太阳微系统公司为Solaris8开发了微状态计时特性,而线程状态的术语可以溯及更早之前。1969-72年开发的TENEX操作系统可以使用Control-T按键打印当前任务的状态(线程状态)和其他细节。这一功能由RUNSTAT命令实现,它可以识别一些列状态,包括“运行中”、“等待IO”、“休眠”和“等待fork”。

RSTS/E是另一个从1970年代开发的DEC操作系统,最终增加了Control-T功能和一组任务状态细分。下表来自于RSTS/E系统用户手册。

对于不同的I/O设备设置不同的状态是值得思考的,尽管在TSA方法中使用太多状态可能会很笨重。我将对分解进行更多讨论。

要注意虽然状态是已知的,我想内核没有像微状态计时那样跟踪累加时间。为了在一些老旧操作系统上执行TSA方法,你将需要分析(采样)线程状态的方法。

非时间分片

关于旧电脑的话题,前面描述的状态适用于分时操作系统(如Unix、Linux、Windows等)。如果你想应用UNIVAC,那么线程状态将需要重新思考。例如,计算机可能总是在执行同一个程序,并在执行指令期间等待I/O。在这种情况下,没有对这些状态重新定义。休眠在I/O等待上的时间和执行时间不是互斥的。

结论

TSA方法是一种简单的分析独立线程性能的方法,并提供了分析的出发点和方向。这个方法可以在早期调查中执行,配合USE方法使用来得到初期的性能处理。TSA方法包括选择有用的线程状态来分割线程时间,然后决定那个操作系统工具可以度量这些状态,以及那个操作系统工具可以进一步调查线程状态。

在本文中,我解释了TSA方法并提供了一个通用的6种状态分解。我还提供了例子展示如何将TSA方法应用到操作系统,以Solaris为目标。后续我会开发将TSA应用到其他操作系统上的特定的操作。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!