Linux 網(wǎng)絡(luò)收發(fā)流程
Linux 網(wǎng)絡(luò)棧
Linux 實(shí)際按照 TCP/IP 模型琉预,實(shí)現(xiàn)了網(wǎng)絡(luò)協(xié)議棧胆屿。在進(jìn)行網(wǎng)絡(luò)傳輸時(shí),數(shù)據(jù)包就會(huì)按照協(xié)議棧婿牍,對(duì)上一層發(fā)來的數(shù)據(jù)進(jìn)行逐層處理;然后封裝上該層的協(xié)議頭惩歉,再發(fā)送給下一層等脂。
網(wǎng)絡(luò)包的接收
當(dāng)一個(gè)網(wǎng)絡(luò)幀到達(dá)網(wǎng)卡后,網(wǎng)卡會(huì)通過 DMA 方式撑蚌,把這個(gè)網(wǎng)絡(luò)包放到收包隊(duì)列中上遥;然后通過硬中斷,告訴中斷處理程序已經(jīng)收到了網(wǎng)絡(luò)包争涌。
網(wǎng)卡中斷處理程序會(huì)為網(wǎng)絡(luò)幀分配內(nèi)核數(shù)據(jù)結(jié)sk_buff
粉楚,并將其拷貝到 sk_buff
緩沖區(qū)中;然后再通過軟中斷模软,通知內(nèi)核收到了新的網(wǎng)絡(luò)幀。
接下來仅颇,內(nèi)核協(xié)議棧從緩沖區(qū)中取出網(wǎng)絡(luò)幀政冻,并通過網(wǎng)絡(luò)協(xié)議棧李丰,從下到上逐層處理這個(gè)網(wǎng)絡(luò)幀
- 在鏈路層檢查報(bào)文的合法性嗜憔,找出上層協(xié)議的類型(比如 IPv4 還是 IPv6)币励,再去掉幀頭、幀尾影兽,然后交給網(wǎng)絡(luò)層。
- 網(wǎng)絡(luò)層取出 IP 頭镶蹋,判斷網(wǎng)絡(luò)包下一步的走向,比如是交給上層處理還是轉(zhuǎn)發(fā)赏半。當(dāng)網(wǎng)絡(luò)層確認(rèn)這個(gè)包是要發(fā)送到本機(jī)后贺归,就會(huì)取出上層協(xié)議的類型(比如 TCP 還是 UDP),去掉 IP 頭断箫,再交給傳輸層處理拂酣。
- 傳輸層取出 TCP 頭或者 UDP 頭后,根據(jù)
源 IP仲义、源端口婶熬、目的 IP、目的端口
四元組作為標(biāo)識(shí)埃撵,找出對(duì)應(yīng)的 Socket赵颅,并把數(shù)據(jù)拷貝到 Socket 的接收緩存中。
網(wǎng)絡(luò)包的發(fā)送
應(yīng)用程序調(diào)用 Socket API(比如 send)發(fā)送網(wǎng)絡(luò)包暂刘。由于這是一個(gè)系統(tǒng)調(diào)用饺谬,所以會(huì)陷入到內(nèi)核態(tài)的套接字層中。套接字層會(huì)把數(shù)據(jù)包放到 Socket 發(fā)送緩沖區(qū)中鸳惯。
網(wǎng)絡(luò)協(xié)議棧從 Socket 發(fā)送緩沖區(qū)中商蕴,取出數(shù)據(jù)包;再按照 TCP/IP 棧芝发,從上到下逐層處理绪商。比如,傳輸層和網(wǎng)絡(luò)層辅鲸,分別為其增加 TCP 頭和 IP 頭格郁,執(zhí)行路由查找確認(rèn)下一跳的 IP,并按照 MTU 大小進(jìn)行分片。
分片后的網(wǎng)絡(luò)包例书,再送到網(wǎng)絡(luò)接口層锣尉,進(jìn)行物理地址尋址,以找到下一跳的 MAC 地址自沧。然后添加幀頭和幀尾树瞭,放到發(fā)包隊(duì)列中晒喷。這一切完成后,會(huì)有軟中斷通知驅(qū)動(dòng)程序:發(fā)包隊(duì)列中有新的網(wǎng)絡(luò)幀需要發(fā)送衣盾。
最后势决,驅(qū)動(dòng)程序通過 DMA 徽龟,從發(fā)包隊(duì)列中讀出網(wǎng)絡(luò)幀唉地,并通過物理網(wǎng)卡把它發(fā)送出去耘沼。
處理線程
TODO
網(wǎng)絡(luò)監(jiān)控工具全景圖
性能指標(biāo)
帶寬
表示鏈路的最大傳輸速率群嗤,單位是b/s(比特 / 秒)兵琳。
吞吐量
表示單位時(shí)間內(nèi)成功傳輸?shù)臄?shù)據(jù)量躯肌,單位通常為 b/s(比特 / 秒)或者 B/s(字節(jié) / 秒)。吞吐量受帶寬限制
延時(shí)
表示從網(wǎng)絡(luò)請(qǐng)求發(fā)出后钱烟,一直收到遠(yuǎn)端響應(yīng)拴袭,所需要的時(shí)間延遲。在不同場(chǎng)景中怜瞒,這一指標(biāo)可能會(huì)有不同含義盼砍。比如逝她,它可以表示黔宛,建立連接需要的時(shí)間(比如 TCP 握手延時(shí))臀晃,或一個(gè)數(shù)據(jù)包往返所需的時(shí)間(比如 RTT)。
PPS
Packet Per Second(包 / 秒) 的縮寫案淋,表示以網(wǎng)絡(luò)包為單位的傳輸速率踢京。PPS通常用來評(píng)估網(wǎng)絡(luò)的轉(zhuǎn)發(fā)能力宦棺。
網(wǎng)絡(luò)基準(zhǔn)測(cè)試
轉(zhuǎn)發(fā)性能測(cè)試PPS
Linux 內(nèi)核自帶的高性能網(wǎng)絡(luò)測(cè)試工具 pktgen代咸。pktgen 支持豐富的自定義選項(xiàng)呐芥,方便你根據(jù)實(shí)際需要構(gòu)造所需網(wǎng)絡(luò)包思瘟,從而更準(zhǔn)確地測(cè)試出目標(biāo)服務(wù)器的性能。
不過管搪,在 Linux 系統(tǒng)中更鲁,你并不能直接找到 pktgen 命令澡为,因?yàn)?pktgen 作為一個(gè)內(nèi)核線程來運(yùn)行,需要你加載 pktgen 內(nèi)核模塊后顶别,再通過 /proc 文件系統(tǒng)來交互驯绎。
# modprobe pktgen
# ls /proc/net/pktgen/
kpktgend_0 kpktgend_1 pgctrl
根據(jù)上面的結(jié)果剩失,我們發(fā)現(xiàn)拴孤,PPS 為 12 萬(wàn)甲捏,吞吐量為 61 Mb/s司顿,沒有發(fā)生錯(cuò)誤免猾。那么猎提,12 萬(wàn)的 PPS 好不好呢锨苏?
作為對(duì)比棺聊,你可以計(jì)算一下千兆交換機(jī)的 PPS限佩。交換機(jī)可以達(dá)到線速(滿負(fù)載時(shí),無差錯(cuò)轉(zhuǎn)發(fā))理疙,它的 PPS 就是 1000Mbit 除以以太網(wǎng)幀的大小窖贤,即 1000Mbps / ((64+20)*8bit) = 1.5 Mpps(其中赃梧,20B 為以太網(wǎng)幀前導(dǎo)和幀間距的大惺卩帧)蹄皱。
即使是千兆交換機(jī)的 PPS夯接,也可以達(dá)到 150 萬(wàn) PPS盔几,比我們測(cè)試得到的 12 萬(wàn)大多了逊拍。所以际邻,看到這個(gè)數(shù)值你并不用擔(dān)心世曾,現(xiàn)在的多核服務(wù)器和萬(wàn)兆網(wǎng)卡已經(jīng)很普遍了轮听,稍做優(yōu)化就可以達(dá)到數(shù)百萬(wàn)的 PPS血巍。
而且述寡,如果你用了DPDK 或 XDP 禀崖,還能達(dá)到千萬(wàn)數(shù)量級(jí)帆焕。
TDP/UDP 性能
iperf
和 netperf
都是最常用的網(wǎng)絡(luò)性能測(cè)試工具叶雹,用來測(cè)試TCP 和 UDP的吞吐量折晦。它們都以客戶端和服務(wù)器通信的方式满着,測(cè)試一段時(shí)間內(nèi)的平均吞吐量。這里以iperf
命令為例风喇。
-
常用命令
-
實(shí)踐
在目標(biāo)機(jī)器上啟動(dòng)iperf 服務(wù)端# iperf3 -s -i 1 -p 10000 -s 表示啟動(dòng)服務(wù)端 -i 表示匯報(bào)間隔 -p 表示監(jiān)聽端口
在另一臺(tái)機(jī)器上運(yùn)行客戶端
# iperf3 -c 192.168.0.30 -b 1G -t 15 -P 2 -p 10000 -c 表示啟動(dòng)客戶端 -b 表示目標(biāo)帶寬 -t 表示測(cè)試時(shí)間 -P 表示并發(fā)數(shù) -p 表示目標(biāo)服務(wù)器的監(jiān)聽端口
無標(biāo)題.png
從上面可以看出目標(biāo)機(jī)器的吞吐量為866 Mb/s还蹲。
HTTP
測(cè)試HTTP的性能谜喊,也有大量工具可以使用,比如 ab诵次,webbench等藻懒。這里以 ab 為例
-
安裝
- ubuntu
apt-get install -y apache2-utils
- centos
yum install -y httpd-tools
- ubuntu
-
常用命令
-
實(shí)踐
- 在目標(biāo)機(jī)器上酷含,使用 Docker 啟動(dòng)一個(gè) Nginx 服務(wù),然后用 ab 來測(cè)試它的性能。
docker run -p 80:80 -itd nginx
- 在另一臺(tái)機(jī)器上弥虐,運(yùn)行
ab
命令,測(cè)試nginx性能# ab -c 1000 -n 10000 http://192.168.0.30/ # -c 表示并發(fā)量100,10000表示總的
- 在目標(biāo)機(jī)器上酷含,使用 Docker 啟動(dòng)一個(gè) Nginx 服務(wù),然后用 ab 來測(cè)試它的性能。
應(yīng)用負(fù)載性能
TODO
網(wǎng)絡(luò)配置
root@VM-0-12-ubuntu:~# ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.12 netmask 255.255.240.0 broadcast 172.17.15.255
inet6 fe80::5054:ff:fed7:21c8 prefixlen 64 scopeid 0x20<link>
ether 52:54:00:d7:21:c8 txqueuelen 1000 (Ethernet)
RX packets 160252 bytes 164031108 (164.0 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 64627 bytes 10431076 (10.4 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
網(wǎng)絡(luò)接口的狀態(tài)標(biāo)志
輸出的RUNNING
,都表示物理網(wǎng)絡(luò)是連通的个唧,即網(wǎng)卡已經(jīng)連接到了交換機(jī)或者路由器中。MTU的大小
規(guī)定了最大的 IP 包大小,画恰。MTU 默認(rèn)大小是 1500。網(wǎng)絡(luò)接口的IP地址考润,子網(wǎng),以及MAC地址
-
網(wǎng)絡(luò)收發(fā)的字節(jié)數(shù)绎谦,包數(shù)窃肠,錯(cuò)誤數(shù)以及丟包的情況
- errors
表示發(fā)生錯(cuò)誤的數(shù)據(jù)包數(shù)树灶,比如校驗(yàn)錯(cuò)誤破托,幀同步錯(cuò)誤州既。 - dropped
表示丟棄的數(shù)據(jù)包數(shù),即數(shù)據(jù)包已經(jīng)收到了Ring Buffer
。 - overruns
表示超限數(shù)據(jù)包數(shù),即網(wǎng)絡(luò) I/O 速度過快侮叮,導(dǎo)致Ring Buffer
中的數(shù)據(jù)包來不及處理(隊(duì)列滿)而導(dǎo)致的丟包; - carrier
表示發(fā)生 carrirer 錯(cuò)誤的數(shù)據(jù)包數(shù),比如雙工模式不匹配曙求、物理電纜出現(xiàn)問題等 - collisions
表示碰撞數(shù)據(jù)包數(shù)
- errors
查看網(wǎng)卡帶寬
# ethtool eth0 | grep Speed
連通性和延時(shí)查看:ping hping3 telnet nc 命令
ping 命令
確定網(wǎng)絡(luò)主機(jī)的連通狀態(tài)
- 發(fā)指定個(gè)數(shù)ping包
- linux
ping -c 4 www.baidu.com
- windows
- linux
- 指定ping報(bào)文數(shù)據(jù)包大小
ping -s 512 www.baidu.com
hping3 命令
出于安全的考慮芽淡,很多網(wǎng)絡(luò)服務(wù)會(huì)把ICMP禁止掉挣菲,這也就導(dǎo)致我們無法用 ping 抚岗,hping3是一個(gè)測(cè)試網(wǎng)絡(luò)包處理能力的性能工具向抢,也可以用來測(cè)試延時(shí)
# hping3 -c 3 -S -p 80 baidu.com # -c 表示3次 -S 表示Tcp SYN -p 表示端口
HPING baidu.com (eth0 39.156.69.79): S set, 40 headers + 0 data bytes
len=40 ip=39.156.69.79 ttl=249 id=6995 sport=80 flags=SA seq=0 win=8192 rtt=29.8 ms
len=40 ip=39.156.69.79 ttl=249 id=32254 sport=80 flags=SA seq=1 win=8192 rtt=36.0 ms
len=40 ip=39.156.69.79 ttl=249 id=20666 sport=80 flags=SA seq=2 win=8192 rtt=32.0 ms
telnet 命令
用于確定目標(biāo)主機(jī)端口是否打開
# telnet www.baicu.com 80
nc 命令
- 連接服務(wù)器某端口
可用來測(cè)試對(duì)方端口是否打開nc -v 127.0.0.1 12345
套接字信息:netstat 命令
netstat
netstat -[atunlp]
-a:列出目前系統(tǒng)上所有的連接亩冬,監(jiān)聽,socket
-t:列出tcp網(wǎng)絡(luò)數(shù)據(jù)包數(shù)據(jù)
-u:列出udp網(wǎng)絡(luò)數(shù)據(jù)包數(shù)據(jù)
-n:不列出進(jìn)程的服務(wù)名稱,以端口號(hào)來顯示
-l:列出目前正在監(jiān)聽的網(wǎng)絡(luò)
-p:列出網(wǎng)絡(luò)服務(wù)的PID
- 查看某個(gè)端口是否被占用
netstat -anp | grep 80
- 統(tǒng)計(jì)TCP套接字各狀態(tài)信息
netstat -ant | awk '/^tcp/ {++S[$NF]} END {for(a in S) print (a,S[a])}'
- netstat 中Recv-Q 和 Send-Q的意義
-
當(dāng)套接字處于連接狀態(tài)時(shí)
- Recv-Q 表示套接字緩沖還沒有被應(yīng)用程序取走的字節(jié)數(shù)(即接收隊(duì)列長(zhǎng)度)
- Send-Q 表示還沒有被遠(yuǎn)端主機(jī)確認(rèn)的字節(jié)數(shù)(即發(fā)送隊(duì)列長(zhǎng)度)
-
當(dāng)套接字處于監(jiān)聽狀態(tài)時(shí)
image.png- Recv-Q 表示全連接隊(duì)列的長(zhǎng)度客扎。
- Send-Q 表示全連接隊(duì)列的最大長(zhǎng)度。
全連接厌衙,是指服務(wù)器收到了客戶端的 ACK,完成了 TCP 三次握手,然后就會(huì)把這個(gè)連接挪到全連接隊(duì)列中。這些全連接中的套接字,還需要被
accept
系統(tǒng)調(diào)用取走。與全連接隊(duì)列相對(duì)應(yīng)的,還有一個(gè)半連接隊(duì)列夕玩。半連接是指還沒有完成 TCP 三次握手的連接尸昧,連接只進(jìn)行了一半。服務(wù)器收到了客戶端的 SYN 包后,就會(huì)把這個(gè)連接放到半連接隊(duì)列中忍法,然后再向客戶端發(fā)送 SYN+ACK 包羹蚣。
-
網(wǎng)絡(luò)吞吐和 PPS:sar 命令
給 sar 增加 -n 參數(shù)就可以查看網(wǎng)絡(luò)的統(tǒng)計(jì)信息,比如網(wǎng)絡(luò)接口(DEV)后专、網(wǎng)絡(luò)接口錯(cuò)誤(EDEV)、TCP、UDP、ICMP 等等
# sar -n DEV 1
Linux 4.15.0-118-generic (VM-0-12-ubuntu) 12/28/2020 _x86_64_ (1 CPU)
11:25:06 AM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
11:25:07 AM eth0 8.00 6.00 0.64 0.97 0.00 0.00 0.00 0.00
11:25:07 AM lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
11:25:07 AM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
11:25:08 AM eth0 3.96 3.96 0.32 0.80 0.00 0.00 0.00 0.00
11:25:08 AM lo 7.92 7.92 0.64 0.64 0.00 0.00 0.00 0.00
rxpck/s txpck/s
每秒鐘 接收/發(fā)送 PPS 的數(shù)據(jù)包槐脏,單位為包 / 秒rxKB/s txkB/s
每秒鐘接受/發(fā)送的數(shù)據(jù)包大小,單位為KB / 秒rxcmp/s 和 txcmp/s
分別是接收和發(fā)送的壓縮數(shù)據(jù)包數(shù)畔规,單位是包 / 秒畜埋。%ifutil
網(wǎng)絡(luò)接口的使用率模燥,即半雙工模式下為 (rxkB/s+txkB/s)/Bandwidth,而全雙工模式下為 max(rxkB/s, txkB/s)/Bandwidth。
統(tǒng)計(jì)socket連接信息
sar -n SOCK 1 1
- totsck 當(dāng)前被使用的socket總數(shù)
- tcpsck 當(dāng)前正在被使用的TCP的socket總數(shù)
- udpsck 當(dāng)前正在被使用的UDP的socket總數(shù)
- rawsck 當(dāng)前正在被使用于RAW的skcket總數(shù)
- if-frag 當(dāng)前的IP分片的數(shù)目
- tcp-tw TCP套接字中處于TIME-WAIT狀態(tài)的連接數(shù)量
iftop 命令
iftop是類似于top的實(shí)時(shí)流量監(jiān)控工具。
中間的<= =>這兩個(gè)左右箭頭束铭,表示的是流量的方向。
TX:發(fā)送流量
RX:接收流量
TOTAL:總流量
Cumm:運(yùn)行iftop到目前時(shí)間的總流量
peak:流量峰值
rates:分別表示過去 2s 10s 40s 的平均流量
常用命令
-
-i設(shè)定監(jiān)測(cè)的網(wǎng)卡
iftop -i eth1
-
-B 以bytes為單位顯示流量(默認(rèn)是bits)
iftop -B
-
-n使host信息默認(rèn)直接都顯示IP
iftop -n
-
-N使端口信息默認(rèn)直接都顯示端口號(hào)
iftop -N
-P使host信息及端口信息默認(rèn)就都顯示
-F顯示特定網(wǎng)段的進(jìn)出流量金闽,如# iftop -F 10.10.1.0/24或# iftop -F 10.10.1.0/255.255.255.0
-h(display this message)纯露,幫助,顯示參數(shù)信息
進(jìn)入iftop畫面后的一些操作命令
按h切換是否顯示幫助;
按n切換顯示本機(jī)的IP或主機(jī)名;
按s切換是否顯示本機(jī)的host信息;
按d切換是否顯示遠(yuǎn)端目標(biāo)主機(jī)的host信息;
按t切換顯示格式為2行/1行/只顯示發(fā)送流量/只顯示接收流量;
按N切換顯示端口號(hào)或端口服務(wù)名稱;
按S切換是否顯示本機(jī)的端口信息;
按D切換是否顯示遠(yuǎn)端目標(biāo)主機(jī)的端口信息;
按p切換是否顯示端口信息;
按P切換暫停/繼續(xù)顯示;
按b切換是否顯示平均流量圖形條;
按B切換計(jì)算2秒或10秒或40秒內(nèi)的平均流量;
按T切換是否顯示每個(gè)連接的總流量;
按l打開屏幕過濾功能代芜,輸入要過濾的字符埠褪,比如ip,按回車后,屏幕就只顯示這個(gè)IP相關(guān)的流量信息;
按L切換顯示畫面上邊的刻度;刻度不同挤庇,流量圖形條會(huì)有變化;
按j或按k可以向上或向下滾動(dòng)屏幕顯示的連接記錄;
按1或2或3可以根據(jù)右側(cè)顯示的三列流量數(shù)據(jù)進(jìn)行排序;
按<根據(jù)左邊的本機(jī)名或IP排序;
按>根據(jù)遠(yuǎn)端目標(biāo)主機(jī)的主機(jī)名或IP排序;
按o切換是否固定只顯示當(dāng)前的連接;
按f可以編輯過濾代碼钞速,這是翻譯過來的說法,我還沒用過這個(gè)嫡秕!
按!可以使用shell命令渴语,這個(gè)沒用過!沒搞明白啥命令在這好用呢昆咽!
按q退出監(jiān)控驾凶。
延展閱讀
- 文件描述符的數(shù)量
- syn 洪泛攻擊
- 大量請(qǐng)求帶來的中斷處理中斷不均
- dropped 上升
- 連接狀態(tài)的跟蹤(CONNTRACK)