tcp ip參數詳解


1. TCP/IP模型

我們一般知道OSI的網絡參考模型是分為7層:“應表會傳網數物”——應用層,表示層,會話層,傳輸層,網絡層,數據鏈路層,物理層。而實際的Linux網絡層協議是參照了OSI標准,但是它實現為4層:應用層,傳輸層,網絡層,網絡接口層。OSI的多層對應到了實際實現中的一層。我們最為關注的是傳輸層和網絡層。一般而言網絡層也就是IP層,負責IP路由尋址等等細節,而傳輸層TCP/UDP負責數據的可靠/快速的傳輸功能。

t

網絡的實際運行過程就是發送方,從高層向底層,根據協議對數據進行一層一層的封包,每一層加上該層協議的header;而接收方,從底層向高層,不斷的解封數據包,每一層去掉該層的協議的header,然后最高層的應用層得到應用層數據:

每一層添加的 Header(TCP/UDP Header, IP Header, Data Link Header) 都是為了實現該層協議服務而必須存在的協議相關數據。

2. Socket Buffer

發生方發送數據,接收方接受數據,那么雙方必須存在一個保存數據的buffer,稱為Socket Buffer,TCP/IP的實現都是放在kernel中的,所以Socket Buffer也是在kernel中的。Socket Buffer的大小配置對網絡的性能有很大的影響,相關參數如下:

1)/proc/sys/net/ipv4/tcp_mem: 這是一個系統全局參數,表示所有TCP的buffer配置。有三個值,單位為內存頁(通常為4K),第一個值buffer值的下限,第二個值表示內存壓力模式開始對buffer應於壓力的上限;第三個值內存使用的上限,超過時,可能會丟棄報文。

2)/proc/sys/net/ipv4/tcp_rmen: r 表示receive,也有三個值,第一個值為TCP接收buffer的最少字節數;第二個是默認值(該值會被rmem_default覆蓋);第三個值TCP接收buffer的最大字節數(該值會被rmem_max覆蓋);

3)/proc/sys/net/ipv4/tcp_wmem: w表示write,也就是send。也有三個值,第一個值為TCP發送buffer的最少字節數;第二個是默認值(該值會被wmem_default覆蓋);第三個值TCP發送buffer的最大字節數(該值會被wmem_max覆蓋);

4)/proc/sys/net/core/wmem_default: TCP數據發送窗口默認字節數;

5)/proc/sys/net/core/wmem_max: TCP數據發送窗口最大字節數;

6)/proc/sys/net/core/rmem_default: TCP數據接收窗口默認字節數;

7)/proc/sys/net/core/rmem_max: TCP數據接收窗口最大字節數;

注意:除了tcp_mem單位為內存頁之外,其它幾個單位都是字節;而且tcp_mem是全局配置,其它幾個都是針對每一個TCP連接的配置參數。

3. 網絡 NAPI, Newer newer NAPI

NAPI是為了解決網絡對CPU的影響而引入的。

Every time an Ethernet frame with a matching MAC address arrives at the interface, there will be a hard interrupt. Whenever a CPU has to handle a hard interrupt, it has to stop processing whatever it was working on and handle the interrupt, causing a context switch and the associated flush of the processor cache. While you might think that this is not a problem if only a few packets arrive at the interface, Gigabit Ethernet and modern applications can create thousands of packets per second, causing a large number of interrupts and context switches to occur.

Because of this, NAPI was introduced to counter the overhead associated with processing network traffic. For the first packet, NAPI works just like the traditional implementation as it issues an interrupt for the first packet. But after the first packet, the interface goes into a polling mode. As long as there are packets in the DMA ring buffer of the network interface, no new interrupts will be caused, effectively reducing context switching and the associated overhead.

可見:NAPI 可以有效的減少網絡對CPU中斷而導致的上下文切換次數,減輕導致的CPU性能損耗。

4. Netfilter

Linux內核中的防火牆實現模塊。也就是我們使用iptables調用的功能。提供了包過濾和地址轉換功能。

5. TCP/IP 的三次握手建立連接和四次揮手結束連接

5.1 三次握手建立連接:

1)第一次握手:建立連接時,客戶端A發送SYN包(SYN=j)到服務器B,並進入SYN_SEND狀態,等待服務器B確認。

2)第二次握手:服務器B收到SYN包,必須發生一個ACK包,來確認客戶A的SYN(ACK=j+1),同時自己也發送一個SYN包(SYN=k),即SYN+ACK包,此時服務器B進入SYN_RECV狀態。

3)第三次握手:客戶端A收到服務器B的SYN+ACK包,向服務器B發送確認包ACK(ACK=k+1),此包發送完畢,客戶端A和服務器B進入ESTABLISHED狀態,完成三次握手(注意,主動打開方的最后一個ACK包中可能會攜帶了它要發送給服務端的數據)。

