gitbook/性能测试实战30讲/docs/181916.md
2022-09-03 22:05:03 +08:00

198 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 05丨指标关系你知道并发用户数应该怎么算吗
我在性能综述的那三篇文章中描述了各种指标比如TPS、RPS、QPS、HPS、CPM等。我也强调了我们在实际工作的时候应该对这些概念有统一的认识。
![](https://static001.geekbang.org/resource/image/d4/5d/d46c772ccce3e8270e5f7be7e915755d.jpg)
这样的话,在使用过程中,一个团队或企业从上到下都具有同样的概念意识,就可以避免出现沟通上的偏差。
我说一个故事。
我以前接触过一个咨询项目。在我接触之前性能测试团队一直给老板汇报着一个数据那就是10000TPS。并且在每个版本之后都会出一个性能测试报告老板一看这个数据并没有少于10000TPS很好。 后来我进去一看他们一直提的这个10000TPS指的是单业务的订单并且是最基础的订单逻辑。那么问题来了如果混合起来会怎么样呢于是我就让他们做个混合容量场景显然提容量不提混合只说单接口的容量是不能满足生产环境要求的。
结果怎么样呢只能测试到6000TPS。于是我就要去跟老板解释说系统达到的指标是6000TPS。老板就恼火了呀同样的系统以前报的一直是10000TPS现在怎么只有6000TPS了不行你们开发的这个版本肯定是有问题的。于是老板找到了研发VP研发VP找到了研发经理研发经理找了研发组长研发组长又找到了开发工程师开发工程师找到了我。我说之前不是混合场景的结果现在混合容量场景最多达到6000TPS你们可以自己来测。
然后证明TPS确实只能达到6000。然后就是一轮又一轮的向上解释。
说这个故事是为了告诉你你用TPS也好RPS也好QPS也好甚至用西夏文来定义也不是不可以只要在一个团队中大家都懂就可以了。
但是,在性能市场上,我们总要用具有普适性的指标说明,而不是用混乱的体系。
在这里我建议用TPS做为关键的性能指标。那么在今天的内容里我们就要说明白TPS到底是什么。在第3篇文章中我提到过在不同的测试目标中设置不同的事务也就是TPS中的T要根据实际的业务产生变化。
那么问题又来了TPS和并发数是什么关系呢 在并发中谁来承载”并发“这个概念呢?
说到这个,我们先说一下所谓的“绝对并发”和“相对并发”这两个概念。绝对并发指的是同一时刻的并发数;相对并发指的是一个时间段内发生的事情。
你能详细说一下这两个概念之间的区别吗?如果说不出来那简直太正常了,因为这两个概念把事情说得更复杂了。
## 什么是并发
下面我们就来说一下“并发”这个概念。
![](https://static001.geekbang.org/resource/image/0e/96/0ef2fca88f59342a64084e147b33af96.jpg)
我们假设上图中的这些小人是严格按照这个逻辑到达系统的那显然系统的绝对并发用户数是4。如果描述1秒内的并发用户数那就是16。是不是显而易见
但是,在实际的系统中,用户通常是这样分配的:
![](https://static001.geekbang.org/resource/image/1e/23/1e42cc116598acb7c703eec95a7c6723.png)
也就是说,这些用户会分布在系统中不同的服务、网络等对象中。这时候”绝对并发“这个概念就难描述了,你说的是哪部分的绝对并发呢?
要说积分服务那是2要说库存服务那是5要说订单服务它自己是5个请求正在处理但同时它又hold住了5个到库存服务的链接因为要等着它返回之后再返回给前端。所以将绝对并发细分下去之后你会发现头都大了不知道要描述什么了。
有人说我们可以通过CPU啊I/O啊或者内存来描述绝对并发来看CPU在同一时刻处理的任务数。如果是这样的话绝对并发还用算吗那肯定是CPU的个数呀。有人说CPU 1ns就可以处理好多个任务了这里的1ns也是时间段呀。要说绝对的某个时刻任务数肯定不会大于CPU物理个数。
所以“绝对并发”这个概念,不管是用来描述硬件细化的层面,还是用来描述业务逻辑的层面,都是没什么意义的。
我们只要描述并发就好了,不用有“相对”和“绝对”的概念,这样可以简化沟通,也不会出错。
那么如何来描述上面的并发用户数呢在这里我建议用TPS来承载“并发”这个概念。
并发数是16TPS就是1秒内整个系统处理了16个事务。
这样描述就够了,别纠结。
## 在线用户数、并发用户数怎么计算
那么新问题又来了,在线用户数和并发用户数应该如何算呢?下面我们接着来看示意图:
![](https://static001.geekbang.org/resource/image/1b/99/1beff8afb0116c72dd428eba9d329299.jpg)
如上图所示总共有32个用户进入了系统但是绿色的用户并没有任何动作那么显然在线用户数是32个并发用户数是16个这时的并发度就是50%。
但在一个系统中,通常都是下面这个样子的。
![](https://static001.geekbang.org/resource/image/59/1c/59fd25efa2fdd259b4fc0b6b462a031c.jpg)
为了能hold住更多的用户我们通常都会把一些数据放到Redis这样的缓存服务器中。所以在线用户数怎么算呢如果仅从上面这种简单的图来看的话其实就是缓存服务器能有多大能hold住多少用户需要的数据。
最多再加上在超时路上的用户数。如下所示:
![](https://static001.geekbang.org/resource/image/4b/10/4bbf31a73fd4ccf6245634b8c7eb2910.jpg)
所以我们要是想知道在线的最大的用户数是多少,对于一个设计逻辑清晰的系统来说,不用测试就可以知道,直接拿缓存的内存来算就可以了。
假设一个用户进入系统之后需要用10k内存来维护一个用户的信息那么10G的内存就能hold住1,048,576个用户的数据这就是最大在线用户数了。在实际的项目中我们还会将超时放在一起来考虑。
但并发用户数不同,他们需要在系统中执行某个动作。我们要测试的重中之重,就是统计这些正在执行动作的并发用户数。
当我们统计生产环境中的在线用户数时,并发用户数也是要同时统计的。这里会涉及到一个概念:**并发度**。
要想计算并发用户和在线用户数之间的关系,都需要有并发度。
做性能的人都知道,我们有时会接到一个需求,那就是一定要测试出来**系统最大在线用户数是多少**。这个需求怎么做呢?
很多人都是通过加思考时间有的压力工具中叫等待时间Sleep时间来保持用户与系统之间的session不断但实际上的并发度非常非常低。
我曾经看到一个小伙在一台4C8G的笔记本上用LoadRunner跑了1万个用户里面的error疯狂上涨当然正常的事务也有。我问他你这个场景有什么意义这么多错他说老板要一个最大在线用户数。我说你这些都错了呀。他说没事我要的是Running User能达到最大就行给老板交差。我只能默默地离开了。
这里有一个比较严重的理解误区,那就是压力工具中的线程或用户数到底是不是用来描述性能表现的?我们通过一个示意图来说明:
![](https://static001.geekbang.org/resource/image/08/3c/0814da6123f7a7fefedc3a24f364ac3c.jpg)
通过这个图,我们可以看到一个简单的计算逻辑:
1. 如果有10000个在线用户数同时并发度是1%那显然并发用户数就是100。
2. 如果每个线程的20TPS显然只需要5个线程就够了请注意这里说的线程指的是压力机的线程数
3. 这时对Server来说它处理的就是100TPS平均响应时间是50ms。50ms就是根据1000ms/20TPS得来的请注意这里说的平均响应时间会在一个区间内浮动但只要TPS不变这个平均响应时间就不会变
4. 如果我们有两个Server线程来处理那么一个线程就是50TPS这个很直接吧。
5. 请大家注意,这里我有一个转换的细节,那就是**并发用户数到压力机的并发线程数**。这一步,我们通常怎么做呢?就是基准测试的第一步。关于这一点,我们在后续的场景中交待。
而我们通常说的“并发”这个词依赖TPS来承载的时候指的都是Server端的处理能力并不是压力工具上的并发线程数。在上面的例子中我们说的并发就是指服务器上100TPS的处理能力而不是指5个压力机的并发线程数。**请你切记这一点,以免沟通障碍**。
在我带过的所有项目中,这都是一个沟通的前提。
所以,我一直在强调一点,这是一个基础的知识:**不要在意你用的是什么压力工具,只要在意你服务端的处理能力就可以了**。
## 示例
上面说了这么多,我们现在来看一个实例。这个例子很简单,就是:
JMeter1个线程 - Nginx - Tomcat - MySQL
通过上面的逻辑我们先来看看JMeter的处理情况
```
summary + 5922 in 00:00:30 = 197.4/s Avg: 4 Min: 0 Max: 26 Err: 0 (0.00%) Active: 1 Started: 1 Finished: 0
summary = 35463 in 00:03:05 = 192.0/s Avg: 5 Min: 0 Max: 147 Err: 0 (0.00%)
summary + 5922 in 00:00:30 = 197.5/s Avg: 4 Min: 0 Max: 24 Err: 0 (0.00%) Active: 1 Started: 1 Finished: 0
summary = 41385 in 00:03:35 = 192.8/s Avg: 5 Min: 0 Max: 147 Err: 0 (0.00%)
summary + 5808 in 00:00:30 = 193.6/s Avg: 5 Min: 0 Max: 25 Err: 0 (0.00%) Active: 1 Started: 1 Finished: 0
summary = 47193 in 00:04:05 = 192.9/s Avg: 5 Min: 0 Max: 147 Err: 0 (0.00%)
```
我们可以看到JMeter的平均响应时间基本都在5ms因为只有一个压力机线程所以它的TPS应该接近1000ms/5ms=200TPS。从测试结果上来看也确实是接近的。有人说为什么会少一点因为这里算的是平均数并且这个数据是30s刷新一次用30秒的时间内完成的事务数除以30s得到的但是如果事务还没有完成就不会计算在内了同时如果在这段时间内有一两个时间长的事务也会拉低TPS。
那么对于服务端呢,我们来看看服务端线程的工作情况。
![](https://static001.geekbang.org/resource/image/bd/55/bdce20f34b2e0689c21977859f54e155.png)
可以看到在服务端我开了5个线程但是服务端并没有一直干活只有一个在干活的其他的都处于空闲状态。
这是一种很合理的状态。但是你需要注意的是,这种合理的状态并不一定是对的性能状态。
1. 并发用户数TPS是193.6TPS。如果并发度为5%在线用户数就是193.6/5%=3872。
2. 响应时间是5ms。
3. 压力机并发线程数是1。这一条我们通常也不对非专业人士描述只要性能测试工程师自己知道就可以了。
下面我们换一下场景在压力机上启动10个线程。结果如下
```
summary + 11742 in 00:00:30 = 391.3/s Avg: 25 Min: 0 Max: 335 Err: 0 (0.00%) Active: 10 Started: 10 Finished: 0
summary = 55761 in 00:02:24 = 386.6/s Avg: 25 Min: 0 Max: 346 Err: 0 (0.00%)
summary + 11924 in 00:00:30 = 397.5/s Avg: 25 Min: 0 Max: 80 Err: 0 (0.00%) Active: 10 Started: 10 Finished: 0
summary = 67685 in 00:02:54 = 388.5/s Avg: 25 Min: 0 Max: 346 Err: 0 (0.00%)
summary + 11884 in 00:00:30 = 396.2/s Avg: 25 Min: 0 Max: 240 Err: 0 (0.00%) Active: 10 Started: 10 Finished: 0
summary = 79569 in 00:03:24 = 389.6/s Avg: 25 Min: 0 Max: 346 Err: 0 (0.00%)
```
平均响应时间在25ms我们来计算一处(1000ms/25ms)\*10=400TPS而最新刷出来的一条是396.2,是不是非常合理?
再回来看看服务端的线程:
![](https://static001.geekbang.org/resource/image/59/90/596564dd3186769bdf546bfdc5bdae90.png)
同样是5个线程现在就忙了很多。
1. 并发用户数TPS是396.2TPS。如果并发度为5%在线用户数就是396.2/5%=7924。
2. 响应时间是25ms。
3. 压力机并发线程数是10。这一条我们通常也不对非专业人士描述只要性能测试工程师自己知道就可以了。
如果要有公式的话,这个计算公式将非常简单:
$TPS = \\frac{1000ms}{响应时间(单位ms)}\*压力机线程数$
我不打算再将此公式复杂化,所以就不再用字母替代了。
这就是我经常提到的,**对于压力工具来说只要不报错我们就关心TPS和响应时间就可以了因为TPS反应出来的是和服务器对应的处理能力至少压力线程数是多少并不关键**。我想这时会有人能想起来JMeter的BIO和AIO之争吧。
你也许会说这个我理解了服务端有多少个线程就可以支持多少个压力机上的并发线程。但是这取决于TPS有多少如果服务端处理的快那压力机的并发线程就可以更多一些。
这个逻辑看似很合理,但是通常服务端都是有业务逻辑的,既然有业务逻辑,显然不会比压力机快。
应该说,服务端需要更多的线程来处理压力机线程发过来的请求。所以我们用几台压力机就可以压几十台服务端的性能了。
如果在一个微服务的系统中,因为每个服务都只做一件事情,拆分得很细,我们要注意整个系统的容量水位,而不是看某一个服务的能力,这就是拉平整个系统的容量。
我曾经看一个人做压力的时候压力工具中要使用4000个线程结果给服务端的Tomcat上也配置了4000个线程结果Tomcat一启动稍微有点访问CS就特别高结果导致请求没处理多少自己倒浪费了不少CPU。
## 总结
通过示意图和示例我描述了在线用户数、并发用户数、TPS这里我们假设了一个用户只对应一个事务、响应时间之间的关系。有几点需要强调
1. 通常所说的并发都是指服务端的并发,而不是指压力机上的并发线程数,因为服务端的并发才是服务器的处理能力。
2. 性能中常说的并发是用TPS这样的概念来承载具体数值的。
3. 压力工具中的线程数、响应时间和TPS之间是有对应关系的。
这里既没有复杂的逻辑,也没有复杂的公式。希望你在性能项目中,能简化概念,注重实用性。
## 思考题
如果你吸收了今天的内容,不妨思考一下这几个问题:
如何理解“服务端的并发能力”这一描述我为什么不提倡使用“绝对并发”和“相对并发”的概念呢以及我们为什么不推荐用CPU来计算并发数