<audio id="audio" title="06丨倾囊相授：我毕生所学的性能分析思路都在这里了" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/7b/d6/7be1cd5c82c60c1592a307d136d190d6.mp3"></audio>

我还年轻的时候，经常听一些大会或者演讲。有些人说，思路逻辑非常重要。我那时就想，你肯定是瞎忽悠的，因为我怎么就没听懂你说的思路呢？

而现在轮到自己来写或者讲一些东西的时候，才发现他们说得很对，而我之所以不理解，也是有原因的。

性能分析思路和具体的实现之间，有一道鸿沟，那就是操作的能力。之前我为什么听不懂那些人的思路，其实是因为我没有操作的功底。

而有了操作的功底之后，还有一个大的鸿沟要越过去，那就是从操作到对监控计数器的理解。这一步可以说让很多性能测试人员都望而却步了。

但是这还不算完，这一步迈过去之后，还有一个跳跃，就是相关性分析和证据链分析的过程。

如此一来，就会得到一张**性能测试分析的能力阶梯视图**，如下：

<img src="https://static001.geekbang.org/resource/image/1d/f8/1dbe8969f74d0d314675cb8bc24965f8.jpg" alt="">

1. 工具操作：包括压力工具、监控工具、剖析工具、调试工具。
1. 数值理解：包括上面工具中所有输出的数据。
1. **趋势分析、相关性分析、证据链分析**：就是理解了工具产生的数值之后，还要把它们的逻辑关系想明白。这才是性能测试分析中最重要的一环。
1. 最后才是调优：有了第3步之后，调优的方案策略就有很多种了，具体选择取决于调优成本和产生的效果。

那么怎么把这些内容都融会贯通呢？下面我们就来说说性能测试分析的几个重要环节。

应该说，从我十几年的性能工作中，上面讲的这些内容是我觉得最有价值的内容了。在今天的文章中，我们将对它做一次系统的说明。我先把**性能分析思路**大纲列在这里：

1. 瓶颈的精准判断；
1. 线程递增的策略；
1. 性能衰减的过程；
1. 响应时间的拆分；
1. 构建分析决策树；
1. 场景的比对。

## 瓶颈的精准判断

### TPS曲线

对性能瓶颈做出判断是性能分析的第一步，有了问题才能分析调优。

之前有很多人在描述性能测试的过程中，说要找到性能测试中曲线上的“拐点”。我也有明确说过，大部分系统其实是没有明确的拐点的。

举例来说，TPS的视图如下：

<img src="https://static001.geekbang.org/resource/image/67/4e/67613a7c330a115064167cac05d82d4e.png" alt="" title="TPS图1">

显然，这是一个阶梯式增加的场景，非常好。但是拐点在哪呢？有人说，显然在1200TPS左右的时候。也有人说了，显然是到1500TPS才是拐点呀。但是也有人说，这都已经能到2000TPS了，显然2000TPS是拐点。

我们再来看一下这张图对应的响应时间视图：

<img src="https://static001.geekbang.org/resource/image/67/51/67b8573993a39a68e923e78e19442151.png" alt="" title="响应时间图1">

是不是有人要说响应时间为4.5ms时是拐点了？

其实这些对拐点的判断，都是不合理的。如果我们对TPS的增加控制得更为精准的话，那么这个TPS的增加是有一个有清晰的弧度，而不是有一个非常清晰的拐点。

但是至少我们可以有一个非常明确的判断，那就是瓶颈在第二个压力阶梯上已经出现了。因为响应时间增加了，TPS增加得却没有那么多，到第三个阶梯时，显然增加的TPS更少了，响应时间也在不断地增加，所以，性能瓶颈在加剧，越往后就越明显。

那么我们的判断就是：

1. 有瓶颈！
1. 瓶颈和压力有关。
1. 压力呈阶梯，并且增长幅度在衰减。

如果你觉得上面的瓶颈还算清晰的话，那么我们再来看一张图：

<img src="https://static001.geekbang.org/resource/image/16/58/16e821606d14d3a0061244c1740a3b58.png" alt="" title="TPS图2">

在这个TPS的曲线中，你还能判断出拐点在哪吗？

显然是判断不出来拐点的，但是我们根据图得出以下几个结论：

1. 有瓶颈！
1. 瓶颈和压力有关。
1. 压力也是阶梯的，但是并没有明确的拐点。

我们再来看一个TPS图：