總結三次握手,其實就是主動打開方,發送SYN,表示要建立連接,然后被動打開方對此進行確認,表示可以,然后主動方收到確認之后,對確認進行確認;

5.2 四次揮手斷開連接:

由於TCP連接是全雙工的,因此每個方向都必須單獨進行關閉,TCP的雙方都要向對方發送一次 FIN 包,並且要對方對次進行確認。根據兩次FIN包的發送和確認可以將四次揮手分為兩個階段:

第一階段:主要是主動閉方方發生FIN,被動方對它進行確認;  

1)第一次揮手:主動關閉方,客戶端發送完數據之后,向服務器發送一個FIN(M)數據包,進入 FIN_WAIT1 狀態;

                     被動關閉方服務器收到FIN(M)后,進入 CLOSE_WAIT 狀態;
2)第二次揮手:服務端發生FIN(M)的確認包ACK(M+1),關閉服務器讀通道,進入 LAST_ACK 狀態;客戶端收到ACK(M+1)后,關閉客戶端寫通道,

                     進入 FIN_WATI2 狀態;此時客戶端仍能通過讀通道讀取服務器的數據,服務器仍能通過寫通道寫數據。

第二階段:主要是被動關閉方發生FIN,主動方對它進行確認;

3)第三次揮手:服務器發送完數據,向客戶機發送一個FIN(N)數據包,狀態沒有變還是 LAST_ACK;客戶端收到FIN(N)后,進入 TIME_WAIT 狀態

4)第四次揮手:客戶端返回對FIN(N)的確認段ACK(N+1),關閉客戶機讀通道(還是TIME_WAIT狀態);

                     服務器收到ACK(N+1)后,關閉服務器寫通道,進入CLOSED狀態。

總結

四次揮手,其本質就是:

主動關閉方數據發生完成之后 發生FIN,表示我方數據發生完,要斷開連接,被動方對此進行確認;

然后被動關閉方在數據發生完成之后 發生FIN,表示我方數據發生完成,要斷開連接,主動方對此進行確認

5.3 CLOSE_WAIT狀態的原因和處理方法:

由上面的TCP四次揮手斷開連接的過程,可以知道 CLOSE_WAIT 是主動關閉方發生FIN之后,被動方收到 FIN 就進入了 CLOSE_WAIT狀態,此時如果被動方沒有調用 close() 函數來關閉TCP連接,那么被動方服務器就會一直處於 CLOSE_WAIT 狀態(等待調用close函數的狀態);

所以 CLOSE_WAIT 狀態很多的原因有兩點:

1)代碼中沒有寫關閉連接的代碼,也就是程序有bug; 
2)該連接的業務代碼處理時間太長,代碼還在處理,對方已經發起斷開連接請求; 也就是客戶端因為某種原因先於服務端發出了FIN信號,導致服務端被動關閉,若服務端不主動關閉socket發FIN給Client,此時服務端Socket會處於CLOSE_WAIT狀態(而不是LAST_ACK狀態)。

CLOSE_WAIT 的特性

由於某種原因導致的CLOSE_WAIT會維持至少2個小時的時間(系統默認超時時間的是7200秒,也就是2小時)。如果服務端程序因某個原因導致系統造成一堆 CLOSE_WAIT消耗資源,那么通常是等不到釋放那一刻,系統就已崩潰。CLOSE_WAIT 的危害還包括是TOMCAT失去響應等等。

要解決 CLOSE_WAIT 過多導致的問題,有兩種方法:

1)找到程序的bug,進行修正;

2)修改TCP/IP的keepalive的相關參數來縮短CLOSE_WAIT狀態維持的時間;

TCP連接的保持(keepalive)相關參數

1> /proc/sys/net/ipv4/tcp_keepalive_time  對應內核參數 net.ipv4.tcp_keepalive_time

含義:如果在該參數指定的秒數內,TCP連接一直處於空閑,則內核開始向客戶端發起對它的探測,看他是否還存活着;

2> /proc/sys/net/ipv4/tcp_keepalive_intvl  對應內核參數 net.ipv4.tcp_keepalive_intvl

含義:以該參數指定的秒數為時間間隔,向客戶端發起對它的探測;

3> /proc/sys/net/ipv4/tcp_keepalive_probes  對應內核參數 net.ipv4.tcp_keepalive_probes

含義:內核發起對客戶端探測的次數,如果都沒有得到相應,那么就斷定客戶端不可達或者已關閉,內核就關閉該TCP連接,釋放相關資源;

所以 CLOSE_WAIT 狀態維持的秒數 = tcp_keepalive_time + tcp_keepalive_intvl * tcp_keepalive_probes

所以適當的 降低 tcp_keepalive_time, tcp_keepalive_intvl,tcp_keepalive_probes 三個值就可以減少 CLOSE_WAIT:

修改方法:

sysctl -w net.ipv4.tcp_keepalive_time=600   
sysctl -w net.ipv4.tcp_keepalive_probes=3
sysctl -w net.ipv4.tcp_keepalive_intvl=5
sysctl -p

