Linux高性能網(wǎng)絡(luò)編程十談 | 工具篇
上篇文章主要是介紹《Linux高性能網(wǎng)絡(luò)編程十談|協(xié)程》,整理如何設(shè)計(jì)高性能網(wǎng)絡(luò)編程,接下來的兩篇文章主要介紹工具和性能問題分析的總結(jié),有相關(guān)的問題可以在留言區(qū)留言,我將解答大家的疑問。
這是一張linux各個(gè)模塊的圖和對(duì)應(yīng)的工具(當(dāng)然這里工具比較多,本文只將講和高性能調(diào)試和排查問題相關(guān)的工具)。
第一部分:Linux服務(wù)器參數(shù)
1、內(nèi)核參數(shù)
(1)max-file-number
在linux系統(tǒng)中很多資源都是以文件描述符表示的,但是文件描述符并非無限的大,系統(tǒng)分為硬限制和軟限制(軟限制小于等于硬限制),如果需要修改,則通過/etc/security/limits.conf:
hard nofile max-file-number
soft nofile max-file-number
有時(shí)我們?cè)趌inux編程中會(huì)碰到錯(cuò)誤:Too many open files,這個(gè)表示某個(gè)進(jìn)程打開的文件句柄超過限制,再打開文件就會(huì)報(bào)錯(cuò),這就是linux對(duì)用戶級(jí)限制的句柄數(shù),查詢可以通過命令ulimit -n,修改可以通過命令ulimit -SHn max-file-number。
(2)limits.conf中的其他限制
限制cpu運(yùn)行時(shí)間,可以設(shè)置hard cpu 1,單位是分鐘
fsize限制創(chuàng)建文件大小,可以設(shè)置hard fsize 100,單位是kb
(3)/proc/sys/fs/file-max
系統(tǒng)級(jí)的文件描述符限制,可以臨時(shí)修改/proc/sys/fs/file-max的值,放開限制。
(4)/proc/sys/fs/epoll/max_user_watches
epoll內(nèi)核事件表中注冊(cè)事件的總量,這里包含用戶打開的所有epoll實(shí)例總共能監(jiān)聽的事件數(shù)目。
2、網(wǎng)絡(luò)參數(shù)
(1)/proc/sys/net/core/somaxconn
指定listen監(jiān)聽隊(duì)列中,能夠建立完整連接的從而進(jìn)入ESTABLISHD狀態(tài)的socket最大數(shù)目。
(2)/proc/sys/net/ipv4/tcp_max_syn_backlog
指定listen監(jiān)聽隊(duì)列中,能夠建立完整連接的從而進(jìn)入ESTABLISHD或者SYNC_RCVD狀態(tài)的socket最大數(shù)目。
(3)/proc/sys/net/ipv4/tcp_wmem和/proc/sys/net/ipv4/tcp_rmem
- /proc/sys/net/ipv4/tcp_wmem指定socket的TCP寫緩沖最大值,默認(rèn)值和最小值
- /proc/sys/net/ipv4/tcp_rmem指定socket的TCP讀緩沖最大值,默認(rèn)值和最小值
(4)/proc/sys/net/ipv4/tcp_syncookies
是否打開TCP的同步標(biāo)簽,tcp_syncookies目的是解決一個(gè)監(jiān)聽socket因不停的重復(fù)收到來自同一個(gè)地址的連接請(qǐng)求,而導(dǎo)致listen監(jiān)聽隊(duì)列的溢出。
以上永久生效的生效方式是修改或者添加選項(xiàng)到/etc/synctl.conf,然后執(zhí)行sysctl -p。
第二部分:分析工具
測(cè)試程序,以下命令依賴的本代碼作為樣例
#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是程序員必備的調(diào)試工具,網(wǎng)上資料比較多我就不詳細(xì)介紹,這里幾個(gè)常用的調(diào)試方式:
gdb [options][執(zhí)行文件 core文件|進(jìn)程PID]
$ (gdb) info all-reg # 顯示所有處理器寄存器的內(nèi)容,包括浮點(diǎn)和向量寄存器
$ (gdb) list filename:line_number # 顯示源代碼,并以指定的行作為中心
$ (gdb) break [filename:] line_number # 在(指定文件或當(dāng)前文件)指定行設(shè)置斷點(diǎn)
$ (gdb) continue / c [passes] # 繼續(xù)執(zhí)行到下一個(gè)斷點(diǎn),passes表示忽略幾次中斷
$ (gdb) step / s [lines] # 執(zhí)行多少行后再次被中斷,如果遇到函數(shù),將會(huì)進(jìn)入函數(shù),并在函數(shù)第一行停下來
$ (gdb) next / n [lines] # 執(zhí)行多少行后再次被中斷,不會(huì)進(jìn)入函數(shù)
$ (gdb) frame [number] # 顯示當(dāng)前棧幀,或者選擇不同的棧幀
$ (gdb) info locals # 當(dāng)前棧幀的局部變量
$ (gdb) info args # 列出對(duì)應(yīng)函數(shù)調(diào)用的參數(shù)值
$ (gdb) bt # 打印堆棧信息
...
# 調(diào)試多進(jìn)程程序,允許在執(zhí)行fork以后繼續(xù)調(diào)試父進(jìn)程還是子進(jìn)程
$ (gdb) set follow-fork-mode mode(parent|child)
# 調(diào)試多線程程序常用命令
$ (gdb) info threads # 打印線程信息
$ (gdb) thread 線程ID # 切換線程ID
$ (gdb) set scheduler-locking (off|on|step) # 當(dāng)前調(diào)試程序是否鎖定線程
與gdp配套的還有兩個(gè)工具是gstack和gcore,gstack是查看進(jìn)程堆棧信息,gcore是將進(jìn)程堆棧轉(zhuǎn)存,然后使用gdb調(diào)試。
樣例:
(1)常用調(diào)試,命令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 進(jìn)程號(hào)查看堆棧,然后gcore 進(jìn)程號(hào)轉(zhuǎn)存數(shù)據(jù),最后用gdb調(diào)試,輸出如下:
[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]
# 其中轉(zhuǎn)存文件為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是一款經(jīng)典的網(wǎng)絡(luò)抓包工具,也是linux下必備調(diào)試網(wǎng)絡(luò)工具,其中tcpdump使用參數(shù):
tcpdump [-adeflnNOpqStvx][-c 數(shù)量][-F 文件名][-i 網(wǎng)絡(luò)接口][-r 文件名][-s snaplen][-T 類型][-w 文件名] [表達(dá)式]
樣例:
(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
參數(shù)解釋:
tcp: ip icmp arp rarp 和 tcp、udp、icmp這些選項(xiàng)等都要放到第一個(gè)參數(shù)的位置,用來過濾數(shù)據(jù)報(bào)的類型
-i eth1:只抓經(jīng)過接口eth1的包
-t:不顯示時(shí)間戳
-s 0:抓取數(shù)據(jù)包時(shí)默認(rèn)抓取長(zhǎng)度為68字節(jié),加上`-S 0`后可以抓到完整的數(shù)據(jù)包
-c 100:只抓取100個(gè)數(shù)據(jù)包
dst port ! 22:不抓取目標(biāo)端口是22的數(shù)據(jù)包
src net 192.168.1.0/24:數(shù)據(jù)包的源網(wǎng)絡(luò)地址為192.168.1.0/24
-w ./target.cap:保存成cap文件,方便用wireshark分析
(2)執(zhí)行命令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是列出當(dāng)前系統(tǒng)或者進(jìn)程打開文件描述符的工具,其中使用方式:
lsof -i [46] [protocol][@hostname|ipaddr]:[service|port] // 顯示當(dāng)前端口或者ip占用的句柄列表
lsof -c [進(jìn)程名] // 顯示當(dāng)前進(jìn)程名打開的句柄列表
lsof -p [進(jìn)程id] // 顯示當(dāng)前進(jìn)程id打開的句柄列表
lsof -t [文件名] // 顯示打開當(dāng)前文件的進(jìn)程id
樣例:
(1)執(zhí)行l(wèi)sof -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)執(zhí)行l(wèi)sof -p 58582,查看進(jìn)程占用句柄,輸出如下:
[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<網(wǎng)關(guān)...>][-G<指向器數(shù)目>][-i<延遲秒數(shù)>][-o<輸出文件>][-p<通信端口>][-s<來源位址>][-v...][-w<超時(shí)秒數(shù)>][主機(jī)名稱][通信端口...]
-g<網(wǎng)關(guān)> 設(shè)置路由器躍程通信網(wǎng)關(guān),最多可設(shè)置8個(gè)
-G<指向器數(shù)目> 設(shè)置來源路由指向器,其數(shù)值為4的倍數(shù)
-h 在線幫助
-i<延遲秒數(shù)> 設(shè)置時(shí)間間隔,以便傳送信息及掃描通信端口
-l 使用監(jiān)聽模式,管控傳入的資料
-n 直接使用IP地址,而不通過域名服務(wù)器
-o<輸出文件> 指定文件名稱,把往來傳輸?shù)臄?shù)據(jù)以16進(jìn)制字碼傾倒成該文件保存
-p<通信端口> 設(shè)置本地主機(jī)使用的通信端口
-r 亂數(shù)指定本地與遠(yuǎn)端主機(jī)的通信端口
-s<來源位址> 設(shè)置本地主機(jī)送出數(shù)據(jù)包的IP地址
-u 使用UDP傳輸協(xié)議
-v 顯示指令執(zhí)行過程
-w<超時(shí)秒數(shù)> 設(shè)置等待連線的時(shí)間
-z 使用0輸入/輸出模式,只在掃描通信端口時(shí)使用
樣例:
(1)web服務(wù)器
# 1. 啟動(dòng)server端,while :; do (echo -ne "HTTP/1.1 200 OK\r\nhello world")|nc -l -p 8000; done
# 2. 啟動(dòng)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)遠(yuǎn)程控制
# 正向控制,被控端主動(dòng)設(shè)置監(jiān)聽端口及bash環(huán)境,控制端連接
# 被控制端執(zhí)行下面的命令:
nc -lvnp 8888 -c bash
# 控制端執(zhí)行下面的命令(可以輸入ls命令,就能獲取返回):
nc 127.0.0.1 8888
5、strace
strace是測(cè)試服務(wù)性能的重要工具,它可以跟蹤程序運(yùn)行過程中執(zhí)行的系統(tǒng)調(diào)用和接收信號(hào)等,使用方式:
strace [-cdfrt][-e trace=all|file|process|network|signal|ipc...][-p 進(jìn)程號(hào)]
-c 統(tǒng)計(jì)每一系統(tǒng)調(diào)用的所執(zhí)行的時(shí)間,次數(shù)和出錯(cuò)的次數(shù)等
-d 輸出strace關(guān)于標(biāo)準(zhǔn)錯(cuò)誤的調(diào)試信息
-f 跟蹤由fork調(diào)用所產(chǎn)生的子進(jìn)程
-F 嘗試跟蹤vfork調(diào)用,在-f時(shí),vfork不被跟蹤
-a 設(shè)置返回值的輸出位置
-r 打印出相對(duì)時(shí)間關(guān)于每一個(gè)系統(tǒng)調(diào)用
-t 在輸出中的每一行前加上時(shí)間信息(方便查看調(diào)用事件)
-T 顯示每一調(diào)用所耗的時(shí)間(可以分析系統(tǒng)調(diào)用函數(shù)情況)
-x 以十六進(jìn)制形式輸出非標(biāo)準(zhǔn)字符串
-xx 所有字符串以十六進(jìn)制形式輸出
-p 跟蹤指定進(jìn)程
其中:
-e expr指定一個(gè)表達(dá)式,格式[qualifier=][!]value1[,value2]...,但是只能是(trace,abbrev,verbose,raw,signal,read,write)之一,以trace跟蹤格式為例,如下樣例:
-e trace=set 跟蹤指定的系統(tǒng)調(diào)用,例如:-e trace=open,close,rean,write表示只跟蹤這四個(gè)系統(tǒng)調(diào)用,默認(rèn)的為set=all
-e trace=file 跟蹤有關(guān)文件操作的系統(tǒng)調(diào)用
-e trace=process 跟蹤有關(guān)進(jìn)程控制的系統(tǒng)調(diào)用
-e trace=network 跟蹤與網(wǎng)絡(luò)有關(guān)的所有系統(tǒng)調(diào)用
-e trace=signal 跟蹤所有與系統(tǒng)信號(hào)有關(guān)的系統(tǒng)調(diào)用
-e trace=ipc 跟蹤所有與進(jìn)程通訊有關(guān)的系統(tǒng)調(diào)用
-e trace=all 兩個(gè)特殊的符號(hào)all和none,all表示跟蹤所有的set,none表示不跟蹤
樣例:
(1)跟蹤上面的nc命令,執(zhí)行nc -lvnp 8888 -c bash,輸出如下:
[root@VM-16-16-centos ~]# strace -e trace=network nc -lvnp 8888 -c bash
Ncat: Version 7.70 ( https://nmap.org/ncat )
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)統(tǒng)計(jì)系統(tǒng)調(diào)用時(shí)間
[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是功能很強(qiáng)大的網(wǎng)絡(luò)信息統(tǒng)計(jì)工具,經(jīng)常在網(wǎng)絡(luò)問題排查中使用,選項(xiàng)包括:
netstat [-natrisop][-c 采樣間隔(s)]
-n 顯示IP地址和端口號(hào)
-a 顯示結(jié)果中包含監(jiān)聽的socket
-t 只顯示TCP連接信息
-u 只顯示UDP連接信息
-r 顯示路由信息
-i 顯示網(wǎng)卡的數(shù)據(jù)流量
-o 顯示socket定時(shí)器信息
-p 顯示socket所屬進(jìn)程PID和名字
-s 顯示ICMP,TCP,UDP等socket的系統(tǒng)信息
樣例:
(1)顯示TCP,UDP和進(jìn)程信息,命令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
其中一些輸出信息簡(jiǎn)單解釋:
- Proto:協(xié)議信息,包括TCP和UDP
- Recv-Q:如果TCP連接狀態(tài)處于Established,Recv-Q的數(shù)值表示接收緩沖區(qū)中還沒拷貝到應(yīng)用層的數(shù)據(jù)大小,如果 TCP 連接狀態(tài)處于Listen狀態(tài),Recv-Q的數(shù)值表示當(dāng)前全連接隊(duì)列的大小
- Send-Q:表示發(fā)送緩沖區(qū)中已發(fā)送但未被確認(rèn)的數(shù)據(jù)大小(不管TCP是Listen狀態(tài)還是Established狀態(tài)都表示這個(gè)意思)
- State:鏈路狀態(tài),包括LISTEN,SYN_SENT,SYN_RECV,ESTABLISHED,TIME-WAIT,UNKNOWN,F(xiàn)IN-WAIT-1,F(xiàn)IN-WAIT-2,CLOSE-WAIT,CLOSE-WAIT等
- PID:進(jìn)程信息,這里包含進(jìn)程名(通過-p參數(shù)輸出的)
(2)顯示socket當(dāng)前的統(tǒng)計(jì)信息,命令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
...
其中一些輸出信息簡(jiǎn)單解釋(可以基于TcpExt一些信息分析當(dāng)前網(wǎng)絡(luò)狀況,從而快速排查問題):
- active connection openings:表示主動(dòng)發(fā)起TCP連接的次數(shù)
- passive connection openings:表示被動(dòng)接受TCP連接的次數(shù)
- failed connection attempts:表示TCP連接失敗的次數(shù)
- connection resets received:表示TCP連接被重置的次數(shù)
- connections established:表示當(dāng)前已經(jīng)建立的TCP連接數(shù)
- segments received:表示接收到的TCP數(shù)據(jù)包的數(shù)量
- segments sent out:表示發(fā)送的TCP數(shù)據(jù)包的數(shù)量
- segments retransmitted:表示重傳的TCP數(shù)據(jù)包的數(shù)量
- InCsumErrors:表示接收到的TCP數(shù)據(jù)包錯(cuò)誤的數(shù)量
7、vmstat
vmstat是輸出各個(gè)資源使用情況的工具,如進(jìn)程,內(nèi)存,CPU使用率等信息,選項(xiàng)包括:
vmstat [-fsdp][-S k|K|m|M][interval采樣間隔(s)][count采樣次數(shù)]
-f 顯示系統(tǒng)啟動(dòng)執(zhí)行以來的fork次數(shù)
-s 顯示內(nèi)存統(tǒng)計(jì)信息和活動(dòng)統(tǒng)計(jì)信息,包括fork次數(shù)
-d 顯示磁盤統(tǒng)計(jì)信息
樣例:
(1)顯示常用統(tǒng)計(jì)信息(間隔2s,并執(zhí)行兩次輸出),命令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
其中一些輸出信息簡(jiǎn)單解釋:
- procs進(jìn)程信息,r是等待運(yùn)行的進(jìn)程數(shù),b是不可中斷的睡眠狀態(tài)的進(jìn)程數(shù)
- memory內(nèi)存信息,swpd是swap內(nèi)存數(shù),free是空間內(nèi)存,buff一些系統(tǒng)buff或者io緩存的中間內(nèi)存,cache是未寫入磁盤內(nèi)存
- swap:交換分區(qū)當(dāng)前信息
- io:塊設(shè)備當(dāng)前信息
- system:CPU在內(nèi)核態(tài)運(yùn)行信息,包括in中斷次數(shù),cs上下文切換次數(shù)
- cpu:CPU使用信息,和后面mpstat命令輸出類似
(2)顯示系統(tǒng)活動(dòng)數(shù)量統(tǒng)計(jì),命令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是簡(jiǎn)單的網(wǎng)絡(luò)流量檢測(cè)工具,選項(xiàng)包括:
ifstat [-atb][-i 網(wǎng)卡][interval采樣間隔(s)][count采樣次數(shù)]
-a 監(jiān)聽所有網(wǎng)卡接口
-t 每行輸出時(shí)間信息
-b 以Kbit/s為單位顯示
-i 監(jiān)聽指定的網(wǎng)卡接口
樣例:
(1)監(jiān)聽所有網(wǎng)卡的流量情況,命令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是查看每個(gè)CPU的使用情況,使用命令:
mpstat [-P|ALL][interval采樣間隔(s)][count采樣次數(shù)]
樣例:
(1)監(jiān)聽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時(shí)02分15秒 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
10時(shí)02分20秒 all 0.70 0.00 0.80 0.50 0.00 0.00 0.00 0.00 0.00 98.00
10時(shí)02分20秒 0 0.60 0.00 0.80 0.20 0.00 0.00 0.00 0.00 0.00 98.40
10時(shí)02分20秒 1 0.80 0.00 0.80 0.80 0.00 0.00 0.00 0.00 0.00 97.60
10時(shí)02分20秒 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
10時(shí)02分25秒 all 0.50 0.00 0.30 0.00 0.00 0.00 0.00 0.00 0.00 99.20
10時(shí)02分25秒 0 0.40 0.00 0.40 0.00 0.00 0.00 0.00 0.00 0.00 99.20
10時(shí)02分25秒 1 0.60 0.00 0.20 0.00 0.00 0.00 0.00 0.00 0.00 99.20
平均時(shí)間: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
平均時(shí)間: all 0.60 0.00 0.55 0.25 0.00 0.00 0.00 0.00 0.00 98.60
平均時(shí)間: 0 0.50 0.00 0.60 0.10 0.00 0.00 0.00 0.00 0.00 98.80
平均時(shí)間: 1 0.70 0.00 0.50 0.40 0.00 0.00 0.00 0.00 0.00 98.40
其中一些輸出信息簡(jiǎn)單解釋:
- %usr:除了nice為負(fù)的進(jìn)程,系統(tǒng)上其他進(jìn)程在用戶空間的CPU運(yùn)行時(shí)間占比
- %nice:nice為負(fù)的進(jìn)程在用戶空間的CPU運(yùn)行時(shí)間占比
- %sys:系統(tǒng)上所有進(jìn)程在內(nèi)核空間的CPU運(yùn)行時(shí)間占比,但不包括硬中斷和軟中斷所耗的CPU時(shí)間
- %iowait:CPU等待磁盤操作的時(shí)間占比
- %irq:CPU處理硬中斷的時(shí)間占比
- %soft:CPU處理軟中斷的時(shí)間占比
- %steal:虛擬CPU等待時(shí)間占比
- %guest:虛擬CPU運(yùn)行時(shí)間占比
- %idle:系統(tǒng)空間時(shí)間占比
10、perf
perf是linux的一款性能分析工具,能夠進(jìn)行函數(shù)級(jí)和指令級(jí)的熱點(diǎn)查找,可以用來分析程序中熱點(diǎn)函數(shù)的CPU占用率,從而定位性能瓶頸,使用命令:
perf [top|stat][record][report][-e 事件名稱][-p 進(jìn)程ID]
-e 指定關(guān)注的事件,比如查看造成cache miss最多的函數(shù)排行:
perf top -e cache-misses
perf top -e task-clock
perf top -G // 得到調(diào)用關(guān)系圖
perf top-e cache-misses -G // 得到調(diào)用關(guān)系圖
perf top -e cycles // 指定性能事件
perf top -p 23015,32476 //查看這兩個(gè)進(jìn)程的cpu cycles使用情況
perf top -s comm,pid,symbol // 顯示調(diào)用symbol的進(jìn)程名和進(jìn)程號(hào)
perf top --comms nginx,top // 僅顯示屬于指定進(jìn)程的符號(hào)
perf top --symbols kfree // 僅顯示指定的符號(hào)
樣例:
(1)統(tǒng)計(jì)某個(gè)進(jìn)程調(diào)用函數(shù)情況,命令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壓測(cè)工具
這里介紹壓測(cè)工具h(yuǎn)ttp_bench,是HTTP(HTTP/1, HTTP/2, HTTP/3, Websocket)壓測(cè)工具,并支持單機(jī)和分布式,使用命令:
-n 請(qǐng)求HTTP的次數(shù)
-c 并發(fā)的客戶端數(shù)量,但是不能大于HTTP的請(qǐng)求次數(shù)
-q 頻率限制,每秒的請(qǐng)求數(shù)
-d 壓測(cè)持續(xù)時(shí)間,默認(rèn)10秒,例如:2s, 2m, 2h(s:秒,m:分鐘,h:小時(shí))
-t 設(shè)置請(qǐng)求的超時(shí)時(shí)間,默認(rèn)3s
-o 輸出結(jié)果格式,可以為CSV,也可以直接打印
-m HTTP方法,包括GET, POST, PUT, DELETE, HEAD, OPTIONS.
-H 請(qǐng)求發(fā)起的HTTP的頭部信息,例如:-H "Accept: text/html" -H "Content-Type: application/xml"
-body HTTP發(fā)起POST請(qǐng)求的body數(shù)據(jù)
-a HTTP的鑒權(quán)請(qǐng)求, 例如:http://username:password@xxx/
-http 支持http1, http2, http3, ws和wss, 默認(rèn)http1
-x HTTP的代理IP和端口
-disable-compression 不啟用壓縮
-disable-keepalive 不開啟keepalive
-cpus 使用cpu的內(nèi)核數(shù)
-url 壓測(cè)單個(gè)URL
-verbose 打印詳細(xì)日志,默認(rèn)等級(jí):3(0:TRACE, 1:DEBUG, 2:INFO, 3:ERROR)
-url-file 讀取文件中的URL,格式為一行一個(gè)URL,發(fā)起請(qǐng)求每次隨機(jī)選擇發(fā)送的URL
-body-file 從文件中讀取請(qǐng)求的body數(shù)據(jù)
-listen 分布式壓測(cè)任務(wù)機(jī)器監(jiān)聽I(yíng)P:PORT,例如: "127.0.0.1:12710".
-dashboard 監(jiān)聽端口,瀏覽器發(fā)起壓測(cè)和查看QPS曲線.
-W 分布式壓測(cè)執(zhí)行任務(wù)的機(jī)器列表,例如: -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