<img src="https://static001.geekbang.org/resource/image/3c/fb/3cc3ee474966a49f845fcfc52cb337fb.png" alt="" title="TPS图3">

看到这张图，是不是明显感觉系统有瓶颈呢？那么瓶颈是不是和压力大小有关呢？

这种比较有规律的问题，显然不是压力大小的原因。为什么呢？因为TPS周期性地出现降低，并且最大的TPS也都恢复到了差不多的水位上。所以，即使是压力降低，也最多降低最大的TPS水位，会让问题出现得更晚一点，但是不会不出现。

综合以上，如果画一个示意图的话，TPS的衰减过程大概会如下所示：

<img src="https://static001.geekbang.org/resource/image/a8/b4/a8ea90b0516f081058bf78bc24ed94b4.png" alt="">

1. 随着用户数的增加，响应时间也在缓慢增加。
1. TPS前期一直都有增加，但是增加的幅度在变缓，直到变平。

在这样的趋势图中，我们是看不到明确的拐点的。但是我们能做的清晰的判断就是：有瓶颈！

所以对TPS曲线来说，它可以明确告诉我们的就是：

1. 有没有瓶颈：其实准确说所有的系统都有性能瓶颈，只看我们在哪个量级在做性能测试了。
1. 瓶颈和压力有没有关系：TPS随着压力的变化而变化，那就是有关系。不管压力增不增加，TPS都会出现曲线趋势问题，那就是无关。

这时你可能会问，为什么不看响应时间就武断地下此结论呢？其实响应时间是用来判断业务有多快的，而TPS才是用来判断容量有多大的。

### 响应时间的曲线

我们还是来看看响应时间，下面看一张响应时间图：

<img src="https://static001.geekbang.org/resource/image/06/a7/061e77ee8dc20c9c1cd1ae1f6a27d7a7.png" alt="">

它对应的线程图是：

<img src="https://static001.geekbang.org/resource/image/32/8d/32ab933156f0ba11a1f08489bf62398d.png" alt="">

多明显的问题，随着线程的增多，响应时间也在增加，是吧。再来看它们对应的TPS图：

<img src="https://static001.geekbang.org/resource/image/c9/48/c9f48c144a3663b3779832f62e25e148.png" alt="">

到第40个线程时，TPS基本上达到上限，为2500左右。响应时间随着线程数的增加而增加了，系统的瓶颈显而易见地出现了。

但是，如果只让你看TPS曲线，你是不是也会有同样的判断？那就是：有瓶颈！并且和压力有关？所以说，其实TPS就可以告诉我们系统有没有瓶颈了，而响应时间是用来判断业务有多快的。

后面我们还会提到响应时间会是性能分析调优的重要分析对象。

## 线程递增的策略

讲完响应时间之后，我们再来看下线程递增。

在见识了很多性能测试人员做的场景之后，必须得承认，有些场景的问题太多了。

首先，我们来看两个场景的执行对比。

场景1的线程图：

<img src="https://static001.geekbang.org/resource/image/68/d7/68b4c0811e61657432a8b4ceb1c7dbd7.png" alt="">

场景1的TPS图：

<img src="https://static001.geekbang.org/resource/image/ac/b5/aca9cb229a4503b0ebba911c38cf0bb5.png" alt="">

场景1的响应时间图：

<img src="https://static001.geekbang.org/resource/image/bd/af/bda2ca6d65527aa6f3a435573eaefeaf.png" alt="">

场景2的线程图：

<img src="https://static001.geekbang.org/resource/image/b1/7a/b105147c5cfbdc66fa708daae0a1977a.png" alt="">

场景2的TPS图：

<img src="https://static001.geekbang.org/resource/image/8a/2a/8a849b11b9be9beffebf0c4579c4a12a.png" alt="">

场景2的响应时间图：

<img src="https://static001.geekbang.org/resource/image/a9/e4/a9e3d6318a1ef1d7fc28e9b45c4733e4.png" alt="">

这两个场景的比对如下：

<img src="https://static001.geekbang.org/resource/image/87/e6/87a445e7c292ca19f8f71b7dface94e6.png" alt="">

有了这些对比数据之后，你是不是觉得哪里似乎是有问题的？

对的！

TPS都是达到400，但两个场景中线程递增的策略不同，产生的响应时间完全不同。虽然都没有报错，但是第一种场景是完全不符合真实的业务场景的。这是为什么呢？

