极客时间已完结课程限时免费阅读

18丨CentOS:操作系统级监控及常用计数器解析(下)

18丨CentOS:操作系统级监控及常用计数器解析(下)-极客时间

18丨CentOS:操作系统级监控及常用计数器解析(下)

讲述:高楼

时长22:40大小20.70M

在上一篇文章中,我们已经讲了监控系统层面的分析思路以及 CPU 分析,今天我们分析一下操作系统中其他的层面。
首先是 I/O。

I/O

I/O 其实是挺复杂的一个逻辑,但我们今天只说在做性能分析的时候,应该如何定位问题。
对性能优化比较有经验的人(或者说见过世面比较多的人)都会知道,当一个系统调到非常精致的程度时,基本上会卡在两个环节上,对计算密集型的应用来说,会卡在 CPU 上;对 I/O 密集型的应用来说,瓶颈会卡在 I/O 上。
我们对 I/O 的判断逻辑关系是什么呢?
我们先画一个 I/O 基本的逻辑过程。我们很多人嘴上说 I/O,其实脑子里想的都是 Disk I/O,但实际上一个数据要想写到磁盘当中,没那么容易,步骤并不简单。
这个简化的图是思虑再三的结果。
I/O 有很多原理细节,那我们如何能快速地做出相应的判断呢?首先要祭出的一个工具就是iostat
在这张图中,我们取出一条数据来做详细看下:
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz
vda 0.00 0.67 18.33 114.33 540.00 54073.33 823.32
avgqu-sz await r_await w_await svctm %util
127.01 776.75 1.76 901.01 7.54 100.00
我解释一下其中几个关键计数器的含义。
svctm代表 I/O 平均响应时间。请注意,这个计数器,有很多人还把它当个宝一样,实际上在 man 手册中已经明确说了:“Warning! Do not trust this field any more. This field will be removed in a future sysstat version.” 也就是说,这个数据你爱看就爱,不一定准。
w_await表示写入的平均响应时间;r_await表示读取的平均响应时间;r/s表示每秒读取次数;w/s表示每秒写入次数。
而 IO/s 的关键计算是这样的:
IO/s = r/s + w/s = 18.33+114.33 = 132.66
%util = ( (IO/s * svctm) /1000) * 100% = 100.02564%
这个%util是用svctm算来的,既然svctm都不一定准了,那这个值也只能参考了。还好我们还有其他工具可以接着往深了去定位,那就是iotop
Total DISK READ : 2.27 M/s | Total DISK WRITE : 574.86 M/s
Actual DISK READ: 3.86 M/s | Actual DISK WRITE: 34.13 M/s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
394 be/3 root 0.00 B/s 441.15 M/s 0.00 % 85.47 % [jbd2/vda1-8]
32616 be/4 root 1984.69 K/s 3.40 K/s 0.00 % 42.89 % kube-controllers
13787 be/4 root 0.00 B/s 0.00 B/s 0.00 % 35.41 % [kworker/u4:1]
...............................
从上面的Total DISK WRITE/READ就可以知道当前的读写到底有多少了,默认是按照I/O列来排序的,这里有Total,也有Actual,并且这两个并不相等,为什么呢?
因为 Total 的值显示的是用户态进程与内核态进程之间的速度,而 Actual 显示的是内核块设备子系统与硬件之间的速度。
而在I/O交互中,由于存在cache和在内核中会做I/O排序,因此这两个值并不会相同。那如果你要说磁盘的读写能力怎么样,我们应该看的是Actual。这个没啥好说的,因为Total再大,不能真实写到硬盘上也是没用的。
在下面的线程列表中,通过排序,就可以知道是哪个线程(注意在第一列是 TID 哦)占的I/O高了。

Memory

