问题
观测
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
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解析查询。
.. .
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偏高。