修改會暫時生效,重新啟動服務器后,會還原成默認值。修改之后,進行觀察一段時間,如果CLOSE_WAIT減少,那么就可以進行永久性修改:

在文件 /etc/sysctl.conf 中的添加或者修改成下面的內容:

net.ipv4.tcp_keepalive_time = 1800 
net.ipv4.tcp_keepalive_probes = 3 
net.ipv4.tcp_keepalive_intvl = 15 

這里的數值比上面的要大,因為上面的測試數據有點激進。當然數據該大之后效果不好,還是可以使用上面激進的數據。

修改之后執行: sysctl -p 使修改馬上生效。

5.4 TIME_WAIT狀態的原因和處理方法:

TIME_WAIT和CLOSE_WAIT不一樣,默認的TIME_WAIT本來就比較大,但是默認的CLOSE_WAIT應該很短才對。

TIME_WAIT發生在TCP四次揮手的第二階段:被動關閉方發生FIN(N),主動方收到該FIN(N),就進入 TIME_WAIT 狀態,然后發生ACK(N+1)。

進入 TIME_WAIT 之后,主動關閉方會等待 2MSL(Maximum Segment Lifetime 報文最大存活時間)的時間,才釋放自己占有的端口等資源。為什么呢?

這是因為,如果最后的ACK(N+1)沒有被被動方收到的話,被動方會重新發生一個FIN(N2),那么主動方再次發生一個確認ACK(N2+1),所以這樣一來就要用使主動關閉方在 TIME_WAIT 狀態等待 2MSL 的時長。

如果你的 TIME_WAIT 狀態的TCP過多,占用了端口等資源,那么可以通過修改TCP內核參數進行調優:

TCP 連接的 TIME_WATI相關參數:

1)/proc/sys/net/ipv4/tcp_tw_reuse  對應的內核參數:net.ipv4.tcp_tw_reuse

含義:是否能夠重新啟用處於TIME_WAIT狀態的TCP連接用於新的連接;啟用該resuse的同時,必須同時啟用下面的快速回收recycle!

2)/proc/sys/net/ipv4/tcp_tw_recycle 對應的內核參數:net.ipv4.tcp_tw_recycle

含義:設置是否對TIME_WAIT狀態的TCP進行快速回收;

3)/proc/sys/net/ipv4/tcp_fin_timeout 對應的內核參數:net.ipv4.tcp_fin_timeout

含義:主動關閉方TCP保持在FIN_WAIT_2狀態的時間。對方可能會一直不結束連接或不可預料的進程死亡。默認值為 60 秒。

修改方法和 keepalive 的相關參數一樣:

sysctl -w net.ipv4.tcp_tw_reuse=1   
sysctl -w net.ipv4.tcp_tw_recycle=1
sysctl -w net.ipv4.tcp_fin_timeout=30
sysctl -p

永久修改方法,也是修改 /etc/sydctl.conf:

net.ipv4.tcp_tw_reuse=1   
net.ipv4.tcp_tw_recycle=1
net.ipv4.tcp_fin_timeout=30

sysctl -p 是修改生效。

如果是Windows Server,則可以修改:TcpTimedWaitDelay  和 MaxUserPort;具體參見:http://www.cnblogs.com/digdeep/p/4779544.html

5.5 查看 TCP 連接處於各種狀態的連接數量:

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
TIME_WAIT 297
ESTABLISHED 53
CLOSE_WAIT 5

windows 平台實現類似功能:

netstat -n | find /i "time_wait" /c
netstat -n | find /i "close_wait" /c
一個一個的狀態來統計。

6. TCP/IP transfer window(傳輸窗口,滑動窗口)

Basically, the TCP transfer window is the maximum amount of data a given host can send or receive before requiring an acknowledgement from the other side of the connection. The window size is offered from the receiving host to the sending host by the window size field in the TCP header. Using the transfer window, the host can send packets more effectively because the sending host doesn't have to wait for acknowledgement for each sending packet. It enables the network to be utilized more. Delayed acknowledgement also improves efficiency. TCP windows start small and increase slowly with every successful acknowledgement from the other side of the connection.

傳輸窗口或者說滑動窗口,是指發送方在收到一個接收方的確認包之前,可以發送的數據的總量。接收方通過TCP頭中的window size字段告訴發送方自己的可以接受的 傳輸窗口是多大,然后發送方就會據此對傳輸窗口的大小進行優化。

7. TCP/IP Offload

如果網卡硬件支持checksum、tso等等功能,那么就可以將這些功能讓網卡來實現,從而降低CPU的負載。

1)checksum offload:為了保證數據傳輸時沒有被破壞,IP/TCP/UDP都會對數據進行checksum,然后進行比較;該功能可以讓網卡硬件實現;

2)TCP segmentation offload(TSO):如果傳輸的數據超過了網卡的MTU,那么就必須拆分成,也可以讓網卡硬件來實現該功能;

