今天我们来看一个真实的案例。事情是这样的,之前有人在微信上问我一个问题,这个问题的现象很典型:典型的 TPS 上不去,响应时间增加,资源用不上。
大概的情况是这样的:有两台 4C8G 的服务器,一台服务器上有 2 个 Tomcat,一台服务器上是 DB。压测的混合场景有 4 个功能模块,其中 3 个访问一个 Tomcat,另外一个访问一个 Tomcat。
Tomcat 的监控页面如下:
应用服务器系统资源监控页面如下:
数据库服务器系统资源监控如下:
JMeter 结果如下:
综上现象就是,单业务场景执行起来并不慢,但是一混合起来就很慢,应用服务器和数据库服务器的系统资源使用率并不高。请问慢在哪?
这是非常典型的询问性能问题的方式,虽然多给了系统资源信息,但是这些信息也不足以说明瓶颈在哪。
为什么呢?在现在多如牛毛的监控工具中,除非我们在系统中提前做好分析算法或警告,否则不会有监控工具主动告诉你, 监控出的某个数据有问题,而这个只能靠做性能分析的人来判断。
我在很多场合听一些“专家”说:性能分析判断要遵守木桶原理。但是在做具体技术分析的时候,又不给人说明白木桶的短板在哪里。这就好像,一个赛车手说要是有一个各方面都好的车,我肯定能得第一名,但是,我没有车。
话说出来轻而易举,但是请问木桶的短板怎么判断呢?因为 CPU 高,所以 CPU 就是短板吗?所以就要加 CPU 吗?这肯定是不对的。
因为这个例子并不大,所以可以细细地写下去。今天文章的目的就是要告诉你,性能问题分析到底应该是个什么分析思路。
分析的第一阶段
画架构图
做性能测试时,我们需要先画一个架构图,虽然简单,但是让自己脑子里时时记得架构图,是非常有必要的。因为架构级的分析,就是要胸怀架构,在看到一个问题点时,可以从架构图中立即反应出来问题的相关性。
上面这张图是自己脑子里的逻辑图,数据在网络中的流转并不是这样,而是像下图这样。
数据流是从压力机到应用服务器,应用服务器再到网络设备,再到数据库服务器;数据库把数据返回给应用服务器,应用服务器再通过网络设备给压力机。
如果把里面的 Redis、ActiveMQ 和 MySQL 的逻辑再细说明白,那么这个小小的应用都可以描述好一会。所以这里,我先大概描述一下,如果后面的分析中涉及到了相应的逻辑,再一点点加进来。
应用服务器只有一台,上面有两个 Tomcat 实例;数据库服务器有三个应用。混合场景中有四个业务,其中三个访问 Tomcat1,第四个访问 Tomcat2。
场景描述
有了场景大概的画像之后,我们再来看场景。根据测试工程师描述:
响应时间慢的,都是可视化页面,有不少图片、JS、CSS 等静态资源。公网上是用 CDN 的,现在只测试内网的部分。静态资源已经做了压缩。
单业务测试的容量是可以满足要求的,但混合场景响应时间就长。系统资源用得并不多。
压力场景是 300 线程,Ramp-up period 是 1 秒。
Duration 是 72000。
各参数化都已经做了,参数化数据也合理。
测试环境都是内网。
服务器是 CentOS,压力机是 Win10。
既然这样,我们还是要看看系统的各个资源,再来判断方向。我在很多场合都强调证据链。对架构比较简单的应用来说,我们都不用再做时间的拆分了,直接到各主机上看看资源就好了。
瓶颈分析定位
根据我们之前画的架构图,我们从应用服务器、数据库服务器和压力数据分别定位一下。
应用服务器
从前面的应用服务器资源来看,CPU 使用率现在还不高,也基本都在 us CPU(就是 user 消耗的 CPU)上,比例也比较合理。
物理内存 8G,还有 3.5G。即使不多,对 Java 应用来说,也要先看 JVM,只要不是 page fault 过多,我们可以先不用管物理内存。
网络资源接收 900KB/s 左右,发送 11M 左右。这样的带宽应该说是比较敏感的,因为对 100Mbps 和 1000Mbps 来说,我们要心里有一个数,一个是 12.5MB(对应 100Mbps),一个是 125MB(对应 1000Mbps),当和这样的带宽值接近的时候,就要考虑下是不是带宽导致的压力上不去。不过这里我们也不用先下定论。只是留个疑问在这里。
磁盘资源,基本上没有读写,很正常。
从 Process 列表中,也没看到什么异常数据。faults 也都是 min,major fault 并没有。但在这个案例中,还部署了另一个监控工具,上面显示如下:
为什么这个 Swapping 要标黄呢?那肯定是过大了嘛。是的,你可以觉得 swap 过多。这个扣,我们也记在心里。在这里标红加粗敲黑板!
数据库服务器
照样分析,CPU、内存、网络、磁盘、Process 列表,并没看到哪里有异常的数据,连网络都只有 500 多 k 的发送。
这样的数据库资源状态告诉我们,它不在我们的问题分析主线上。接下来是压力数据。
压力数据
这是 JMeter 中的聚合报告:
从上面这张图也能看出,响应时间确实挺长的,并且,300 线程只有 37 的 TPS,带宽总量 10M 左右。这个带宽倒是和应用服务器上的带宽使用量相当。关于这个带宽的判断请你一定注意,对于性能分析来说,带宽能不能对得上非常重要。比如,客户端接收了多少流量,服务端就应该是发出了多少流量。如果服务端发了很多包,但是客户端没有接收,那就是堵在队列上了。
既然其它的资源暂时没出现什么瓶颈。其实在这个时间里,如果是复杂的应用的话,我们最应该干的一件事情就是拆分时间。如下图所示:
这里我把时间拆为 t1-t5,具体分析哪一段为什么消耗了时间。我们可以在 Tomcat 中加上 %D 和 %F 两个参数来记录 request 和 response 的时间。
在没有做这个动作之前,我们先把前面的扣解决一下。首先,带宽是不是受了 100Mbps 的限制?
一般来说,判断网络的时候,我们会有几个判断点。
首先是带宽的流量大小,也就是前面我们看到的 11M 左右的值。一般来说,100Mbps 是指的 bit per second,但是在应用层基本上都是 byte,所以对 100Mbps 来说,是 12.5MB。
其次是,全连接和半连接队列是否已经溢出?
我们通过 SYNs to LISTEN sockets dropped 来判断半连接队列是否溢出,通过 times the listen queue of a socket overflowed 来判断全连接队列是否溢出。
通过实时的查看,这两个值的增加并不多。所以这里不会是问题点。
最后是发送和接收队列是否堆积?
通过应用服务器上的 send-Q(前面数第三列),可以看到服务器和压力机之间的的队列还是很长的,基本上每次查看都存在,这说明队列一直都有堆积。
我们再到压力机上看看带宽用了多少:
看这里也是用到了 93Mbps,那么到这里我们就可以确定是网络问题导致的 TPS 上不去,响应时间增加,系统资源也用不上了。
和系统管理员确认宿主机的带宽后,被告知宿主机确实是 100Mbps。
似乎这个分析到这里就可以结束了,直接把带宽加上再接着测试呗。但是,从项目实施的角度上说,这个问题,并不是阻塞性的。
为了把更多的性能问题提前找出来,现在我们先不下载静态资源,只发接口请求找下其他性能问题。这个带宽的问题,记一个 bug 就行了。
优化结果
我们将静态资源全都过滤掉之后,再次执行场景,结果是下面这样的。
JMeter 压力数据:
应用服务器带宽:
数据库服务器带宽:
应用服务器网络队列:
应用服务器资源监控:
通过上面的结果可以看出:
TPS 可以达到 221.5 了,并且 Received 和 Sent 的字节加一起不到 4MB。
应用服务器和数据库服务器的带宽都用到了近 40Mbps,和 JMeter 结果也相当。
应用服务器上的网络队列也没有堆积。
应用服务器的 CPU 也已经能消耗到 66% 了,
当正在想通过过滤掉静态资源绕过带宽不足的现状来测试其他性能问题的时候,这时,Swap 双向都标黄了。这时,性能测试工程师更纠结了,它为什么双向都黄了?CPU 使用率才 66% 嘛。
其实,这两句话之间并没有什么关系,CPU 使用率不管是多少,Swap 该黄还是会黄。
这是为什么呢?这里卖个关子,在下一篇文章中,我们接着分析。
总结
带宽问题是性能分析中常见的问题之一,其难点就在于,带宽不像 CPU 使用率那么清晰可理解,它和 TCP/IP 协议的很多细节有关,像三次握手,四次挥手,队列长度,网络抖动、丢包、延时等等,都会影响性能,关键是这些判断点还不在同一个界面中,所以需要做分析的人有非常明确的分析思路才可以做得到。而且现在的监控分析工具中,对网络的判断也是非常薄弱的。
而 Swap 问题不能算是常见,只要出现,基本上就会很多人晕乎。解决的关键就是要明白 Swap 的原理,查到关联参数,然后就可以很快地定位了。