如何排查網路問題-開發眼裡的網路

藍胖子的程式設計夢發表於2023-03-07

網路

服務監控系列文章

服務監控系列影片

作為開發對網路的疑問

1,頻寬是什麼?
2,丟包問題如何排查?
3,如何衡量網路效能好壞,你平時需要關注網路的哪些指標呢?

概念模型

頻寬是什麼

頻寬是網路包被髮送的能力,會受到網路卡複製網路包到核心緩衝區或者搬運核心緩衝區的網路包到網路卡緩衝區的能力影響,也會受到接收視窗,擁塞視窗的影響。
如果對端接收能力變弱,那麼頻寬也不能提升上去。

當網路鏈路變長以後,網路的情況就及其複雜,因為可能網路包會經過多個路由器乃至不同運營商之間進行資料交換,而不同代理商之間的網路流量又是及其龐大的,可能會導致你的網路包產生丟包或者重發的狀況。

網路包收發過程

image.png

如何衡量網路情況的好壞

  • 從系統層面看網路

幾個重要的指標
MBS 每秒多少個MB位元組

Mbps 每秒多少個M位元位

換算關係 MBS = Mbps / 8
網路卡流入流出的流量 Mbps Gbps
每秒收發包的數量 pps
丟包數

使用sar每1秒統計一次網路介面的活動狀況,連續顯示5次。
sar -n DEV 1 5
03:05:31 PM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s
03:05:32 PM      eth0      3.00      1.00      0.26      0.20      0.00      0.00      0.00
03:05:32 PM        lo    138.00    138.00     40.56     40.56      0.00      0.00      0.00
IFACE:網路介面名稱。
rxpck/s、txpck/s:每秒收或發的資料包數量。
rxkB/s、txkB/s:每秒收或發的位元組數,以kB/s為單位。
rxcmp/s、txcmp/s:每秒收或發的壓縮過的資料包數量。
rxmcst/s:每秒收到的多播資料包。
  • 從程式角度看

更多的時候其實不是系統網路達到瓶頸,而是程式處理網路包的能力跟不上。

能夠列出每一條連線的Mbps  找出哪個ip消耗流量最多
iftop -P 

檢視程式佔用頻寬情況

sudo nethogs eth0

image.png
go tool trace 能分析出程式由於網路排程帶來的延遲問題,找出網路延遲最高的一塊程式碼。

如何查詢丟包問題

image.png

應用層

核心在監聽套接字的時候,在三次握手時,會建立兩個佇列,在伺服器收到syn 包時,會建立半連線佇列,並將這條未完成的連線 放到裡面,然後回覆ack,syn包給客戶端,當客戶端回覆ack時,核心會將這條連線放到全連線佇列裡,呼叫accept就是將連線從全連線佇列裡取出。

如果半連線佇列或者全連線佇列滿了,則可能發生丟包行為。
半連線佇列大小由核心引數tcp_max_syn_backlog定義。

sysctl -w net.ipv4.tcp_max_syn_backlog=1024

另外,上述行為受到核心引數tcp_syncookies的影響,若啟用syncookie機制,當半連線佇列溢位時,並不會直接丟棄SYN包,而是回覆帶有syncookie的SYC+ACK包,設計的目的是防範SYN Flood造成正常請求服務不可用。

sysctl -w net.ipv4.tcp_syncookies=1

如何確認

dmesg | grep "TCP: drop open request from"
netstat -ant|grep SYN_RECV|wc -l

全連線佇列大小
ss 命令可以檢視全連線佇列大小

# -l 顯示正在監聽 
# -n 不解析服務名稱
# -t 只顯示 tcp socket
$ ss -lnt
State       Recv-Q Send-Q                     Local Address:Port                                    Peer Address:Port              
LISTEN      0      50                                     *:2181                                               *:*                  
LISTEN      0      32768                          127.0.0.1:9200                                               *:*                  
LISTEN      0      32768                      192.168.0.233:9200                                               *:* 