8. 多網卡綁定

Linux 內核支持將多個物理網卡綁定成一個邏輯網絡,從而進行網卡的負載均衡和網卡容錯的實現。

9. 偵測網絡瓶頸和故障

查看Linux網絡情況的命令一般有:netstat, iptraf, tcpdump 等等,其中netstat是使用的最多,也最好使用的工具。

9.1 使用 netstat 命令查看活動的網絡連接

netstat 查看信息根據協議不同和連接狀態不同分為兩類:

1)根據協議 tcp -t, udp -u 進行顯示: netstat -ntap, netstat -nuap

-t 表示tcp 連接, -u 表示 udp 連接,如下所示

復制代碼
[root@localhost ~]# netstat -ntap
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name
tcp        0      0 0.0.0.0:21                  0.0.0.0:*                   LISTEN      1373/vsftpd
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      1352/sshd
tcp        0      0 0.0.0.0:6379                0.0.0.0:*                   LISTEN      1359/redis-server *
tcp        0      0 0.0.0.0:111                 0.0.0.0:*                   LISTEN      1078/rpcbind
tcp        0      0 192.168.1.200:22            192.168.1.3:50911           ESTABLISHED 1651/sshd
tcp        0      0 192.168.1.200:22            192.168.1.3:50910           ESTABLISHED 1648/sshd
tcp        0      0 192.168.1.200:22            192.168.1.3:52950           ESTABLISHED 2304/sshd
tcp        0      0 192.168.1.200:22            192.168.1.3:50909           ESTABLISHED 1645/sshd
tcp        0      0 192.168.1.200:22            192.168.1.3:50908           ESTABLISHED 1642/sshd
tcp        0      0 :::22                       :::*                        LISTEN      1352/sshd
tcp        0      0 :::3306                     :::*                        LISTEN      2131/mysqld
tcp        0      0 :::6379                     :::*                        LISTEN      1359/redis-server *
tcp        0      0 :::111                      :::*                        LISTEN      1078/rpcbind
[root@localhost ~]# netstat -nuap
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name
udp        0      0 0.0.0.0:829                 0.0.0.0:*                               1078/rpcbind
udp        0      0 0.0.0.0:111                 0.0.0.0:*                               1078/rpcbind
udp        0      0 0.0.0.0:631                 0.0.0.0:*                               1042/portreserve
udp        0      0 :::829                      :::*                                    1078/rpcbind
udp        0      0 :::111                      :::*                                    1078/rpcbind
復制代碼

2)其中對於TCP協議又可以根據連接的狀態不同進行顯示: LISTEN -l ; 非 LISTEN 的,所有狀態的 -a

加 -l 選項表示僅僅顯示 listen 狀態的TCP連接,-a 選項表示所有狀態的TCP連接,默認只顯示ESTABLISHED 的TCP的連接,如下所示:

復制代碼
[root@localhost ~]# netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name
tcp        0      0 0.0.0.0:21                  0.0.0.0:*                   LISTEN      1373/vsftpd
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      1352/sshd
tcp        0      0 0.0.0.0:6379                0.0.0.0:*                   LISTEN      1359/redis-server *
tcp        0      0 0.0.0.0:111                 0.0.0.0:*                   LISTEN      1078/rpcbind
tcp        0      0 :::22                       :::*                        LISTEN      1352/sshd
tcp        0      0 :::3306                     :::*                        LISTEN      2131/mysqld
tcp        0      0 :::6379                     :::*                        LISTEN      1359/redis-server *
tcp        0      0 :::111                      :::*                        LISTEN      1078/rpcbind
[root@localhost ~]# netstat -ntp
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name
tcp        0      0 192.168.1.200:22            192.168.1.3:50911           ESTABLISHED 1651/sshd
tcp        0      0 192.168.1.200:22            192.168.1.3:50910           ESTABLISHED 1648/sshd
tcp        0      0 192.168.1.200:22            192.168.1.3:52950           ESTABLISHED 2304/sshd
tcp        0      0 192.168.1.200:22            192.168.1.3:50909           ESTABLISHED 1645/sshd
tcp        0      0 192.168.1.200:22            192.168.1.3:50908           ESTABLISHED 1642/sshd
[root@localhost ~]# netstat -ntap
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name
tcp        0      0 0.0.0.0:21                  0.0.0.0:*                   LISTEN      1373/vsftpd
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      1352/sshd
tcp        0      0 0.0.0.0:6379                0.0.0.0:*                   LISTEN      1359/redis-server *
tcp        0      0 0.0.0.0:111                 0.0.0.0:*                   LISTEN      1078/rpcbind
tcp        0      0 192.168.1.200:22            192.168.1.3:50911           ESTABLISHED 1651/sshd
tcp        0      0 192.168.1.200:22            192.168.1.3:50910           ESTABLISHED 1648/sshd
tcp        0    608 192.168.1.200:22            192.168.1.3:52950           ESTABLISHED 2304/sshd
tcp        0      0 192.168.1.200:22            192.168.1.3:50909           ESTABLISHED 1645/sshd
tcp        0      0 192.168.1.200:22            192.168.1.3:50908           ESTABLISHED 1642/sshd
tcp        0      0 :::22                       :::*                        LISTEN      1352/sshd
tcp        0      0 :::3306                     :::*                        LISTEN      2131/mysqld
tcp        0      0 :::6379                     :::*                        LISTEN      1359/redis-server *
tcp        0      0 :::111                      :::*                        LISTEN      1078/rpcbind
復制代碼