关于内存,要说操作系统的内存管理,那大概开一个新专栏也不为过。但是在性能测试的项目中,如果不做底层的测试,基本上在上层语言开发的系统中,比如说 Java、Go、C++ 等,在分析过程中都直接看业务系统就好了。
在操作系统中,分析业务应用的时候,我们会关注的内存内容如下面的命令所示:
[root@7dgroup ~]# free -m
total used free shared buff/cache available
Mem: 3791 1873 421 174 1495 1512
Swap: 0 0 0
[root@7dgroup ~]#
total肯定是要优先看的,其次是available,这个值才是系统真正可用的内存,而不是free
因为 Linux 通常都会把用的内存给cache,但是不一定会用,所以free肯定会越来越少,但是available是计算了buffcache中不用的内存的,所以只要available多,就表示内存够用。
当出现内存泄露或因其他原因导致物理内存不够用的时候,操作系统就会调用OOM Killer,这个进程会强制杀死消耗内存大的应用。这个过程是不商量的,然后你在“dmesg”中就会看到如下信息。
[12766211.187745] Out of memory: Kill process 32188 (java) score 177 or sacrifice child
[12766211.190964] Killed process 32188 (java) total-vm:5861784kB, anon-rss:1416044kB, file-rss:0kB, shmem-rss:0kB
这种情况只要出现,TPS 肯定会掉下来,如果你有负载均衡的话,压力工具中的事务还是可能有成功的。但如果你只有一个应用节点,或者所有应用节点都被OOM Killer给干掉了,那 TPS 就会是这样的结果。
对内存监控,可以看到这样的趋势:
内存慢慢被耗光,但是杀掉应用进程之后,free内存立即就有了。你看上面这个图,就是一个机器上有两个节点,先被杀了一个,另一个接着泄露,又把内存耗光了,于是又被杀掉,最后内存全都空闲了。
在我的性能工作生涯中,这样的例子还挺常见。当然对这种情况的分析定位,只看物理内存已经没有意义了,更重要的是看应用的内存是如何被消耗光的。
对于内存的分析,你还可以用nmoncat/proc/meminfo看到更多信息。如果你的应用是需要大页处理的,特别是大数据类的应用,需要关注下HugePages相关的计数器。
内存我们就说到这里,总之,要关注available内存的值。

NetWork

这里我们就来到了网络分析的部分了,在说握手之前,我们先看网络的分析决策链。
请看上图中,在判断了瓶颈在网络上之后,如果知道某个进程的网络流量大,首先肯定是要考虑减少流量,当然要在保证业务正常运行,TPS 也不降低的情况下。

Recv_Q 和 Send_Q

当然我们还要干一件事,就是可能你并不知道是在哪个具体的环节上出了问题,那就要学会判断了。网络I/O栈也并不简单,看下图:
数据发送过程是这样的。
应用把数据给到tcp_wmem就结束它的工作了,由内核接过来之后,经过传输层,再经过队列、环形缓冲区,最后通过网卡发出去。
数据接收过程则是这样的。
网卡把数据接过来,经过队列、环形缓冲区,再经过传输层,最后通过tcp_rmem给到应用。
你似乎懂了对不对?那么在这个过程中,我们有什么需要关注的呢?
首先肯定是看队列,通过netstat或其他命令可以看到Recv_QSend_Q,这两项至少可以告诉你瓶颈会在哪一端。如下图所示:
我画个表清晰地判断一下瓶颈点。
其实这个过程中,我还没有把防火墙加进去,甚至我都没说NAT的逻辑,这些基础知识你需要自己先做足功课。
在我们做性能分析的过程中,基本上,基于上面这个表格就够通过接收和发送判断瓶颈点发生在谁身上了。
但是,要是这些队列都没有值,是不是网络就算好了呢?还不是。

三次握手和四次挥手