在场景的执行过程中，首先，响应时间应该是从低到高的，而在场景1中不是这样。其次，线程应该是递增的，而场景1并没有这样做（这里或许有人会想到秒杀的场景，认为场景1符合秒杀的业务设定，这个问题我们稍后提及）。最后，在两个场景中，TPS的上限都达到了400TPS。但是你可以看到，在场景2中，只要40个线程即可达到，但场景1中居然用到了500线程，显然压力过大，所以响应时间才那么长。

其实在生产环境中，像场景1这样的情形是不会出现的。如果它出现了，那就是你作为性能测试的责任，因为你没有给出生产环境中应该如何控制流量的参数配置说明。

同时，我们从上面的场景对比可以看到，**对一个系统来说，如果仅在改变压力策略（其他的条件比如环境、数据、软硬件配置等都不变）的情况下，系统的最大TPS上限是固定的**。

场景2使用了递增的策略，在每个阶梯递增的过程中，出现了抖动，这就明显是系统设置的不合理导致的。设置不合理，有两种可能性：1. 资源的动态分配不合理，像后端线程池、内存、缓存等等；2. 数据没有预热。

我们再回到之前说的秒杀场景。

说到秒杀场景，有人觉得用大线程并发是合理的，其实这属于认识上的错误。因为即使线程数增加得再多，对已经达到TPS上限的系统来说，除了会增加响应时间之外，并无其他作用。所以我们描述系统的容量是用系统当前能处理的业务量（你用TPS也好，RPS也好，HPS也好，它们都是用来描述服务端的处理能力的），而不是压力工具中的线程数。这一点，我在第5篇文章中已经做了详细的解析，你可以回去再看看。

那么，对于场景中线程（有些工具中叫虚拟用户）递增的策略，我们要做到以下几点：

1. 场景中的线程递增一定是连续的，并且在递增的过程中也是有梯度的。
1. 场景中的线程递增一定要和TPS的递增有比例关系，而不是突然达到最上限。后面在场景的篇幅中我们会再说它们之间的比例关系。
1. 上面两点针对的是常规的性能场景。对于秒杀类的场景，我们前期一定是做好了系统预热的工作的，在预热之后，线程突增产生的压力，也是在可处理范围的。这时，我们可以设计线程突增的场景来看系统瞬间的处理能力。如果不能模拟出秒杀的陡增，就是不合理的场景。

这里给出我做性能场景递增的经验值：

<img src="https://static001.geekbang.org/resource/image/33/9c/3341781894e1bbf771e8a35781e7df9c.png" alt="">

当然这里也不会是放在哪个系统中都适合的递增幅度，你还是要根据实际的测试过程来做相应的判断。

有了这些判断之后，相信大家都能做出合理的场景来了。

## 性能衰减的过程

有了瓶颈的判断能力，也有了线程递增的意识，那么下面在场景执行中，我们就要有判断性能衰减的能力了吧。

来，我们先看一个压力过程中产生的结果图。

<img src="https://static001.geekbang.org/resource/image/eb/ce/eb938af9e8bd5c4fcb170855102e23ce.png" alt="">

在递增的压力过程中，随着用户数的增加。我们可以做几次计算。

第一次计算，在线程达到24时，TPS为1810.6，也就是每线程每秒发出75.44个请求。

第二次计算，在线程达到72时，TPS为4375.1，也就是每线程每秒发出60.77个请求。

第三次计算，在线程达到137时，TPS为5034，也就是每线程每秒发出36.74个请求。

通过这三次计算，我们是不是可以看到，每线程每秒发出的请求数在变少，但是整体TPS是在增加的。

我们有很多做性能测试的人，基本上，只看TPS和响应时间的时候，在上面这个示例中，肯定会一直往上加用户。虽然响应时间在增加，但是增加得也不多嘛。

但实际上，通过我们的计算可以知道，性能是在不断地衰减的。我们来看一张统计图：

<img src="https://static001.geekbang.org/resource/image/88/17/88f8facef19db7d6828fa64349483b17.png" alt="">

通过红线的大致比对可以知道，当每线程每秒的请求数降到55左右的时候，TPS就达到上限了，大概在5000左右，再接着往上增加线程已经没有用了，响应时间开始往上增加了。

这就是性能衰减的过程（题外话，在上图中，其实还有一个问题，就是在红线前面，性能在上升的过程中有几次抖动，这个抖动到后面变大了，也变频繁了，如果这是必然出现的抖动，那也是配置问题，希望你注意到这一点）。

为什么要这么细致地描述性能衰减的过程呢？