-n 表示 numeric 用數字顯示 ip 和 端口,而不是文字; -p 表示程序名稱;

還有 -c 可以連續每秒顯示一次。

字段含義:

recv-Q 表示網絡接收隊列(receive queue)
表示收到的數據已經在本地接收緩沖,但是還有多少沒有被用戶進程取走,如果接收隊列Recv-Q一直處於阻塞狀態,可能是遭受了拒絕服務 denial-of-service 攻擊。

send-Q 表示網路發送隊列(send queue)
發送了,但是沒有收到對方的Ack的, 還保留本地緩沖區.
如果發送隊列Send-Q不能很快的清零,可能是有應用向外發送數據包過快,或者是對方接收數據包不夠快。

這兩個值通常應該為0,如果不為0可能是有問題的。packets在兩個隊列里都不應該有堆積狀態。可接受短暫的非0情況。

netstat -s 顯示所有協議的連接的統計數據:

復制代碼
[root@localhost ~]# netstat -s
Ip:
    4677 total packets received
    0 forwarded
    0 incoming packets discarded
    4635 incoming packets delivered
    4938 requests sent out
Icmp:
    2 ICMP messages received
    0 input ICMP message failed.
    ICMP input histogram:
        destination unreachable: 2
    2 ICMP messages sent
    0 ICMP messages failed
    ICMP output histogram:
        destination unreachable: 2
IcmpMsg:
        InType3: 2
        OutType3: 2
Tcp:
    0 active connections openings
    5 passive connection openings
    0 failed connection attempts
    0 connection resets received
    5 connections established
    4391 segments received
    4799 segments send out
    0 segments retransmited
    0 bad segments received.
    0 resets sent
Udp:
    0 packets received
    0 packets to unknown port received.
    0 packet receive errors
    137 packets sent
UdpLite:
TcpExt:
    13 delayed acks sent
    1 delayed acks further delayed because of locked socket
    557 packets header predicted
    2384 acknowledgments not containing data received
    1 predicted acknowledgments
    0 TCP data loss events
IpExt:
    InBcastPkts: 242
    InOctets: 408070
    OutOctets: 730869
    InBcastOctets: 68876
復制代碼

9.2 使用 iptraf 命令實時查看網絡

該命令顯示的是實時變化的網絡信息,直接執行  iptraf 可以進入交互界面。

一般使用方法:iptraf -i eth0, iptraf -g eth0, iptraf -d eth0,  iptraf -l eth0 其中 eth0 可以換成其它網卡,或者所有網卡 all

-i 表示 ip traffic, -g 表示 genral info, -d 表示 detail info 
比較常用的是: iptraf -d eth0, iptraf -d eth0 

其中顯示了:接收到的數據包的數量,發送的數據包的數量;還有網絡發包速率:incoming rates, outgoing rates。

9.3 使用 tcpdump 命令查看網絡 

使用 tcpdump 可以對 網卡,host, 協議,端口等等進行過濾,指定只 查看指定的網絡信息。

下面的結果來自 192.168.1.3 的瀏覽器訪問虛擬機中的 192.168.1.200中的nginx的網絡包的發送情況:

復制代碼
[root@localhost ~]# tcpdump -n -i eth0 host 192.168.1.200 and 192.168.1.3  and tcp port ! 22
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
14:18:10.381925 IP 192.168.1.3.52970 > 192.168.1.200.http: Flags [S], seq 1845276991, win 8192, options [mss 1460,nop,wscale 2,nop,nop,s  ackOK], length 0
14:18:10.382024 IP 192.168.1.200.http > 192.168.1.3.52970: Flags [S.], seq 3067341762, ack 1845276992, win 14600, options [mss 1460,nop,  nop,sackOK,nop,wscale 6], length 0
14:18:10.382301 IP 192.168.1.3.52970 > 192.168.1.200.http: Flags [.], ack 1, win 16425, length 0
14:18:10.383170 IP 192.168.1.3.52970 > 192.168.1.200.http: Flags [P.], seq 1:352, ack 1, win 16425, length 351
14:18:10.383222 IP 192.168.1.200.http > 192.168.1.3.52970: Flags [.], ack 352, win 245, length 0
14:18:10.385314 IP 192.168.1.200.http > 192.168.1.3.52970: Flags [P.], seq 1:244, ack 352, win 245, length 243
14:18:10.386902 IP 192.168.1.200.http > 192.168.1.3.52970: Flags [P.], seq 244:856, ack 352, win 245, length 612
14:18:10.387324 IP 192.168.1.3.52970 > 192.168.1.200.http: Flags [.], ack 856, win 16211, length 0
14:18:20.392717 IP 192.168.1.3.52970 > 192.168.1.200.http: Flags [.], seq 351:352, ack 856, win 16211, length 1
14:18:20.392784 IP 192.168.1.200.http > 192.168.1.3.52970: Flags [.], ack 352, win 245, options [nop,nop,sack 1 {351:352}], length 0
^C
10 packets captured
12 packets received by filter
0 packets dropped by kernel
復制代碼

