Linux内核CPU使用偏高排查
·
问题
- 内核cpu使用过高
观测
- top查看负载。系统中断si和系统内核sy占用cpu偏高
top - 13:23:41 up 225 days, 9:53, 2 users, load average: 2.80, 3.06, 2.39
Tasks: 211 total, 1 running, 210 sleeping, 0 stopped, 0 zombie
%Cpu(s): 23.4 us, 10.6 sy, 0.0 ni, 56.5 id, 0.1 wa, 0.0 hi, 9.4 si, 0.0 st
KiB Mem : 8008660 total, 203620 free, 1213136 used, 6591904 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 6367804 avail Mem
- iostat 查看磁盘io情况,正常
avg-cpu: %user %nice %system %iowait %steal %idle
23.08 0.00 18.61 0.25 0.00 58.06
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 0.00 13.00 0.00 12.00 0.00 2756.00 459.33 0.07 5.83 0.00 5.83 1.00 1.20
- vmstat -w 1 10 查看总体资源。中断in和上下文切换cs偏高。一般而言应该是I/O调用导致的频繁上下文切换,此服务器是处理业务的,存在大量的网络调用
$ vmstat -w 1 10
procs -----------------------memory---------------------- ---swap-- -----io---- -system-- --------cpu--------
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 0 206204 313168 6278648 0 0 0 455 0 0 13 11 76 0 0
1 0 0 206784 313168 6278648 0 0 0 2756 40875 33178 24 19 57 0 0
3 0 0 206080 313168 6278648 0 0 0 2852 39429 32818 20 19 61 0 0
0 0 0 206852 313168 6278648 0 0 0 2756 40426 32924 24 22 53 0 0
0 0 0 205656 313168 6278648 0 0 0 2756 40709 33823 23 18 58 0 0
1 0 0 202956 313168 6278648 0 0 0 2764 43104 35866 24 19 56 0 0
1 0 0 205952 313168 6278652 0 0 0 2756 41111 34041 23 18 59 0 0
1 0 0 203988 313168 6278652 0 0 0 2832 38512 32345 21 18 61 0 0
2 0 0 204532 313168 6278652 0 0 0 2756 41736 35027 23 20 57 0 0
0 0 0 206172 313168 6278652 0 0 0 2864 41838 34968 22 19 59 0 0
- 查看网络层协议调用情况。nginx和php-fpm之间的交互是采用AF_UNIX域的,剩下的AF_INET为网络访问,这个比较多
bpftrace sofamily.bt
@accept[nginx, 2, AF_INET]: 116
@accept[php-fpm, 1, AF_UNIX]: 10493
@connect[CmsGoAgent.linu, 2, AF_INET]: 6
@connect[php-fpm, 0, AF_UNSPEC]: 8
@connect[php-fpm, 10, AF_INET6]: 8
@connect[php-fpm, 1, AF_UNIX]: 190
@connect[nginx, 1, AF_UNIX]: 10574
@connect[php-fpm, 2, AF_INET]: 48323
- 采用bpf工具
- 查看传输层协议情况。
- UDP使用较多,服务器没有使用UDP端口的自研应用,那么一般而言就是DNS服务了
bpftrace soprotocol.bt @connect[systemd-cgroups, 0, IPPROTO_IP, UNIX]: 2 @connect[CmsGoAgent.linu, 0, IPPROTO_IP, UNIX]: 3 @connect[dbus-daemon, 0, IPPROTO_IP, UNIX]: 4 @connect[aliyun-service, 6, IPPROTO_TCP, TCP]: 7 @connect[ps, 0, IPPROTO_IP, UNIX]: 8 @connect[CmsGoAgent.linu, 6, IPPROTO_TCP, TCP]: 10 @connect[crond, 0, IPPROTO_IP, UNIX]: 10 @connect[aliyun-service, 17, IPPROTO_UDP, UDP]: 12 @connect[CmsGoAgent.linu, 17, IPPROTO_UDP, UDP]: 20 @connect[php-fpm, 17, IPPROTO_UDP, UDPv6]: 95 @connect[nginx, 6, IPPROTO_TCP, TCP]: 717 @connect[nginx, 0, IPPROTO_IP, UNIX]: 42835 @connect[php-fpm, 0, IPPROTO_IP, UNIX]: 43514 @connect[php-fpm, 6, IPPROTO_TCP, TCP]: 66381 @connect[php-fpm, 17, IPPROTO_UDP, UDP]: 127774 tcpdump 抓包查看UDP的报文。显示主要为mysql和redis的dns解析,但是redis采用的是长连接,不应该有这么多,redis由多台,但是只有一台频繁解析,这很疑惑
# 53为dns端口
tcpdump -c 100000 port 53 > tcpdump.out
# head tcpdump.out
13:10:54.525159 IP server001.40657 > 100.100.2.136.domain: 49971+ A? mysql.test001.com. (61)
13:10:54.525248 IP 100.100.2.136.domain > server001.40657: 49971* 1/0/0 A 172.17.191.188 (77)
13:10:54.525301 IP server001.58239 > 100.100.2.136.domain: 41535+ AAAA? mysql.test001.com. (61)
# cat tcpdump.out|awk '{print $8,$9}'|sort |uniq -c|sort -rn
36020 mysql.test001.com. (61)
24197 (140)
18010 A 172.17.191.188
6430 mysql.test002. (61)
5938 redis.test001. (61)
3215 A 172.17.191.191
2969 A 172.17.191.192
1486 es.test001. (68)
743 A 172.17.142.150
- 排查代码发现只有一处采用了短连接,但是那是专供脚本使用的,采用单例,如果有大量的dns解析,那么应该每台redis服务器的DNS解析都会不少。改为长连接,上线测试了一下,redis的DNS解析没有降低,不是代码的问题,还原代码。
采用tcpdump抓包redis 解析很多的服务器内容看看效果。先找到ip,抓指定ip的包,看到了PHPREDIS_SESSION,这就不奇怪了,phpsession使用redis存储的(dns解析最多的那台redis服务器),是短连接,所以会有大量的dns解析查询。
# grep -B3 'redis.test001' tcpdump.out|head -10
...
13:10:54.535689 IP server001.40281 > 100.100.2.136.domain: 59941+ A? redis.test001. (61)
13:10:54.535805 IP 100.100.2.136.domain > server001.40281: 59941* 1/0/0 A 172.17.191.192 (77)
...
tcpdump -c 100 dst host 172.17.191.192 and port 6379 -xx
...
14:03:10.361710 IP server001.57342 > 172.17.191.192.6379: Flags [P.], seq 37:100, ack 6, win 229, length 63: RESP "GET" "PHPREDIS_SESSION:k3cr2f5mooqsddd9vlbj6pqv2e"
对于Mysql的解析很多,这是框架的问题,首先mysql采用的短连接,而且每一次建立请求的时候都会建立Mysql连接,但是数据其实从redis缓存就获取到了。解决办法是修改mysql连接机制,还是使用短连接,但是MySQL建立需要在要查询SQL时才建立,而不是每一个获取数据都建立MySQL连接,因为很多请求其实数据直接来源于redis。- 减少无效TCP连接建立,也就减少了一部分的系统调用,从而降低负载。
- 把mysql的无效连接取消后,中断和进程上下文切换有所下降20%,CPU变化不是特别明显,load有所下降,3.5->2.5
小包请求问题
- 问题是由于大量的小数据包导致的内核CPU消耗,系统存在大量的redis请求,网络包很小,例如统计信息等。
解决办法就是减少小包获取,尽量合并请求,一次获取多条数据。 - 负载均衡服务器每个包大小在1000B以上,而work1的包大小在200B左右,内核消耗明显是work1偏高。



openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐
所有评论(0)