我们先看握手图:
我发现一点,很多人以为三次握手是非常容易理解的,但是没几个人能判断出和它相关的问题。
握手的过程,我就不说了,主要看这里面的两个队列:半连接队列和全连接队列。
在 B 只接到第一个syn包的时候,把这个连接放到半连接队列中,当接到ack的时候才放到全连接队列中。这两个队列如果有问题,都到不了发送接收数据的时候,你就看到报错了。
查看半连接全连接溢出的手段也很简单,像下面这种情况就是半连接没建立起来,半连接队列满了,syn包都被扔掉了。
[root@7dgroup ~]# netstat -s |grep -i listen
8866 SYNs to LISTEN sockets dropped
那么半连接队列和什么参数有关呢?
代码中的backlog:你是不是想起来了ServerSocket(int port, int backlog)中的backlog?是的,它就是半连接的队列长度,如果它不够了,就会丢掉syn包了。
还有操作系统的内核参数net.ipv4.tcp_max_syn_backlog
而像下面这样的情况呢,就是全连接队列已经满了,但是还有连接要进来,已经超过负荷了。
[root@7dgroup2 ~]# netstat -s |grep overflow
154864 times the listen queue of a socket overflowed
这是在性能分析过程中经常遇到的连接出各种错的原因之一,它和哪些参数有关呢?我列在这里。
net.core.somaxconn:系统中每一个端口最大的监听队列的长度。
net.core.netdev_max_backlog:每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。
open_file:文件句柄数。
我们再来看下四次挥手。我遇到性能测试过程中的挥手问题,有很多都是做性能分析的人在不了解的情况下就去做各种优化动作而产生的。
先看一下 TCP 挥手图:
在挥手的逻辑中,和性能相关的问题真的非常少。
但有一个点是经常会问到的,那就是TIME_WAIT。不知道为什么,很多人看到TIME_WAIT就紧张,就想去处理掉,于是搜索一圈,哦,要改recycle/reuse的 TCP 参数,要改fin_time_out值。
至于为什么要处理TIME_WAIT,却没几个人能回答得上来。
在我的性能工作经验中,只有一种情况要处理TIME_WAIT,那就是端口不够用的时候。
TCP/IPv4的标准中,端口最大是 65535,还有一些被用了的,所以当我们做压力测试的时候,有些应用由于响应时间非常快,端口就会不够用,这时我们去处理TIME_WAIT的端口,让它复用或尽快释放掉,以支持更多的压力。
所以处理TIME_WAIT的端口要先判断清楚,如果是其他原因导致的,即使你处理了TIME_WAIT,也没有提升性能的希望。
如果还有人说,还有一种情况,就是内存不够用。我必须得说,那是我没见过世面了,我至今没见过因为TIME_WAIT的连接数把内存耗光了的。
一个 TCP 连接大概占 3KB,创建 10 万个连接,才100000x3KB≈300M左右,服务器有那么穷吗?

System

确切地说,在性能测试分析的领域里,System 似乎实在是没有什么可写的地方。
我们最常见的 System 的计数器是in(interrupts:中断)cs(context switch:上下文切换)
因为这是我能找得到的最疯狂的 System 计数器了。
中断的逻辑在前面跟你说过了。
cs也比较容易理解,就是 CPU 不得不转到另一件事情上,听这一句你就会知道,中断时肯定会有cs。但是不止中断会引起 cs,还有多任务处理也会导致cs
因为cs是被动的,这个值的高和低都不会是问题的原因,只会是一种表现,所以它只能用来做性能分析中的证据数据。
在我们的这个图中,显然是由于in引起的cs,CPU 队列那么高也是由in导致的。像这样的问题,你可以去看我们在上篇文章中提到的si CPU高的那个分析链了。

Swap

Swap 的逻辑是什么呢?它是在磁盘上创建的一个空间,当物理内存不够的时候,可以保存物理内存里的数据。如下图所示:
先看和它相关的几个参数。
在操作系统中,vm.swappiness 是用来定义使用 swap 的倾向性。官方说明如下:
swappiness
This control is used to define how aggressive the kernel will swap memory pages. Higher values will increase agressiveness, lower values decrease the amount of swap.
A value of 0 instructs the kernel not to initiate swap until the amount of free and file-backed pages is less than the high water mark in a zone.
The default value is 60.
值越高,则使用 swap 的倾向性越大。
值越低,则使用 swap 的倾向性越小。
但这个倾向性是谁跟谁比呢?简单地说,在内存中有 anon 内存 (匿名而链表,分为:inactive/active) 和 file 内存 (映射页链表,也分为:inactive/active),而 swappiness 是定义了对 anon 页链表扫描的倾向性。在 Linux 源码 vmscan.c 中有这样的定义:
/*
* With swappiness at 100, anonymous and file have the same priority.
* This scanning priority is essentially the inverse of IO cost.
*/
anon_prio = swappiness;
file_prio = 200 - anon_prio;
也就是说如果 swappiness 设置为 100 时,则 anon 和 file 内存会同等的扫描;如果设置为 0 时,则 file 内存扫描的优先级会高。但是这并不是说设置为了 0 就没有 swap 了,在操作系统中还有其他的逻辑使用 swap。
swapiness默认是 60%。注意,下面还有一个参数叫vm.min_free_kbytes。即使把vm.swappiness改为 0,当内存用到小于vm.min_free_kbytes时照样会发生 Swap。
想关掉 Swap 就swapoff -a
和 Swap 相关的计数器有:top中的Totalfreeusedvmstat里的siso
说到 Swap,在性能测试和分析中,我的建议是直接把它关了。
为什么呢?因为当物理内存不足的时候,不管怎么交换性能都是会下降的,不管是 Swap 还是磁盘上的其他空间,都是从磁盘上取数据,性能肯定会刷刷往下掉。