下面截圖簡單分析上面的結果:

首先是 192.168.1.3.52970 的瀏覽器 向 192.168.1.200.http 的服務器 發送一個 主動打開的 SYN(1845276991) 包;

接下來 192.168.1.200.http 的服務器 向 192.168.1.3.52970 的瀏覽器 發送一個 SYN + ACK 包,注意 ack=1845276992 = 1845276991 +1;

然后是 192.168.1.3.52970 的瀏覽器 向 192.168.1.200.http 的服務器 發送一個 ACK(1),然后向 服務器發送請求,seq 1:352從1到352剛好351個字節,和請求的長度: length 351 吻合;

接下來 服務器接受http請求之后,返回一個 ACK(352) ,確認收到瀏覽器的請求,然后開始處理,接着返回內容:

seq: 1:244, seq: 244:856, 響應請求,發送內容是用了兩個TCP連接,一起發送了 855個字節給瀏覽器;

然后是 192.168.1.3.52970 的瀏覽器 接收到 856 個字節之后,返回一個 ACK(856)該服務器。

最后的兩個可能是用於 瀏覽器和服務器之間保持keepalive而發送的。因為瀏覽器向服務器進發送一個字節(seq 351:352),然后服務器進行確認ACK(352)

可以看到每一個連接的頭部都帶有了 win 字段值(window size),在確定傳輸窗口(滑動窗口)是需要使用到該字段;同時還可以看到MSS值。

9.4 使用 sar -n 命令查看網絡 

sar 命令太強大了,CPU、內存、磁盤IO、網絡 都可以使用sar命令來查看。sar -n 專門用於網絡,使用方法如下:

sar -n { keyword [,...] | ALL }
              Report network statistics.

              Possible keywords are DEV, EDEV, NFS, NFSD, SOCK, IP, EIP, ICMP, EICMP, TCP,  ETCP,  UDP,  SOCK6,  IP6,  EIP6,
              ICMP6, EICMP6 and UDP6.

sar -n DEV: 查看所有網卡每秒收包,發包數量,每秒接收多少KB,發送多少KB:

復制代碼
[root@localhost ~]# sar -n DEV
Linux 2.6.32-504.el6.i686 (localhost.localdomain)       10/12/2015      _i686_  (1 CPU)

09:19:33 AM       LINUX RESTART
... ...
11:10:02 AM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s
11:20:01 AM        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00
11:20:01 AM      eth0     14.40     17.84      2.16      8.13      0.00      0.00      0.06
11:20:01 AM      eth1      0.25      0.03      0.02      0.01      0.00      0.00      0.00
11:30:01 AM        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00
11:30:01 AM      eth0      0.49      0.21      0.06      0.05      0.00      0.00      0.00
11:30:01 AM      eth1      0.23      0.04      0.01      0.01      0.00      0.00      0.00
Average:           lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00
Average:         eth0      3.40      4.65      0.35      1.37      0.00      0.00      0.00
Average:         eth1      0.24      0.04      0.01      0.01      0.00      0.00      0.00
復制代碼

字段含義:rxpck/s txpck/s rxkB/s txkB/s 每秒收包,每秒發包,每秒接收KB數量,每秒發送KB數量;

sar -n EDEV: 查看網絡 錯誤,網絡超負載,網絡故障

復制代碼
[root@localhost ~]# sar -n EDEV
Linux 2.6.32-504.el6.i686 (localhost.localdomain)       10/12/2015      _i686_  (1 CPU)

09:19:33 AM       LINUX RESTART
... ...
11:10:02 AM     IFACE   rxerr/s   txerr/s    coll/s  rxdrop/s  txdrop/s  txcarr/s  rxfram/s  rxfifo/s  txfifo/s
11:20:01 AM        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
11:20:01 AM      eth0      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
11:20:01 AM      eth1      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
11:30:01 AM        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
11:30:01 AM      eth0      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
11:30:01 AM      eth1      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
Average:           lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
Average:         eth0      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
Average:         eth1      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
復制代碼

字段含義:

