14.2. ss - another utility to investigate sockets
ss是Socket Statistics的縮寫
ss命令可以用來獲取socket統計信息,它可以顯示和netstat類似的內容;但ss的優勢在於它能夠顯示更多更詳細的有關TCP和連接狀態的信息,而且比netstat更快速更高效.
當伺服器的socket連接數量變得非常大時,無論是使用netstat命令還是直接cat /proc/net/tcp,執行速度都會很慢;ss快的秘訣在於,它利用到了TCP協議棧中 tcp_diag . tcp_diag是一個用於分析統計的模組, 用netfilter來獲取第Linux內核中第一手的信息,這就確保了ss的快捷高效;如果你的系統中沒有tcp_diag,ss也可以正常運行,只是效率會變得稍慢.
netstat命令是net-tools工具集中的一員,而ss命令是iproute工具集中的一員.
yum install iproute iproute-doc
#### ss過濾器
ss的過濾器分為兩種:
state
狀態:established,syn-sent,syn-recv,fin-wait-1,fin-wait-2,time-wait,closed,close-wait,last-ack,listen,closing
除了這13種狀態之外,還有幾個聚類的狀態:
all – for all the states
bucket – 顯示狀態為maintained as minisockets,如:time-wait和syn-recv
big – 和bucket相反
connected – 除了listen and closed的所有狀態
synchronized – 所有已連接的狀態除了syn-sent
addr+port
地址和連接埠可以使用表達式,類似於tcpdump中的用法,關鍵字有:
dst ADDRESS_PATTERN – matches remote address and port
src ADDRESS_PATTERN – matches local address and port
dport RELOP PORT – compares remote port to a number
sport RELOP PORT – compares local port to a number
autobound – checks that socket is bound to an ephemeral port
#### ss usage
ss [ OPTIONS ] [ FILTER ]
OPTIONS:
-p 顯示每個進程的名字和pid
-s 列出當前socket詳細信息
-n 不解析服務名稱
-r 解析主機名
-a 顯示所有套接字(sockets)
-o 顯示計時器信息(timer)
-l 顯示監聽狀態的套接字(sockets)
-e 顯示詳細的套接字(sockets)信息
-m 顯示套接字(sockets)的內存使用情況
-i 顯示 TCP內部信息
-4 僅顯示IPv4的套接字(sockets)
-6 僅顯示IPv6的套接字(sockets)
-0 顯示 PACKET 套接字(sockets)
-t 僅顯示 TCP套接字(sockets)
-u 僅顯示 UCP套接字(sockets)
-d 僅顯示 DCCP套接字(sockets)
-w 僅顯示 RAW套接字(sockets)
-x 僅顯示 Unix套接字(sockets)
-f --family=FAMILY 顯示 FAMILY類型的套接字(sockets),FAMILY可選,支持 unix, inet, inet6, link, netlink
-D --diag=FILE 將原始TCP套接字(sockets)信息轉儲到檔案
-F --filter=FILE 從檔案中都去過濾器信息 FILTER := [ state TCP-STATE ] [ EXPRESSION ]
#### Recv And Send
[root@netkiller ~]# ss -anp | column -c1
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 127.0.0.1:9000 *:* users:(("php-fpm",1481,9),("php-fpm",1482,0),("php-fpm",1483,0),("php-fpm",1484,0),("php-fpm",1485,0),("php-fpm",1486,0),("php-fpm",1487,0),("php-fpm",1488,0),("php-fpm",1489,0),("php-fpm",1490,0),("php-fpm",1491,0))
LISTEN 0 50 *:3306 *:* users:(("mysqld",2680,11))
LISTEN 0 128 *:443 *:* users:(("nginx",1743,8),("nginx",1744,8),("nginx",1745,8))
LISTEN 0 128 10.1.17.17:2812 *:* users:(("monit",2030,6))
TIME-WAIT 0 0 127.0.0.1:43251 127.0.0.1:80
TIME-WAIT 0 0 127.0.0.1:43248 127.0.0.1:80
ESTAB 0 0 10.1.17.17:22 10.1.17.18:51752 users:(("sshd",3122,3))
ESTAB 0 0 10.1.17.17:22 10.1.20.70:51531 users:(("sshd",19093,3))
處于LISTEN狀態的socket:
Recv-Q表示了current listen backlog隊列元素數目(等待用戶調用accept的完成3次握手的socket)
Send-Q表示了listen socket最大能容納的backlog.這個數目由listen時指定,且不能大於 /proc/sys/net/ipv4/tcp_max_syn_backlog;
對於非LISTEN socket:
Recv-Q表示了receive queue中的位元組數目(等待接收的下一個tcp段的序號-尚未從內核空間copy到用戶空間的段最前面的一個序號)
Send-Q表示發送queue中容納的位元組數(已加入發送隊列中最後一個序號-輸出段中最早一個未確認的序號)
#### Sockets State
>1 Listen
[root@netkiller ~]# ss -lnp | column -c1
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 127.0.0.1:9000 *:* users:(("php-fpm",1481,9),("php-fpm",1482,0),("php-fpm",1483,0),("php-fpm",1484,0),("php-fpm",1485,0),("php-fpm",1486,0),("php-fpm",1487,0),("php-fpm",1488,0),("php-fpm",1489,0),("php-fpm",1490,0),("php-fpm",1491,0))
LISTEN 0 50 *:3306 *:* users:(("mysqld",2680,11))
LISTEN 0 50 *:3307 *:* users:(("mysqld",2564,11))
>2 Established
[root@netkiller ~]# ss -onp state established | column -c1
Recv-Q Send-Q Local Address:Port Peer Address:Port
0 0 10.1.17.17:22 10.1.17.18:51752 timer:(keepalive,70min,0) users:(("sshd",3122,3))
0 0 10.1.17.17:22 10.1.20.70:51531 timer:(keepalive,69min,0) users:(("sshd",19093,3))
>3 Sockets Summary
[root@netkiller ~]# ss -s
Total: 93 (kernel 150)
TCP: 106 (estab 10, closed 88, orphaned 0, synrecv 0, timewait 88/0), ports 41
Transport Total IP IPv6
* 150 - -
RAW 0 0 0
UDP 1 1 0
TCP 18 18 0
INET 19 19 0
FRAG 0 0 0
>4 Expand
1 顯示所有狀態為established的ssh連接
[root@netkiller ~]# ss -o state established '( dport = :ssh or sport = :ssh )'
Recv-Q Send-Q Local Address:Port Peer Address:Port
0 0 10.1.17.17:ssh 10.1.17.18:51752 timer:(keepalive,109min,0)
0 0 10.1.17.17:ssh 10.1.20.70:51531 timer:(keepalive,103min,0)
#### ***timer user mem rto***
------在另外一個終端執行 ssh 10.1.2.103-----
然後在本終端執行如下命令
[root@netkiller ~]# ss -eimpn '( dport = :22 )' -o
State Recv-Q Send-Q Local Address:Port Peer Address:Port
ESTAB 0 0 10.1.2.23:44107 10.1.2.103:22 timer:(keepalive,28min,0) users:(("ssh",9545,4)) ino:21970248 sk:ffff88013c2e5900
mem:(r0,w0,f4096,t0) sack cubic wscale:7,8 rto:203 rtt:3.25/1.75 ato:40 cwnd:10 send 35.9Mbps rcv_rtt:33427 rcv_space:113592
------在另外一個終端執行 telnet 27.111.200.86 15672-----
然後在本終端執行如下命令
[root@netkiller ~]# ss -eimpn '( dport = :15672 )' -o
State Recv-Q Send-Q Local Address:Port Peer Address:Port
ESTAB 0 2 10.1.2.23:57531 27.111.200.86:15672 timer:(on,614ms,0) users:(("telnet",10163,4)) ino:21983807 sk:ffff8800378ba040
mem:(r0,w554,f3542,t0) sack cubic wscale:7,8 cwnd:10 rcv_space:14600
> timer
-o 顯示計時器信息(timer),linux對一個tcp socket總共有7個定時器,通過4個timer實現
通過icsk_retransmit_timer實現的重傳定時器,零窗口探測定時器;
通過sk_timer實現的連接建立定時器,保活定時器和FIN_WAIT_2定時器;
通過icsk_delack_timer實現的延時ack定時器以及TIME_WAIT定時器.
timer 這個輸出描述的是tcp socket上的定時器
timer 的輸出含義就是(類型,過期時間,重試次數)
off: 當前socket沒有timer
on: 重傳timer
keepalive:連接建立timer or fin_wait_2 timer or 保活timer;具體是那個timer,可以根據連接的狀態來確定.
timewait: TIME_WAITtimer
persist:零窗口探測timer
> user
ss -p 輸出users項裡會出現三個參數:
第一個是進程名
第二個為pid
第三項該進程檔案描述符的使用數量
> mem
mem:(r0,w554,f3542,t0)
r the read (inbound) buffer
w the write (outbound) buffer
f the "forward allocated memory" (memory available to the socket)
t the transmit queue (stuff waiting to be sent or waiting on an ACK)
> socket information
sack cubic wscale
rto
rtt
cwnd
send
rcv_space
#### Notice
>1 ss process name and pid
only name
ss -tp | grep -v Recv-Q | sed -e 's/.*users:(("//' -e 's/".*$//' | sort | uniq
only pid
[root@netkiller ~]# ss -tp | grep -v Recv-Q | sed -e 's/.*users:((.*",//' -e 's/,.*$//' | sort | uniq
name and pid
# ss -tp | grep -v Recv-Q | sed -e 's/.*users:(("\(.*\)",\(.*\),.*$/\1:\2/' | sort | uniq
f_e_related_dat:4695
mysqld:4289
salt-minion:4001
sshd:25161