其实我就是想告诉你，**只要每线程每秒的TPS开始变少，就意味着性能瓶颈已经出现了。但是瓶颈出现之后，并不是说服务器的处理能力（这里我们用TPS来描述）会下降，应该说TPS仍然会上升，在性能不断衰减的过程中，TPS就会达到上限**。

这也是前面我说的，性能瓶颈其实在最大TPS之前早就已经出现了。

那么我们是不是应该在性能衰减到最大TPS时就停止场景呢？这个不一定的哦。

因为停不停场景，取决于我们的场景目标，如果我们只是为了得到最大TPS，那确实可以停止场景了。但是，如果我们要扩大化性能瓶颈，也就是说为了让瓶颈更为明显，就完全不需要停止场景，只要不报错，就接着往上压，一直压到我们要说的下一个话题——响应时间变长，需要拆分。

## 响应时间的拆分

在性能分析中，响应时间的拆分通常是一个分析起点。因为在性能场景中，不管是什么原因，只要系统达到了瓶颈，再接着增加压力，肯定会导致响应时间的上升，直到超时为止。

在判断了瓶颈之后，我们需要找到问题出现在什么地方。在压力工具上看到的响应时间，都是经过了后端的每一个系统的。

那么，当响应时间变长，我们就要知道，它在哪个阶段时间变长了。

我们看下这张图。

<img src="https://static001.geekbang.org/resource/image/f7/0c/f76da16830ff8c41559537901f8d0a0c.jpg" alt="">

这应该是最简单的一个压力测试逻辑了。一个应用，一个DB，结果也拆分出了8个时间段，这还是在我没有加上压力工具自己所消耗的时间的情况下。

如果我们要分析压力工具中的响应时间，拆分的逻辑就是上面这个示意图。

但是在真实的场景中，基本上不是这样的。如果是内网，那基本上都是连在一个交换机上，所以通常是这样的：

<img src="https://static001.geekbang.org/resource/image/94/71/94c161f0082262de076233415e5e1671.png" alt="">

在这样的拓扑中，我们仍然可以拆出来t1到t8的时间。只是实际动手的时候，思路一定要清晰，时间拆分是从哪里到哪里，要画出来，不能混乱。

我们有很多手段可以进行时间的拆分，当然要看我们的应用支持哪一种。

如果我们是这样的架构，拆分时间应该是比较清楚的。

<img src="https://static001.geekbang.org/resource/image/a4/0d/a4552dfe28750a51eb34e5ed7d50230d.jpg" alt=""><br>
首先我们需要查看Nginx上的时间。日志里就可以通过配置$request_time $upstream_response_time得到日志如下信息：

```
14.131.17.129 - - [09/Dec/2019:08:08:09 +0000] &quot;GET / HTTP/1.1&quot; 200 25317 0.028 0.028

```

最后两列中，前面是请求时间的28ms，后面是后端响应时间的28ms。

同时，我们再到Tomcat上去看时间。

```
172.18.0.1 - - [09/Dec/2019:08:08:09 +0000] &quot;GET / HTTP/1.1&quot; 200 25317 28 27 http-nio-8080-exec-1

```

请求时间消耗了28ms，响应时间消耗了27ms。

接着再来看一下前端的时间消耗。

<img src="https://static001.geekbang.org/resource/image/a6/04/a6821521f99df9f0a63df235b3395a04.png" alt="">

从这里可以看到，从发出请求到接收到第一个字节，即TTFB是55.01ms，内容下载用了11.75ms。从这就可以看得出Nginx基本上没消耗时间，因为它和Tomcat上的请求响应时间非常接近。

那么网络上的消耗时间怎么样呢？我看到有很多人用TTFB来描述网络的时间。先来说明一下，TTFB中显然包括了后端一系列处理和网络传输的时间。如下图所示。

<img src="https://static001.geekbang.org/resource/image/40/c8/401b25353a74784b41c7ed1f29d6e9c8.jpg" alt=""><br>
下面的紫色点是指要接收的内容。上面的红色线就是TTFB。

如果接收完了呢？就是这个状态。

<img src="https://static001.geekbang.org/resource/image/cc/3c/ccdc306190e72f099c4757f2f9fd5e3c.jpg" alt=""><br>
所以，我觉得用TTFB描述网络的健康状态并不合理。如果用Content Download来描述会更为合理。比如我们上面的这个例子中，那就是11.75ms下载了25317 Bytes的内容。

Tomcat上基本上是消耗了处理的所有时间，当然这中间也包括了MySQL花费的时间。而前端看到的其他时间就消耗在了网络中。