总结

对操作系统的监控及常用计数器的分析会涉及到很多的内容,所以两篇文章可能也是覆盖不全的,我只把在性能测试分析工作中经常见到的计数器解析了一遍。总体来说,你需要记住以下三点:
监控平台再花哨,都只是提供数据来给你分析的。只要知道了数据的来源、原理、含义,用什么工具都不重要。
性能分析的时候,不会只看操作系统一个模块或哪几个固定计数器的。这些动态的数据,需要有分析链把它们串起来。
操作系统提供的监控数据是分析链路中不可缺少的一环,除非你能绕过操作系统,又能很确切地定位出根本原因。

思考题

我为什么说用什么监控平台并不重要呢?
欢迎你在评论区写下你的思考,也欢迎把这篇文章分享给你的朋友或者同事,一起交流进步。
分享给需要的人,Ta购买本课程,你将得18
生成海报并分享

赞 5

提建议

上一篇
17丨CentOS:操作系统级监控及常用计数器解析(上)
下一篇
19丨Java & C ++:代码级监控及常用计数器解析(上)
unpreview
 写留言

精选留言(23)

  • 罗辑思维
    2020-04-05
    当操作系统中配置了vm.swappiness是 30%,那么当内存用到1-30%=70%的时候,就会发生 Swap。 高老师,文中对swappiness参数设置值描述跟倪鹏飞老师在专栏讲解有不一样的地方。个人还是认同swappiness不是内存的百分比。下面这段是摘自是倪鹏飞老师《Linux性能分析实战》第19讲。 --------------------------- /proc/sys/vm/swappiness 选项,用来调整使用 Swap 的积极程度。 swappiness 的范围是 0-100,数值越大,越积极使用 Swap,也就是更倾向于回收匿名页;数值越小,越消极使用 Swap,也就是更倾向于回收文件页。 虽然 swappiness 的范围是 0-100,不过要注意,这并不是内存的百分比,而是调整 Swap 积极程度的权重,即使你把它设置成 0,当剩余内存 + 文件页小于页高阈值时,还是会发生 Swap。
    展开

    作者回复: 仔细检查了一下。这个直接说是内存的百分比,确实不够精确。我之前看到过一些文章应该就是直接写的内存使用率百分比。 多谢指正,可以联系我,拿200块钱红包。 在这里更正如下: 在操作系统中,vm.swappiness是用来定义使用swap的倾向性。官方说明如下: swappiness This control is used to define how aggressive the kernel will swap memory pages. Higher values will increase agressiveness, lower values decrease the amount of swap. A value of 0 instructs the kernel not to initiate swap until the amount of free and file-backed pages is less than the high water mark in a zone. The default value is 60. 1. 值越高,则使用swap的倾向性越大。 2. 值越低,则使用swap的倾向性越小。 但这个倾向性是谁跟谁比呢?简单地说,在内存中有anon内存(匿名而链表,分为:inactive/active)和file内存(映射页链表,也分为:inactive/active),而swappiness是定义了对anon页链表扫描的倾向性。在linux源码vmscan.c中有这样的定义: /* * With swappiness at 100, anonymous and file have the same priority. * This scanning priority is essentially the inverse of IO cost. */ anon_prio = swappiness; file_prio = 200 - anon_prio; 也就是说如果swappiness设置为100时,则anon和file内存会同等的扫描;如果设置为0时,则file内存扫描的优先级会高。但是这并不是说设置为了0就没有swap了,在操作系统中还有其他的逻辑使用swap。 以后我会找个时间专门写一下这个逻辑。这里面涉及到几个部分的源代码逻辑,还是有点小复杂。

    共 2 条评论
    19
  • 木剑温华
    2021-08-31
    一个 TCP 连接大概占 3KB,创建 10 万个连接,才100000x3KB≈300M左右,何况最多才 65535 呢?服务器有那么穷吗? 这里感觉老师说的有一点问题,一个tcp链接由四元组组成:sip:sport---cip:cport,单机最多65535个端口,但是可以根据公式可以看到只影响了sport的数量,但是cip和cport的组合是无穷尽的,所以单机理论最大连接数远大于65535,我之前在iot项目和消息推送项目做过相关的压测,成功地把单机最大长连接数提高到100w以上。
    展开

    作者回复: 这里的描述有问题。我修改一下。 对客户端来说,会受到65535的端口数限制,对服务端来说不受端口数限制。

    7
  • SeaYang
    2020-10-27
    使用Linux服务器作为压力机,TPS达到比较高的时候压力机会大量报无法分配请求地址的错误,从而导致TPS直接降为0,命令看了下TIME_WAIT的数量很多,调整了一下几个内核参数,就解决了

    作者回复: 一看就是高手。

    3
  • 月亮和六便士
    2020-03-27
    高老师,看完您的课程,有一些思路了,但是我发现思路和实战之间有一道鸿沟,我已经掉到沟里了,比如 分析的起点拆分响应时间,但是不知道怎么拆分,开发更是一头雾水。应用又是部署在docker里面,好不容易配置了个Tomcat监控,结果重启了一下配置又没了,运维说docker里没法暴露监控端口,真是寸步难行啊

    作者回复: 你这个是管理和沟通的问题,和技术无关。docker里当然可以暴露监控端口。 即使不这样,也得有其他的监控docker的手段。 技术角度来说,没有收拾不了的系统。

    3
  • aoe
    2020-10-14
    老师硬核调优!测试、开发、运维后期在操作系统、网络上都这么强了!

    作者回复: 性能是一个工程,从前到后。在我的思路中,不受职位限制。只看要达到的目标。哈哈。

    2
  • 黑脸龙猫酱
    2020-03-16
    老师可否说下对于云服务器,io有些时间段不稳定的情况应该如何处理?

    作者回复: 云服务器都是虚拟机,如果你是被无良厂商超卖的话,那只能去骂街了。

    2
  • 悦霖
    2020-02-18
    高老师问一下,每次性能测试看io较高基本都是jbd2这个进程占用大量的IO,怎么进一步分析,而且这个jdb2是个啥?

    作者回复: 后面文章里会写到它。

    2
  • David.cui
    2020-12-03
    高老师讲的还是很透彻的,能分析到非常细微的差别。 高手!

    作者回复: 只有落地才是正道。

    1
  • 小老鼠
    2020-02-18
    由于上下文切换过多引起性能降低的情形多吗?

    作者回复: 在我的工作经验中,上下文切换的问题排不到前五名。但是前十名还是有可能的。

    1
  • jy
    2022-10-21 来自江苏
    老师,请教一个问题, 文中:"在我们做性能分析的过程中,基本上,基于上面这个表格就够通过接收和发送判断瓶颈点发生在谁身上了" 感觉这里没说完整呢 比如发送端Send_Q有值,接收端Recv_Q也有值,说明瓶颈点在接收端,那下一步如何分析接收端呢? 比如发送端Send_Q有值,接收端Recv_Q没有值,说明瓶颈点在发送端或者网络设备,这种情况,那下一步又该如何分析发送端呢? 谢谢老师指导。
    展开

    作者回复: 这里只是写判断过程,具体的问题还要有相应的数据才能明确。

  • Fzz
    2022-06-13
    老师你好,想问下系统tps到顶,系统CPU只有20%,系统相响应时间1秒以下,感觉压力发起端也没有瓶颈,想问下这个瓶颈在哪?看了资源的使用也不高,不知道是不是jvm或者应用的的问题?

    作者回复: 你这个问题就比较大了。我需要看到具体的架构,跟着REASR性能分析七步法走一遍才能知道。

    共 2 条评论
  • 学员141
    2021-07-10
    在测试环境压测,发现服务器端口占满了,服务器的端口配置是否需要修改?网上说过大又容易被攻击(我们是docker,一个节点上部署了18个应用,节点主机16C16G,有些应用CPU和内存都分配很小,导致都到一个节点上来)

    作者回复: 没看懂这个问题。

    共 2 条评论
  • 0909
    2021-06-21
    因为数据来源都是一样的,重要的还是要根据数据去找到瓶颈和优化方案

    作者回复: 是的。

  • 闲鱼超人
    2021-02-24
    监控平台为什么不重要呢? 监控平台的主要用途是为了提供运行时状态数据给我们的,利用这些数据,我们分析性能情况。所以关键是数据、是证据链,是这些数据反馈出来的问题,这是核心。所以从这个角度来说,监控平台是不重要的,因为只要能提供这些你需要的数据,哪个平台都可以。

    作者回复: 是的。理解的很对。

  • Geek_7cf52a
    2020-07-10
    老师我之前说的端口不够用的问题我知道了,听了音频知道老师说的客户端的端口了,不是服务端的,刚开始还以为是服务端的端口

    作者回复: 多学习就会知道更多了。

  • Geek_7cf52a
    2020-07-10
    至于为什么要处理TIME_WAIT,却没几个人能回答得上来。在我的性能工作经验中,只有一种情况要处理TIME_WAIT,那就是端口不够用的时候。TCP/IPv4的标准中,端口最大是 65535,还有一些被用了的,所以当我们做压力测试的时候,有些应用由于响应时间非常快,端口就会不够用,这时我们去处理TIME_WAIT的端口,让它复用或尽快释放掉,以支持更多的压力。所以处理TIME_WAIT的端口要先判断清楚,如果是其他原因导致的,即使你处理了TIME_WAIT,也没有提升性能的希望。如果还有人说,还有一种情况,就是内存不够用。我必须得说,那是我没见过世面了,我至今没见过因为TIME_WAIT的连接数把内存耗光了的。一个 TCP 连接大概占 3KB,创建 10 万个连接,才100000x3KB≈300M左右,何况最多才 65535 呢?服务器有那么穷吗? -----来自原文 老师你好,你上面说的端口不够用的时候处理time_wait是不是有问题?应该是连接不够用才对吧?一个应用在一开始就指定了具体的tcp端口,端口是不会变的,只有连接数才会不断的增多
    展开

    作者回复: 看另一个留言,你已经自学解决了。哈哈。

  • 小呀么小二郎
    2020-04-12
    今日思考题 为什么说用什么监控平台并不重要呢? 监控平台再花哨,都只是提供数据来给性能测试人员分析的。作为性能测试人员,重点是要知道数据的来源、原理、含义。 知易行难,信息量好大。一节课够学一个月系列……
    展开

    作者回复: 不操作确实不知道有多难。但是一步步走是必须经历的过程,实在是没有什么捷径可走。最多看着别人走过的路知道是可行的。

  • 月亮和六便士
    2020-04-07
    老师,怎么查看端口够用不够用,或者说端口用了多少?Linux系统的命令是什么,window系统的命令是什么?

    作者回复: 都是netstat。

  • 蔡森冉
    2020-03-23
    平台就像是每个人用着不同品牌手机都用着差不多的功能。老师现在使用着云平台,平台上就会有一个监控模块,公司应用都是在云服务器上,那是否我只用在服务器提供商上的这个监控模块看就可以了?

    作者回复: 工具无所谓只要提供相应的计数器能看懂就可以了。

  • 小老鼠
    2020-02-18
    在固态硬盘中还存在扇区与磁道吗?

    作者回复: 不存在。