rxerr/s:Total number of bad packets received per second. 每秒接收的損壞的包
txerr/s:Total number of errors that happened per second while transmitting packets. 每秒發送的損壞的包
coll/s:    Number of collisions that happened per second while transmitting packets. 每秒發送的網絡沖突包數
rxdrop/s: Number of received packets dropped per second because of a lack of space in linux buffers. 每秒丟棄的接收包
txdrop/s: Number of transmitted packets dropped per second because of a lack of space in linux buffers. 每秒發送的被丟棄的包
txcarr/s:  Number of carrier-errors that happened per second while transmitting packets. carrier-errors 是啥意思?
rxfram/s: Number of frame alignment errors that happened per second on received packets. 
rxfifo/s:Number of FIFO overrun errors that happened per second on received packets. 接收fifo隊列發生過載錯誤次數(每秒)
txfifo/s:Number of FIFO overrun errors that happened per second on transmitted packets. 發送方的fifo隊列發生過載錯誤次數(每秒)

1)如果 coll/s 網絡沖突 持續存在,那么可能網絡設備存在問題或者存在瓶頸,或者配置錯誤;

2)發生了 FIFO 隊列 overrun,表示 SOCKET BUFFER 太小;

3)持續的 數據包損壞,frame 損壞,可能預示着網絡設備出現部分故障,或者配置錯誤;

sar -n SOCK:查看系統占用的所有的SOCKET端口 和 TIME_WAIT狀態連接數

復制代碼
[root@localhost ~]# sar -n SOCK
Linux 2.6.32-504.el6.i686 (localhost.localdomain)       10/12/2015      _i686_  (1 CPU)

03:36:21 PM       LINUX RESTART

03:40:02 PM    totsck    tcpsck    udpsck    rawsck   ip-frag    tcp-tw
03:50:01 PM       105         8         3         0         0         0
04:00:02 PM       105         8         3         0         0         0
04:10:02 PM       108         8         4         0         0         0
04:20:01 PM       108         8         4         0         0         0
04:30:02 PM       105         8         3         0         0         0
04:40:01 PM       105         8         3         0         0         0
04:50:01 PM       105         8         3         0         0         0
Average:          106         8         3         0         0         0
復制代碼

With the SOCK keyword, statistics on sockets in use are reported (IPv4).  The following values are displayed:
totsck:  Total number of sockets used by the system.
tcpsck:  Number of TCP sockets currently in use.
udpsck: Number of UDP sockets currently in use.
rawsck: Number of RAW sockets currently in use.
ip-frag: Number of IP fragments currently in use.
tcp-tw: Number of TCP sockets in TIME_WAIT state.

9.5 使用 ifconfig 命令查看網絡 活動,錯誤,負載:

復制代碼
[root@localhost ~]# ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 08:00:27:07:21:AA
          inet addr:192.168.1.200  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fe07:21aa/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8593 errors:0 dropped:0 overruns:0 frame:0
          TX packets:9949 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:801191 (782.4 KiB)  TX bytes:2469866 (2.3 MiB)
復制代碼

errors: 發生的該網卡上的錯誤;dropped: 被丟棄的數量;overruns: socket buffer被用完的次數;frame:幀錯誤數量

10. 網絡調優 和 故障排除

10.1 首先了解網絡的基本情況:

1)查看各種狀態數量: netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

2)查看網絡error, overruns等待錯誤:ifconfig eth0, ifconfig all, sar -n EDEV, sar -n EDEV | grep eth0

3)查看網絡流量:sar -n DEV, sar -n DEV | grep eth0

10.2 確認網絡 duplex 和 speed 是否正確:

復制代碼
[root@localhost ~]# ethtool eth0
Settings for eth0:
        Supported ports: [ TP ]
        Supported link modes:   10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
                                1000baseT/Full
        Supported pause frame use: No
        Supports auto-negotiation: Yes
        Advertised link modes:  10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
                                1000baseT/Full
        Advertised pause frame use: No
        Advertised auto-negotiation: Yes
        Speed: 1000Mb/s
        Duplex: Full
        Port: Twisted Pair
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        MDI-X: off (auto)
        Supports Wake-on: umbg
        Wake-on: d
        Current message level: 0x00000007 (7)
                               drv probe link
        Link detected: yes
復制代碼

結果中, Speed: 1000Mb/s Duplex: Full 表明了是對的。如果是 Half, 100Mb/s 等等 會對性能影響極大。必須調整。

10.3 MTU 大小 調優

如果TCP連接的兩端的網卡和網絡接口層都支持大的 MTU,那么我們就可以配置網絡,使用更大的mtu大小,也不會導致被 切割重新組裝發送。

配置命令:ifconfig eth0 mtu 9000 up

其實 除了 MTU ,還有一個 MSS(max segement size). MTU是網絡接口層的限制,而MSS是傳輸層的概念。其實這就是 TCP分段 和 IP分片 。MSS值是TCP協議實現的時候根據MTU換算而得(減掉Header)。當一個連接建立時, 連接的雙方都要通告各自的MSS值。