在这个例子中，主要说明了响应时间怎么一步步拆。当然，如果你是下面这种情况的话，再一个个拆就比较辛苦了，需要换另一种方式。

<img src="https://static001.geekbang.org/resource/image/40/c9/400e3191138d25ac195cae863093e4c9.jpg" alt="">

你肯定想知道每个系统消耗了多长时间，那么我们就需要链路监控工具来拆分时间了。比如像这样来拆分：

<img src="https://static001.geekbang.org/resource/image/8f/36/8fb9d1d502be932c8a34b6e50344d336.png" alt="">

从User开始，每个服务之间的调用时间，都需要看看时间消耗的监控。这就是时间拆分的一种方式。

其实不管我们用什么样的工具来监控，最终我们想得到的无非是每个环节消耗了多长时间。用日志也好，用链路监控工具也好，甚至抓包都可以。

当我们拆分到了某个环节之后，就有了下一步的动作：构建分析决策树。

## 构建分析决策树

关于分析决策树，我在很多场合也都有提及。

分析决策树，对性能测试分析人员实在是太重要了，是性能分析中不可或缺的一环。**它是对架构的梳理，是对系统的梳理，是对问题的梳理，是对查找证据链过程的梳理，是对分析思路的梳理。它起的是纵观全局，高屋建瓴的指导作用**。

性能做到了艺术的层级之后，分析决策树就是提炼出来的，可以触类旁通的方法论。

而我要在这里跟你讲的，就是这样的方法论。

应该说，所有的技术行业在面对自己的问题时，都需要有分析决策树。再广而推之的话，所有的问题都要有分析决策树来协助。

通过上面的几个步骤，我们就会知道时间消耗在了哪个节点上。那么之后呢？又当如何？

总要找到根本的原因才可以吧，我画了如下的分析决策图：

<img src="https://static001.geekbang.org/resource/image/aa/2b/aaa0c2e23aa5648a46d6a47b78c3c32b.jpg" alt="">

从压力工具中，只需要知道TPS、响应时间和错误率三条曲线，就可以明确判断瓶颈是否存在。再通过分段分层策略，结合监控平台、日志平台，或者其他的实时分析平台，知道架构中的哪个环节有问题，然后再根据更细化的架构图一一拆解下去。

我在这里，以数据库分析和操作系统分析举一下例子。

首先我们看一下数据库分析决策树。

比如针对RDBMS中的MySQL，我们就可以画一个如下的决策树：

<img src="https://static001.geekbang.org/resource/image/5b/27/5b9c8e2f05ee467ffc834dad86dcb927.png" alt="">

由于这里面的内容实在过多，无法一次性展现在这里。我举几个具体的例子给你说明一下。

MySQL中的索引统计信息有配置值，有状态值。我们要根据具体的结果来判断是否需要增加key_buffer_size值的大小。比如这种就无所谓了。

```
    Buffer used     3.00k of   8.00M  %Used:   0.0004

```

从上面的数据可以看到，key buffer size就用到了4%，显然不用增加。

再比如，我们看到这样的数据：

```
       __Tables_______________________
    Open             2000 of 2000    %Cache: 100.00
    Opened         15.99M     4.1/s

```

这就明显有问题了。配置值为2000的Open Table Cache，已经被占满了。显然这里需要分析。但是，看到状态值达到配置值并不意味着我们需要赶紧加大配置值，而是要分析是否合理，再做相应的处理。比如说上面这个，Table确实打开得多，但是如果我们再对应看下这一条。

```
    Slow 2 s        6.21M     1.6/s

```

你是不是觉得应该先去处理慢SQL的问题了？

关于数据库的我们就不举更多的例子了。在这里只是为了告诉你，在分析决策树的创建过程中，有非常多的相互依赖关系。

然后我们再来看一下操作系统分析决策树，我在这里需要强调一下，操作系统的分析决策树，不可以绕过。

<img src="https://static001.geekbang.org/resource/image/79/1c/79420c5b099a09bc7b5120d98b968b1c.png" alt=""><br>
如果你想到操作系统架构图就头大，那么这时候应该觉得有了希望。那就是我觉得操作系统上的问题判断是比较清晰的，所以基于此决策树，每个人都可以做到对操作系统中性能问题的证据链查找。

但是！对嘛，总得有个但是。

对操作系统的理解是个必然的前提。我看过很多人写的操作系统性能分析方面的书籍或资料，发现大部分人把描述计数器的数值当成性能分析。