Recv-Q:當前全連線佇列的大小,也就是當前已完成三次握手並等待服務端 accept() 的 TCP 連線;
Send-Q:當前全連線最大佇列長度,上面的輸出結果說明監聽 8088 埠的 TCP 服務,最大全連線長度為 128;
listen 的全連線大小可以在listen系統呼叫的時候指定。
go原始碼裡讀取的是 /proc/sys/net/core/somaxconn 裡的值。

# -n 不解析服務名稱
# -t 只顯示tcp socket 
$ ss -nt
State       Recv-Q Send-Q                     Local Address:Port                                    Peer Address:Port              
ESTAB       0      0                          192.168.0.233:27266                                  192.168.0.129:3306               
ESTAB       0      0                          192.168.0.233:30212                                  192.168.0.129:3306               
ESTAB       0      0                          192.168.0.233:8000                                   100.125.64.81:44948  

Recv-Q:已收到但未被應用程式讀取的位元組數;
Send-Q:已傳送但未收到確認的位元組數;

當全連線佇列滿了後,預設核心會將包丟棄,但是也可以指定其他策略。

cat /proc/sys/net/ipv4/tcp_abort_on_overflow
0

0 :如果全連線佇列滿了,那麼 server 扔掉 client 發過來的 ack ;
1 :如果全連線佇列滿了,server 傳送一個 reset 包給 client,表示廢掉這個握手過程和這個連線;

傳輸層

除了防火牆本身配置DROP規則外,與防火牆有關的還有連線跟蹤表nf_conntrack,Linux為每個經過核心網路棧的資料包,生成一個新的連線記錄項,當伺服器處理的連線過多時,連線跟蹤表被打滿,伺服器會丟棄新建連線的資料包。

# 檢視nf_conntrack表最大連線數
$ cat /proc/sys/net/netfilter/nf_conntrack_max
65536
# 檢視nf_conntrack表當前連線數
$ cat /proc/sys/net/netfilter/nf_conntrack_count
7611

網路層,物理層

netstat 可以統計網路丟包以及環形緩衝區溢位


root@nginx:/# netstat -i
Kernel Interface table
Iface      MTU    RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0       100      157      0    344 0            94      0      0      0 BMRU
lo       65536        0      0      0 0             0      0      0      0 LRU

netstat 檢視網路協議層丟包


root@nginx:/# netstat -s
Ip:
    Forwarding: 1          //開啟轉發
    31 total packets received    //總收包數
    0 forwarded            //轉發包數
    0 incoming packets discarded  //接收丟包數
    25 incoming packets delivered  //接收的資料包數
    15 requests sent out      //發出的資料包數
Icmp:
    0 ICMP messages received    //收到的ICMP包數
    0 input ICMP message failed    //收到ICMP失敗數
    ICMP input histogram:
    0 ICMP messages sent      //ICMP傳送數
    0 ICMP messages failed      //ICMP失敗數
    ICMP output histogram:
Tcp:
    0 active connection openings  //主動連線數
    0 passive connection openings  //被動連線數
    11 failed connection attempts  //失敗連線嘗試數
    0 connection resets received  //接收的連線重置數
    0 connections established    //建立連線數
    25 segments received      //已接收報文數
    21 segments sent out      //已傳送報文數
    4 segments retransmitted    //重傳報文數
    0 bad segments received      //錯誤報文數
    0 resets sent          //發出的連線重置數
Udp:
    0 packets received
    ...
TcpExt:
    11 resets received for embryonic SYN_RECV sockets  //半連線重置數
    0 packet headers predicted
    TCPTimeouts: 7    //超時數
    TCPSynRetrans: 4  //SYN重傳數
  ...

mtu的設定有時可能導致丟包的產生,如果傳送的mtu包的大小超過網路卡規定的大小,並且網路卡不允許分片,那麼則會產生丟包。

相關文章