上篇文章主要是介绍《Linux高性能网络编程十谈|协程》,整理如何设计高性能网络编程,接下来的两篇文章主要介绍工具和性能问题分析的总结,有相关的问题可以在留言区留言,我将解答大家的疑问。
这是一张linux各个模块的图和对应的工具(当然这里工具比较多,本文只将讲和高性能调试和排查问题相关的工具)。
第一部分:Linux服务器参数
1、内核参数
(1)max-file-number
在linux系统中很多资源都是以文件描述符表示的,但是文件描述符并非无限的大,系统分为硬限制和软限制(软限制小于等于硬限制),如果需要修改,则通过/etc/security/limits.conf:
hard nofile max-file-number
soft nofile max-file-number
有时我们在linux编程中会碰到错误:Too many open files,这个表示某个进程打开的文件句柄超过限制,再打开文件就会报错,这就是linux对用户级限制的句柄数,查询可以通过命令ulimit -n,修改可以通过命令ulimit -SHn max-file-number。
(2)limits.conf中的其他限制
限制cpu运行时间,可以设置hard cpu 1,单位是分钟
fsize限制创建文件大小,可以设置hard fsize 100,单位是kb
(3)/proc/sys/fs/file-max
系统级的文件描述符限制,可以临时修改/proc/sys/fs/file-max的值,放开限制。
(4)/proc/sys/fs/epoll/max_user_watches
epoll内核事件表中注册事件的总量,这里包含用户打开的所有epoll实例总共能监听的事件数目。
2、网络参数
(1)/proc/sys/net/core/somaxconn
指定listen监听队列中,能够建立完整连接的从而进入ESTABLISHD状态的socket最大数目。
(2)/proc/sys/net/ipv4/tcp_max_syn_backlog
指定listen监听队列中,能够建立完整连接的从而进入ESTABLISHD或者SYNC_RCVD状态的socket最大数目。
(3)/proc/sys/net/ipv4/tcp_wmem和/proc/sys/net/ipv4/tcp_rmem
- /proc/sys/net/ipv4/tcp_wmem指定socket的TCP写缓冲最大值,默认值和最小值
- /proc/sys/net/ipv4/tcp_rmem指定socket的TCP读缓冲最大值,默认值和最小值
(4)/proc/sys/net/ipv4/tcp_syncookies
是否打开TCP的同步标签,tcp_syncookies目的是解决一个监听socket因不停的重复收到来自同一个地址的连接请求,而导致listen监听队列的溢出。
以上永久生效的生效方式是修改或者添加选项到/etc/synctl.conf,然后执行sysctl -p。
第二部分:分析工具
测试程序,以下命令依赖的本代码作为样例
#include <iostream>
#include <cmath>
using namespace std;
void for_loop()
{
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 10000; j++) {
int x = sin(i) + cos(j);
}
}
}
void loop1()
{
for (int i = 0; i < 10; i++) {
for_loop();
}
}
void loop2()
{
for (int i = 0; i < 100; i++) {
for_loop();
}
}
int main()
{
loop1();
loop2();
return 0;
}
// 编译方式 g++ -g test.cc
1、gdb
gdb是程序员必备的调试工具,网上资料比较多我就不详细介绍,这里几个常用的调试方式:
gdb [options][执行文件 core文件|进程PID]
$ (gdb) info all-reg # 显示所有处理器寄存器的内容,包括浮点和向量寄存器
$ (gdb) list filename:line_number # 显示源代码,并以指定的行作为中心
$ (gdb) break [filename:] line_number # 在(指定文件或当前文件)指定行设置断点
$ (gdb) continue / c [passes] # 继续执行到下一个断点,passes表示忽略几次中断
$ (gdb) step / s [lines] # 执行多少行后再次被中断,如果遇到函数,将会进入函数,并在函数第一行停下来
$ (gdb) next / n [lines] # 执行多少行后再次被中断,不会进入函数
$ (gdb) frame [number] # 显示当前栈帧,或者选择不同的栈帧
$ (gdb) info locals # 当前栈帧的局部变量
$ (gdb) info args # 列出对应函数调用的参数值
$ (gdb) bt # 打印堆栈信息
...
# 调试多进程程序,允许在执行fork以后继续调试父进程还是子进程
$ (gdb) set follow-fork-mode mode(parent|child)
# 调试多线程程序常用命令
$ (gdb) info threads # 打印线程信息
$ (gdb) thread 线程ID # 切换线程ID
$ (gdb) set scheduler-locking (off|on|step) # 当前调试程序是否锁定线程
与gdp配套的还有两个工具是gstack和gcore,gstack是查看进程堆栈信息,gcore是将进程堆栈转存,然后使用gdb调试。
样例:
(1)常用调试,命令gdb ./a.out,输出如下:
[root@VM-16-16-centos ~]# gdb ./a.out
GNU gdb (GDB) Red Hat Enterprise Linux 8.2-16.el8
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...done.
(gdb) list
16 for (int i = 0; i < 10; i++) {
17 for_loop();
18 }
19 }
20
21 void loop2()
22 {
23 for (int i = 0; i < 100; i++) {
24 for_loop();
25 }
(2)用命令gstack 进程号查看堆栈,然后gcore 进程号转存数据,最后用gdb调试,输出如下:
[root@VM-16-16-centos ~]# gstack 365609
#0 0x00007f7ceef9bb55 in __sin_fma () from /lib64/libm.so.6
#1 0x0000000000400875 in std::sin<int> (__x=862) at /usr/include/c++/8/cmath:438
#2 0x0000000000400788 in for_loop () at test.cc:9
#3 0x00000000004007ef in loop2 () at test.cc:24
#4 0x0000000000400806 in main () at test.cc:31
[root@VM-16-16-centos ~]# gcore -p 365609
usage: gcore [-a] [-o filename] pid
[root@VM-16-16-centos ~]# gcore 365609
0x00007f7ceef9b602 in __sin_fma () from /lib64/libm.so.6
Saved corefile core.365609
[Inferior 1 (process 365609) detached]
# 其中转存文件为core.365609
[root@VM-16-16-centos ~]# gdb ./a.out ./core.365609
GNU gdb (GDB) Red Hat Enterprise Linux 8.2-16.el8
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...done.
[New LWP 365609]
Core was generated by `./a.out'.
#0 0x00007f7ceef9b602 in __sin_fma () from /lib64/libm.so.6
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-151.el8.x86_64 libgcc-8.5.0-4.el8_5.x86_64 libstdc++-8.5.0-4.el8_5.x86_64
(gdb) bt full
#0 0x00007f7ceef9b602 in __sin_fma () from /lib64/libm.so.6
No symbol table info available.
#1 0x0000000000400875 in std::sin<int> (__x=12) at /usr/include/c++/8/cmath:438
No locals.
#2 0x0000000000400788 in for_loop () at test.cc:9
x = -1
j = 5327
i = 12
#3 0x00000000004007ef in loop2 () at test.cc:24
i = 69
#4 0x0000000000400806 in main () at test.cc:31
No locals.
(gdb) frame 1
#1 0x0000000000400875 in std::sin<int> (__x=12) at /usr/include/c++/8/cmath:438
438 { return __builtin_sin(__x); }
(gdb) info args
__x = 12
2、tcpdump
tcpdump是一款经典的网络抓包工具,也是linux下必备调试网络工具,其中tcpdump使用参数:
tcpdump [-adeflnNOpqStvx][-c 数量][-F 文件名][-i 网络接口][-r 文件名][-s snaplen][-T 类型][-w 文件名] [表达式]
样例:
(1)常用抓包命令
tcpdump tcp -i eth1 -t -s 0 -c 100 and dst port ! 22 and src net 192.168.1.0/24 -w ./target.cap
参数解释:
tcp: ip icmp arp rarp 和 tcp、udp、icmp这些选项等都要放到第一个参数的位置,用来过滤数据报的类型
-i eth1:只抓经过接口eth1的包
-t:不显示时间戳
-s 0:抓取数据包时默认抓取长度为68字节,加上`-S 0`后可以抓到完整的数据包
-c 100:只抓取100个数据包
dst port ! 22:不抓取目标端口是22的数据包
src net 192.168.1.0/24:数据包的源网络地址为192.168.1.0/24
-w ./target.cap:保存成cap文件,方便用wireshark分析
(2)执行命令tcpdump -i any -AAA -c 3,输出如下:
[root@VM-16-16-centos ~]# tcpdump -i any -AAA -c 3
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes
15:53:30.817134 IP VM-16-16-centos.ssh > 113.104.215.65.rrirtr: Flags [P.], seq 2416982452:2416982672, ack 3565832082, win 314, options [nop,nop,TS val 856138616 ecr 1045200609], length 220
......RT........EH....@.@.......qh.A......9...G....:7......
3..x>L~.$H.#..a.*.~..g.VG.n..k......8V`=_.2+Es+.'.,..AH.lEWmQ......Cm.]H......./...[`rh>J..d.N.....H.i.)....W.|'.......-...l.ie*1C....|. zv.....8 ..YO3..;..N+..I..../8e|,.P........xM......V....n.GGa...[y....J.R...........e......
15:53:30.817331 IP VM-16-16-centos.55721 > 183.60.82.98.domain: 41825+ PTR? 65.215.104.113.in-addr.arpa. (45)
......RT........E..I".@.@.RY.....<Rb...5.5...a...........65.215.104.113.in-addr.arpa.....
15:53:30.840249 IP 113.104.215.65.rrirtr > VM-16-16-centos.ssh: Flags [.], ack 0, win 2047, options [nop,nop,TS val 1045200644 ecr 856138605], length 0
........"$.'....E..4..@...zNqh.A..........G...9............
>L..3..m
3 packets captured
11 packets received by filter
2 packets dropped by kernel
3、lsof
lsof是列出当前系统或者进程打开文件描述符的工具,其中使用方式:
lsof -i [46] [protocol][@hostname|ipaddr]:[service|port] // 显示当前端口或者ip占用的句柄列表
lsof -c [进程名] // 显示当前进程名打开的句柄列表
lsof -p [进程id] // 显示当前进程id打开的句柄列表
lsof -t [文件名] // 显示打开当前文件的进程id
样例:
(1)执行lsof -i:22,查看22端口占用句柄,输出如下:
[root@VM-16-16-centos ~]# lsof -i:22
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 1167 root 5u IPv4 21933 0t0 TCP *:ssh (LISTEN)
sshd 1167 root 6u IPv6 21935 0t0 TCP *:ssh (LISTEN)
sshd 39808 root 5u IPv4 372839047 0t0 TCP VM-16-16-centos:ssh->59.37.124.125:32754 (ESTABLISHED)
sshd 39821 root 5u IPv4 372839047 0t0 TCP VM-16-16-centos:ssh->59.37.124.125:32754 (ESTABLISHED)
(2)执行lsof -p 58582,查看进程占用句柄,输出如下:
[root@VM-16-16-centos ~]# lsof -p 58582
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
a.out 58582 root cwd DIR 253,1 4096 393219 /root
a.out 58582 root rtd DIR 253,1 4096 2 /
a.out 58582 root txt REG 253,1 18240 394769 /root/a.out
a.out 58582 root mem REG 253,1 3167976 268071 /usr/lib64/libc-2.28.so
a.out 58582 root mem REG 253,1 99672 262185 /usr/lib64/libgcc_s-8-20210514.so.1
a.out 58582 root mem REG 253,1 2191840 280386 /usr/lib64/libm-2.28.so
a.out 58582 root mem REG 253,1 1660936 269721 /usr/lib64/libstdc++.so.6.0.25
a.out 58582 root mem REG 253,1 278504 268057 /usr/lib64/ld-2.28.so
a.out 58582 root 0u CHR 136,0 0t0 3 /dev/pts/0
a.out 58582 root 1u CHR 136,0 0t0 3 /dev/pts/0
a.out 58582 root 2u CHR 136,0 0t0 3 /dev/pts/0
4、nc
nc是瑞士军刀,主要用来快速建立连接,使用方式:
nc [-hlnruz][-g<网关...>][-G<指向器数目>][-i<延迟秒数>][-o<输出文件>][-p<通信端口>][-s<来源位址>][-v...][-w<超时秒数>][主机名称][通信端口...]
-g<网关> 设置路由器跃程通信网关,最多可设置8个
-G<指向器数目> 设置来源路由指向器,其数值为4的倍数
-h 在线帮助
-i<延迟秒数> 设置时间间隔,以便传送信息及扫描通信端口
-l 使用监听模式,管控传入的资料
-n 直接使用IP地址,而不通过域名服务器
-o<输出文件> 指定文件名称,把往来传输的数据以16进制字码倾倒成该文件保存
-p<通信端口> 设置本地主机使用的通信端口
-r 乱数指定本地与远端主机的通信端口
-s<来源位址> 设置本地主机送出数据包的IP地址
-u 使用UDP传输协议
-v 显示指令执行过程
-w<超时秒数> 设置等待连线的时间
-z 使用0输入/输出模式,只在扫描通信端口时使用
样例:
(1)web服务器
# 1. 启动server端,while :; do (echo -ne "HTTP/1.1 200 OK\r\nhello world")|nc -l -p 8000; done
# 2. 启动client端,echo "GET / HTTP/1.0\r\n\r\n" | nc 127.0.0.1 8000,输出如下:
[root@VM-16-16-centos ~]# echo "GET / HTTP/1.0\r\n\r\n" | nc 127.0.0.1 8000
HTTP/1.1 200 OK
hello world
(2)远程控制
# 正向控制,被控端主动设置监听端口及bash环境,控制端连接
# 被控制端执行下面的命令:
nc -lvnp 8888 -c bash
# 控制端执行下面的命令(可以输入ls命令,就能获取返回):
nc 127.0.0.1 8888
5、strace
strace是测试服务性能的重要工具,它可以跟踪程序运行过程中执行的系统调用和接收信号等,使用方式:
strace [-cdfrt][-e trace=all|file|process|network|signal|ipc...][-p 进程号]
-c 统计每一系统调用的所执行的时间,次数和出错的次数等
-d 输出strace关于标准错误的调试信息
-f 跟踪由fork调用所产生的子进程
-F 尝试跟踪vfork调用,在-f时,vfork不被跟踪
-a 设置返回值的输出位置
-r 打印出相对时间关于每一个系统调用
-t 在输出中的每一行前加上时间信息(方便查看调用事件)
-T 显示每一调用所耗的时间(可以分析系统调用函数情况)
-x 以十六进制形式输出非标准字符串
-xx 所有字符串以十六进制形式输出
-p 跟踪指定进程
其中:
-e expr指定一个表达式,格式[qualifier=][!]value1[,value2]...,但是只能是(trace,abbrev,verbose,raw,signal,read,write)之一,以trace跟踪格式为例,如下样例:
-e trace=set 跟踪指定的系统调用,例如:-e trace=open,close,rean,write表示只跟踪这四个系统调用,默认的为set=all
-e trace=file 跟踪有关文件操作的系统调用
-e trace=process 跟踪有关进程控制的系统调用
-e trace=network 跟踪与网络有关的所有系统调用
-e trace=signal 跟踪所有与系统信号有关的系统调用
-e trace=ipc 跟踪所有与进程通讯有关的系统调用
-e trace=all 两个特殊的符号all和none,all表示跟踪所有的set,none表示不跟踪
样例:
(1)跟踪上面的nc命令,执行nc -lvnp 8888 -c bash,输出如下:
[root@VM-16-16-centos ~]# strace -e trace=network nc -lvnp 8888 -c bash
Ncat: Version 7.70 ( http://www.zzvips.com/uploads/allimg/k1nx3rkiqgq )
socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP) = 3
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
setsockopt(3, SOL_IPV6, IPV6_V6ONLY, [1], 4) = 0
bind(3, {sa_family=AF_INET6, sin6_port=htons(8888), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "::", &sin6_addr), sin6_scope_id=0}, 28) = 0
listen(3, 10) = 0
Ncat: Listening on :::8888
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 4
setsockopt(4, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
bind(4, {sa_family=AF_INET, sin_port=htons(8888), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(4, 10) = 0
Ncat: Listening on 0.0.0.0:8888
accept(4, {sa_family=AF_INET, sin_port=htons(55084), sin_addr=inet_addr("127.0.0.1")}, [128->16]) = 5
Ncat: Connection from 127.0.0.1.
Ncat: Connection from 127.0.0.1:55084.
recvfrom(5, "ls\n", 8192, 0, NULL, NULL) = 3
sendto(5, "a.out\ntest.cc\n", 14, 0, NULL, 0) = 14
(2)统计系统调用时间
[root@VM-16-16-centos ~]# strace -c ./a.out
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
27.95 0.000135 9 14 mmap
24.43 0.000118 11 10 mprotect
13.46 0.000065 7 9 read
8.28 0.000040 8 5 close
8.28 0.000040 8 5 openat
6.21 0.000030 6 5 fstat
6.21 0.000030 6 5 lseek
3.11 0.000015 15 1 munmap
2.07 0.000010 5 2 1 arch_prctl
0.00 0.000000 0 3 brk
0.00 0.000000 0 1 1 access
0.00 0.000000 0 1 execve
------ ----------- ----------- --------- --------- ----------------
100.00 0.000483 7 61 2 total
6、netstat
nestat是功能很强大的网络信息统计工具,经常在网络问题排查中使用,选项包括:
netstat [-natrisop][-c 采样间隔(s)]
-n 显示IP地址和端口号
-a 显示结果中包含监听的socket
-t 只显示TCP连接信息
-u 只显示UDP连接信息
-r 显示路由信息
-i 显示网卡的数据流量
-o 显示socket定时器信息
-p 显示socket所属进程PID和名字
-s 显示ICMP,TCP,UDP等socket的系统信息
样例:
(1)显示TCP,UDP和进程信息,命令netstat -tunp,输出如下:
[root@VM-16-16-centos ~]# netstat -tunp
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 216 172.27.16.16:22 113.104.215.65:4034 ESTABLISHED 299304/sshd: root [
tcp 0 84 172.27.16.16:22 34.105.249.210:42030 ESTABLISHED 300012/sshd: root [
tcp 0 0 172.27.16.16:60822 169.254.0.3:80 TIME_WAIT -
tcp 0 0 172.27.16.16:22 113.104.215.65:1890 ESTABLISHED 281372/sshd: root [
tcp 0 0 172.27.16.16:60824 169.254.0.3:80 TIME_WAIT -
tcp 0 0 172.27.16.16:43802 169.254.0.55:5574 ESTABLISHED 3974640/YDService
tcp 0 389 172.27.16.16:22 34.105.249.210:55280 LAST_ACK -
tcp 0 0 172.27.16.16:60828 169.254.0.3:80 TIME_WAIT -
tcp 0 84 172.27.16.16:22 146.190.222.176:33062 ESTABLISHED 300017/sshd: unknow
tcp 0 0 172.27.16.16:60826 169.254.0.3:80 TIME_WAIT -
tcp 0 0 172.27.16.16:45878 169.254.0.138:8186 ESTABLISHED 214251/tat_agent
tcp 0 0 172.27.16.16:22 113.104.215.65:4443 ESTABLISHED 270055/sshd: root [
tcp 0 0 172.27.16.16:22 113.104.215.65:2186 ESTABLISHED 285317/sshd: root [
tcp 0 0 172.27.16.16:43800 169.254.0.55:5574 ESTABLISHED 3974640/YDService
udp 0 0 172.27.16.16:68 172.27.16.1:67 ESTABLISHED 989/NetworkManager
其中一些输出信息简单解释:
- Proto:协议信息,包括TCP和UDP
- Recv-Q:如果TCP连接状态处于Established,Recv-Q的数值表示接收缓冲区中还没拷贝到应用层的数据大小,如果 TCP 连接状态处于Listen状态,Recv-Q的数值表示当前全连接队列的大小
- Send-Q:表示发送缓冲区中已发送但未被确认的数据大小(不管TCP是Listen状态还是Established状态都表示这个意思)
- State:链路状态,包括LISTEN,SYN_SENT,SYN_RECV,ESTABLISHED,TIME-WAIT,UNKNOWN,FIN-WAIT-1,FIN-WAIT-2,CLOSE-WAIT,CLOSE-WAIT等
- PID:进程信息,这里包含进程名(通过-p参数输出的)
(2)显示socket当前的统计信息,命令netstat -s,输出如下:
[root@VM-16-16-centos ~]# netstat -s
IcmpMsg:
InType0: 37
InType3: 6665
InType5: 550
InType8: 11338192
InType11: 109
InType13: 3
OutType0: 11338192
OutType3: 205969
OutType14: 3
Tcp:
7023585 active connection openings
1100446 passive connection openings
30871 failed connection attempts
224072 connection resets received
8 connections established
68401617 segments received
67268650 segments sent out
330444 segments retransmitted
2734 bad segments received
5638980 resets sent
InCsumErrors: 2721
Udp:
4351700 packets received
450350 packets to unknown port received
145 packet receive errors
4374307 packets sent
0 receive buffer errors
0 send buffer errors
InCsumErrors: 145
UdpLite:
TcpExt:
604 SYN cookies sent
1874 SYN cookies received
129 invalid SYN cookies received
30846 resets received for embryonic SYN_RECV sockets
4 ICMP packets dropped because they were out-of-window
285778 TCP sockets finished time wait in fast timer
964 packets rejected in established connections because of timestamp
2382994 delayed acks sent
...
其中一些输出信息简单解释(可以基于TcpExt一些信息分析当前网络状况,从而快速排查问题):
- active connection openings:表示主动发起TCP连接的次数
- passive connection openings:表示被动接受TCP连接的次数
- failed connection attempts:表示TCP连接失败的次数
- connection resets received:表示TCP连接被重置的次数
- connections established:表示当前已经建立的TCP连接数
- segments received:表示接收到的TCP数据包的数量
- segments sent out:表示发送的TCP数据包的数量
- segments retransmitted:表示重传的TCP数据包的数量
- InCsumErrors:表示接收到的TCP数据包错误的数量
7、vmstat
vmstat是输出各个资源使用情况的工具,如进程,内存,CPU使用率等信息,选项包括:
vmstat [-fsdp][-S k|K|m|M][interval采样间隔(s)][count采样次数]
-f 显示系统启动执行以来的fork次数
-s 显示内存统计信息和活动统计信息,包括fork次数
-d 显示磁盘统计信息
样例:
(1)显示常用统计信息(间隔2s,并执行两次输出),命令vmstat 2 2,输出如下:
[root@VM-16-16-centos ~]# vmstat 2 2
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 298404 96824 1189732 0 0 1 34 1 0 0 0 99 0 0
0 0 0 298284 96824 1189736 0 0 0 214 760 1315 1 0 99 1 0
其中一些输出信息简单解释:
- procs进程信息,r是等待运行的进程数,b是不可中断的睡眠状态的进程数
- memory内存信息,swpd是swap内存数,free是空间内存,buff一些系统buff或者io缓存的中间内存,cache是未写入磁盘内存
- swap:交换分区当前信息
- io:块设备当前信息
- system:CPU在内核态运行信息,包括in中断次数,cs上下文切换次数
- cpu:CPU使用信息,和后面mpstat命令输出类似
(2)显示系统活动数量统计,命令vmstat -s,输出如下:
[root@VM-16-16-centos ~]# vmstat -s
1860492 K total memory
274936 K used memory
701576 K active memory
707432 K inactive memory
299040 K free memory
96824 K buffer memory
1189692 K swap cache
0 K total swap
0 K used swap
0 K free swap
12318019 non-nice user cpu ticks
124590 nice user cpu ticks
11848347 system cpu ticks
2844992141 idle cpu ticks
4677889 IO-wait cpu ticks
0 IRQ cpu ticks
208152 softirq cpu ticks
0 stolen cpu ticks
15879112 pages paged in
985253486 pages paged out
0 pages swapped in
0 pages swapped out
1330511648 interrupts
260667271 CPU context switches
1678004734 boot time
58996940 forks
8、ifstat
ifstat是简单的网络流量检测工具,选项包括:
ifstat [-atb][-i 网卡][interval采样间隔(s)][count采样次数]
-a 监听所有网卡接口
-t 每行输出时间信息
-b 以Kbit/s为单位显示
-i 监听指定的网卡接口
样例:
(1)监听所有网卡的流量情况,命令ifstat -a,输出如下:
[root@VM-16-16-centos ~]# ifstat -a
#kernel
Interface RX Pkts/Rate TX Pkts/Rate RX Data/Rate TX Data/Rate
RX Errs/Drop TX Errs/Drop RX Over/Rate TX Coll/Rate
lo 1228 0 1228 0 147340 0 147340 0
0 0 0 0 0 0 0 0
eth0 88238K 0 83403K 0 1934M 0 1021M 0
0 0 0 0 0 0 0 0
9、mpstat
mpstat是查看每个CPU的使用情况,使用命令:
mpstat [-P|ALL][interval采样间隔(s)][count采样次数]
样例:
(1)监听CPU的使用情况,命令mpstat -P ALL 5 2,输出如下:
[root@VM-16-16-centos ~]# mpstat -P ALL 5 2
Linux 4.18.0-348.7.1.el8_5.x86_64 (VM-16-16-centos) 2023年08月19日 _x86_64_ (2 CPU)
10时02分15秒 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
10时02分20秒 all 0.70 0.00 0.80 0.50 0.00 0.00 0.00 0.00 0.00 98.00
10时02分20秒 0 0.60 0.00 0.80 0.20 0.00 0.00 0.00 0.00 0.00 98.40
10时02分20秒 1 0.80 0.00 0.80 0.80 0.00 0.00 0.00 0.00 0.00 97.60
10时02分20秒 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
10时02分25秒 all 0.50 0.00 0.30 0.00 0.00 0.00 0.00 0.00 0.00 99.20
10时02分25秒 0 0.40 0.00 0.40 0.00 0.00 0.00 0.00 0.00 0.00 99.20
10时02分25秒 1 0.60 0.00 0.20 0.00 0.00 0.00 0.00 0.00 0.00 99.20
平均时间: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
平均时间: all 0.60 0.00 0.55 0.25 0.00 0.00 0.00 0.00 0.00 98.60
平均时间: 0 0.50 0.00 0.60 0.10 0.00 0.00 0.00 0.00 0.00 98.80
平均时间: 1 0.70 0.00 0.50 0.40 0.00 0.00 0.00 0.00 0.00 98.40
其中一些输出信息简单解释:
- %usr:除了nice为负的进程,系统上其他进程在用户空间的CPU运行时间占比
- %nice:nice为负的进程在用户空间的CPU运行时间占比
- %sys:系统上所有进程在内核空间的CPU运行时间占比,但不包括硬中断和软中断所耗的CPU时间
- %iowait:CPU等待磁盘操作的时间占比
- %irq:CPU处理硬中断的时间占比
- %soft:CPU处理软中断的时间占比
- %steal:虚拟CPU等待时间占比
- %guest:虚拟CPU运行时间占比
- %idle:系统空间时间占比
10、perf
perf是linux的一款性能分析工具,能够进行函数级和指令级的热点查找,可以用来分析程序中热点函数的CPU占用率,从而定位性能瓶颈,使用命令:
perf [top|stat][record][report][-e 事件名称][-p 进程ID]
-e 指定关注的事件,比如查看造成cache miss最多的函数排行:
perf top -e cache-misses
perf top -e task-clock
perf top -G // 得到调用关系图
perf top-e cache-misses -G // 得到调用关系图
perf top -e cycles // 指定性能事件
perf top -p 23015,32476 //查看这两个进程的cpu cycles使用情况
perf top -s comm,pid,symbol // 显示调用symbol的进程名和进程号
perf top --comms nginx,top // 仅显示属于指定进程的符号
perf top --symbols kfree // 仅显示指定的符号
样例:
(1)统计某个进程调用函数情况,命令perf top -p 368721,输出如下:
39.66% libm-2.28.so [.] __cos_fma
35.17% libm-2.28.so [.] __sin_fma
10.88% a.out [.] for_loop
6.84% a.out [.] std::cos<int>
6.43% a.out [.] std::sin<int>
0.96% a.out [.] sin@plt
0.03% a.out [.] cos@plt
0.01% [kernel] [k] _raw_spin_unlock_irqrestore
0.01% [kernel] [k] __softirqentry_text_start
0.00% [kernel] [k] tcp_v4_rcv
0.00% [kernel] [k] __inet_lookup_established
0.00% [kernel] [k] packet_rcv
0.00% [kernel] [k] update_io_ticks
0.00% [kernel] [k] _raw_spin_trylock
0.00% [kernel] [k] mod_objcg_state
11、http压测工具
这里介绍压测工具http_bench,是HTTP(HTTP/1, HTTP/2, HTTP/3, Websocket)压测工具,并支持单机和分布式,使用命令:
-n 请求HTTP的次数
-c 并发的客户端数量,但是不能大于HTTP的请求次数
-q 频率限制,每秒的请求数
-d 压测持续时间,默认10秒,例如:2s, 2m, 2h(s:秒,m:分钟,h:小时)
-t 设置请求的超时时间,默认3s
-o 输出结果格式,可以为CSV,也可以直接打印
-m HTTP方法,包括GET, POST, PUT, DELETE, HEAD, OPTIONS.
-H 请求发起的HTTP的头部信息,例如:-H "Accept: text/html" -H "Content-Type: application/xml"
-body HTTP发起POST请求的body数据
-a HTTP的鉴权请求, 例如:http://username:password@xxx/
-http 支持http1, http2, http3, ws和wss, 默认http1
-x HTTP的代理IP和端口
-disable-compression 不启用压缩
-disable-keepalive 不开启keepalive
-cpus 使用cpu的内核数
-url 压测单个URL
-verbose 打印详细日志,默认等级:3(0:TRACE, 1:DEBUG, 2:INFO, 3:ERROR)
-url-file 读取文件中的URL,格式为一行一个URL,发起请求每次随机选择发送的URL
-body-file 从文件中读取请求的body数据
-listen 分布式压测任务机器监听IP:PORT,例如: "127.0.0.1:12710".
-dashboard 监听端口,浏览器发起压测和查看QPS曲线.
-W 分布式压测执行任务的机器列表,例如: -W "127.0.0.1:12710" -W "127.0.0.1:12711".
-example 打印样例信息.
样例
./http_bench http://127.0.0.1:8000 -c 1000 -d 60s
Running 1000 connections, @ http://127.0.0.1:8000
Summary:
Total: 63.031 secs
Slowest: 0.640 secs
Fastest: 0.000 secs
Average: 0.072 secs
Requests/sec: 12132.423
Total data: 8.237 GB
Size/request: 11566 bytes
Status code distribution:
[200] 764713 responses
Latency distribution:
10% in 0.014 secs
25% in 0.030 secs
50% in 0.060 secs
75% in 0.097 secs
90% in 0.149 secs
95% in 0.181 secs
99% in 0.262 secs