怎么理解这句话呢？比如说<br>
“CPU使用率在TPS上升的过程中，从10%增加到95%，超过了预期值。” “内存使用率达到99%，所以是瓶颈点。” “I/O使用率达到100%。” 等等。

像这样的描述，在我的性能团队中，一定会被骂回去重写。我要这些描述有什么用？我要的是为什么达到了这样的值，原因在哪？怎么解决？

就像分析决策树中所描述的那样，性能工程师要做的是一步步地细化分析，给出最终的原因。

有人说，如果按这个路子，似乎操作系统的分析并不复杂嘛。大概三五个命令就可以跳到代码层了。是的，对于操作来说，确实不多，但是对于判断来说，那就复杂了。举个例子来说明一下：

<img src="https://static001.geekbang.org/resource/image/62/23/62fe8e28939ba946aa409f643a826723.png" alt="">

看到这样的图，你是不是有种手足无措的感觉？中断能占40%，sy CPU也能占40%。这系统还用干业务的事吗？全干自己的事去了，可见操作系统有问题！你是不是要做这个判断了？

而实际情况是，这个主机上只有一个网卡队列，而请求量又比较大。

<img src="https://static001.geekbang.org/resource/image/dc/16/dc87f5b31b707be5fa115bd4e5f1b416.png" alt="">

所以要解决的是网卡队列的问题，至于怎么解决，那手段就多了。可以换个服务器，可以多加几个队列，可以多接几个节点......

以上只是给出几个性能分析过程中常见的决策树示例。在后续的分析过程实例中，我们将秉承着这种分析思路，一步步地走到瓶颈的面前。

## 场景的比对

为什么要写这一部分呢？因为我看到很多人对瓶颈的判断，并不那么精确，所以想写一下场景比对的建议。

其实简单来说，就一句话：当你觉得系统中哪个环节不行的时候， 又没能力分析它，你可以直接做该环节的增加。

举例来，我们现在有一个如下的架构：

<img src="https://static001.geekbang.org/resource/image/38/f1/387e513857efb2b5777a31f7ae92d4f1.jpg" alt=""><br>
可以得到这样的结果：

<img src="https://static001.geekbang.org/resource/image/78/db/78e2dcb7bba43e27cbe715d2434c4bdb.png" alt="">

从TPS曲线中，我们可以明显看到系统是有瓶颈的，但是并不知道在哪里。鉴于系统架构如此简单，我们索性直接在某环节上加上一台服务器，变成这样：

<img src="https://static001.geekbang.org/resource/image/2b/ee/2b2bd4cd54f55481ea87e164ab18d4ee.jpg" alt=""><br>
然后得到如下数据：

<img src="https://static001.geekbang.org/resource/image/a2/77/a2dd11b1143c09578fbedf6574f3b277.png" alt="">

哟，没好使！

怎么办？再接着加其他节点，我加了更多的JMeter机器。

<img src="https://static001.geekbang.org/resource/image/2b/ea/2bcaf3cdc7669efce857fcd5736f50ea.jpg" alt=""><br>
再来看下结果：

<img src="https://static001.geekbang.org/resource/image/d5/7b/d59c58bd5a38efd9b397d5755330b27b.png" alt="">

真巧，TPS增加了！

看到了吧，这就是我说的场景比对。

当我们不知道系统中哪个环节存在性能瓶颈时，对架构并不复杂的系统来说，可以使用这样的手段，来做替换法，以快速定位问题。

## 总结

在这一篇中，我说到了瓶颈的精准判断、线程递增的策略、性能衰减的过程、响应时间的拆分、构建分析决策树以及场景的比对，这几个环节，是性能分析过程中非常重要的环节。

从我的经验上来说，这一篇文章可能是我工作十几年的精华所在了。而这里的每一个环节，又有非常多的细分，特别是构建分析决策树这一块，它需要太多的架构知识、系统知识、数据库知识等等。鉴于本文只是想起到一个提纲挈领的作用，所以无法展开描述，希望在后续的篇幅中，我们尽量细致拆解。

## 思考题

今天的内容虽然有点多，但总的来说，思路比较清晰，理解起来也比较容易。如果你认真学习了今天的内容，不妨思考两个问题，为什么线程递增过程不能断？构建分析决策树的关键是什么？

欢迎你在评论区写下你的思考，我会和你一起交流，也欢迎把这篇文章分享给你的朋友或者同事，一起交流一下。