TCP分段發生在傳輸層,分段的依據是MSS, TCP分段是在傳輸層完成,並在傳輸層進行重組

IP分片發生在網絡層,分片的依據是MTU, IP分片由網絡層完成,也在網絡層進行重組。

其實還有一個 window size, 但是它是完全不同的東西:

winsize is used for flow control. Each time the source can send out a number of segments without ACKs. You should check "sliding- 
window" to understand this. The value of win is dynamic since it's related to the remaining buffer size.

(參見:http://www.newsmth.net/nForum/#!article/CompNetResearch/4555)

區分:MTU, MSS, window size

10.4 調高網絡緩存

過小的網絡緩存,或導致頻繁的ACK確認包,以及導致 window size 很小,傳輸窗口也很小;過小的socket buffer對網絡性能影響嚴重。

Small socket buffers could cause performance degradation when a server deals with a lot of concurrent large file transfers. A clear performance decline will hanppen when using small socket buffers. A low value of rmem_max and wmem_max limit available socket buffer sizes even if the peer has affordable socket buffers available. This causes small window sizes and creates a performance ceiling for large data transfers. Though not included in this chart, no clear performance difference is observed for small data (less than 4 KB) transfer.

1)/proc/sys/net/ipv4/tcp_mem TCP全局緩存,單位為內存頁(4k);

對應的內核參數:net.ipv4.tcp_mem ,可以在 /etc/sysctl.conf 中進行修改;

2)/proc/sys/net/ipv4/tcp_rmem 接收buffer,單位為字節

對應的內核參數:net.ipv4.tcp_rmem, 可以在 /etc/sysctl.conf 中進行修改;

3)/proc/sys/net/ipv4/tcp_wmem 接收buffer,單位為字節

對應的內核參數:net.ipv4.tcp_wmem, 可以在 /etc/sysctl.conf 中進行修改;

-----------------------

4)/proc/sys/net/core/rmem_default 接收buffer默認大小,單位字節

對應內核參數:net.core.rmem_default, 可以在 /etc/sysctl.conf 中進行修改;

5)/proc/sys/net/core/rmem_max 接收buffer最大大小,單位字節

對應內核參數:net.core.rmem_max, 可以在 /etc/sysctl.conf 中進行修改;

6)/proc/sys/net/core/wmem_default 發送buffer默認大小,單位字節

對應內核參數:net.core.rmem_default, 可以在 /etc/sysctl.conf 中進行修改;

7)/proc/sys/net/core/wmem_max 發送buffer最大大小,單位字節

對應內核參數:net.core.rmem_max, 可以在 /etc/sysctl.conf 中進行修改;

注意:修改 /etc/sysctl.conf 之后,必須執行 sysctl -p 命令才能生效。

10.5 offload配置

可以將一些網絡操作 offload 到網絡硬件來負責。

ethtool -k eth0 可以查看當前的 offload 配置:

  View Code

ethtool -K eth0 rx on|off, ethtool -K eth0 tx on|off, ethtool -K eth0 tso on|off 進行修改

10.6 調大 接收隊列和發送隊列的大小:

1)接收隊列:/proc/sys/net/core/netdev_max_backlog 對應內核參數:net.core.netdev_max_backlog

2)發送隊列:

[root@localhost ~]# ifconfig eth0 | grep txqueue
          collisions:0 txqueuelen:1000

進行修改:ifconfig eth0 txqueuelen 20000

10.7 調大 SYN 半連接 tcp_max_syn_backlog 數量

TCP三次握手建立連接時,被動打開方,有一個狀態是SYN,

When the server is heavily loaded or has many clients with bad connections with high latency, it can result in an increase in half-open connections. This is common for Web servers, especially when there are a lot of dial-up users. These half-open connections are stored in the backlog connections queue. You should set this value to at least 4096. (The default is 1024.)
Setting this value is useful even if your server does not receive this kind of connection, because it can still be protected from a DoS (syn-flood) attack.

cat /proc/sys/net/ipv4/tcp_max_syn_backlog 對應內核參數: net.ipv4.tcp_max_syn_backlog,可以在/etc/sysctl.conf文件中配置。

sysctl -w net.ipv4.tcp_max_syn_backlog=4096

當服務器負載很重時,會導致很多的客戶端的連接,服務器沒有進行確認,所以就處在 SYN 狀態,這就是所謂的半連接(half-open connection).半連接的數目由 tcp_max_syn_backlog 參數控制,增大它可以避免客戶端的連接被拒絕,同時也能防御SYN洪水攻擊。也就是可以容納更多的等待連接的數量。

10.8  /proc/sys/net/core/somaxconn 和 net.core.somaxconn 

該參數為完成3次握手,已經建立了連接,等待被accept然后進行處理的數量。默認為128,我們可以調整到 65535,甚至更大。也就是尅有容納更多的等待處理的連接。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM