Networking

不同的 ACK 行為(減慢吞吐量?)

  • May 17, 2011

我在一台機器(opensolaris)上執行netio(http://freshmeat.net/projects/netio/)並聯繫兩台不同的Linux機器(都在2.6.18-128.el5上)機器A和機器B。機器A 使用 netio 的網路吞吐量為 10MB/秒,機器 B 使用 netio 的網路吞吐量為 100MB/秒。在打開的 solaris 上,我跟踪了連接,所有互動看起來都一樣 - 接收和發送的視窗大小相同,ssthresh 相同,擁塞視窗大小相同,但是慢速機器正在發送,並且每 2 或 3 次接收 ACK 而快速機器每接收 12 次就發送一個 ACK。三台機器都在同一個交換機上。這是 Dtrace 輸出:快速機器:

增量發送記錄 
(us) bytes 字節 swnd snd_ws rwnd rcv_ws cwnd ssthresh
122 1448 \ 195200 7 131768 2 128872 1073725440
37 1448 \ 195200 7 131768 2 128872 1073725440
20 1448 \ 195200 7 131768 2 128872 1073725440
18 1448 \ 195200 7 131768 2 128872 1073725440
18 1448 \ 195200 7 131768 2 128872 1073725440
18 1448 \ 195200 7 131768 2 128872 1073725440
18 1448 \ 195200 7 131768 2 128872 1073725440
19 1448 \ 195200 7 131768 2 128872 1073725440
18 1448 \ 195200 7 131768 2 128872 1073725440
18 1448 \ 195200 7 131768 2 128872 1073725440 
57 1448 \ 195200 7 131768 2 128872 1073725440
171 1448 \ 195200 7 131768 2 128872 1073725440 
29 912 \ 195200 7 131768 2 128872 1073725440 
30 / 0 195200 7 131768 2 128872 1073725440 

慢機:

增量發送記錄 
(us) bytes 字節 swnd snd_ws rwnd rcv_ws cwnd ssthresh
161 / 0 195200 7 131768 2 127424 1073725440 
52 1448 \ 195200 7 131768 2 128872 1073725440
33 1448 \ 195200 7 131768 2 128872 1073725440 
11 1448 \ 195200 7 131768 2 128872 1073725440 
143 / 0 195200 7 131768 2 128872 1073725440 
46 1448 \ 195200 7 131768 2 130320 1073725440 
31 1448 \ 195200 7 131768 2 130320 1073725440 
11 1448 \ 195200 7 131768 2 130320 1073725440 
157 / 0 195200 7 131768 2 130320 1073725440 
46 1448 \ 195200 7 131768 2 131768 1073725440
18 1448 \ 195200 7 131768 2 131768 1073725440

跟踪程式碼

dtrace:130717 在 CPU 0 上下降
#!/usr/sbin/dtrace -s
#pragma D 選項安靜
#pragma D 選項預設參數
內聯 int TICKS=$1;
內聯字元串 ADDR=$$2;
dtrace:::BEGIN
{
計時器=(滴答聲!= NULL)?蜱:1;
滴答聲 = 計時器;
標題 = 10;
標題 = 0;
walltime=時間戳;
printf("正在啟動...\n");
}
tcp:::發送
/ ( args[2]->ip_daddr == ADDR || ADDR == NULL ) /
{
nfs[args[1]->cs_cid]=1; /* 這是一個 NFS 執行緒 */
delta=時間戳-walltime;
walltime=時間戳;
printf("%6d %8d \ %8s %8d %8d %8d %8d %8d %12d %12d %12d %8d %8d %d \n",
增量/1000,
args[2]->ip_plength - args[4]->tcp_offset,
"",
args[3]->tcps_swnd,
args[3]->tcps_snd_ws,
args[3]->tcps_rwnd,
args[3]->tcps_rcv_ws,
args[3]->tcps_cwnd,
args[3]->tcps_cwnd_ssthresh,
args[3]->tcps_sack_fack,
args[3]->tcps_sack_snxt,
args[3]->tcps_rto,
args[3]->tcps_mss,
args[3]->tcps_retransmit
);
標誌=0;
標題 - ;
}
tcp:::receive
/ ( args[2]->ip_saddr == ADDR || ADDR == NULL ) && nfs[args[1]->cs_cid] /
{
delta=timestamp-walltime;
walltime=時間戳;

printf("%6d %8s / %8d %8d %8d %8d %8d %8d %12d %12d %12d %8d %8d %d \n",
增量/1000,
"",
args[2]->ip_plength - args[4]->tcp_offset,
args[3]->tcps_swnd,
args[3]->tcps_snd_ws,
args[3]->tcps_rwnd,
args[3]->tcps_rcv_ws,
args[3]->tcps_cwnd,
args[3]->tcps_cwnd_ssthresh,
args[3]->tcps_sack_fack,
args[3]->tcps_sack_snxt,
args[3]->tcps_rto,
args[3]->tcps_mss,
args[3]->tcps_retransmit
);
標誌=0;
標題 - ;
}

後續添加到包括未確認的字節數,結果證明慢速程式碼確實執行它是未確認的字節,直到它達到擁塞視窗,而快速機器永遠不會達到它的擁塞視窗。這是當未確認字節到達擁塞視窗時慢速機器的輸出:

unack unack delta bytes 發送 接收 cong ssthresh
字節字節我們發送接收視窗視窗視窗
發送 收到
139760 0 31 1448 \ 195200 131768 144800 1073725440
139760 0 33 1448 \ 195200 131768 144800 1073725440
144104 0 29 1448 \ 195200 131768 146248 1073725440
145552 0 31 / 0 195200 131768 144800 1073725440
145552 0 41 1448 \ 195200 131768 147696 1073725440
147000 0 30 / 0 195200 131768 144800 1073725440
147000 0 22 1448 \ 195200 131768 76744 72400
147000 0 28 / 0 195200 131768 76744 72400
147000 0 18 1448 \ 195200 131768 76744 72400
147000 0 26 / 0 195200 131768 76744 72400
147000 0 17 1448 \ 195200 131768 76744 72400
147000 0 27 / 0 195200 131768 76744 72400
147000 0 18 1448 \ 195200 131768 76744 72400
147000 0 56 / 0 195200 131768 76744 72400
147000 0 22 1448 \ 195200 131768 76744 72400

dtrace 程式碼:


#!/usr/sbin/dtrace -s
#pragma D 選項安靜
#pragma D 選項預設參數
內聯 int TICKS=$1;
內聯字元串 ADDR=$$2;
tcp:::send, tcp:::receive
/ ( args[2]->ip_daddr == ADDR || ADDR == NULL ) /
{
nfs[args[1]->cs_cid]=1; /* 這是一個 NFS 執行緒 */
delta=時間戳-walltime;
walltime=時間戳;
printf("%6d %6d %6d %8d \ %8s %8d %8d %8d %8d %8d %12d %12d %12d %8d %8d %d \n",
args[3]->tcps_snxt - args[3]->tcps_suna ,
args[3]->tcps_rnxt - args[3]->tcps_rack,
增量/1000,
args[2]->ip_plength - args[4]->tcp_offset,
"",
args[3]->tcps_swnd,
args[3]->tcps_snd_ws,
args[3]->tcps_rwnd,
args[3]->tcps_rcv_ws,
args[3]->tcps_cwnd,
args[3]->tcps_cwnd_ssthresh,
args[3]->tcps_sack_fack,
args[3]->tcps_sack_snxt,
args[3]->tcps_rto,
args[3]->tcps_mss,
args[3]->tcps_retransmit
);
}
tcp:::receive
/ ( args[2]->ip_saddr == ADDR || ADDR == NULL ) && nfs[args[1]->cs_cid] /
{
delta=timestamp-walltime;
walltime=時間戳;
printf("%6d %6d %6d %8s / %-8d %8d %8d %8d %8d %8d %12d %12d %12d %8d %8d %d \n",
args[3]->tcps_snxt - args[3]->tcps_suna ,
args[3]->tcps_rnxt - args[3]->tcps_rack,
增量/1000,
"",
args[2]->ip_plength - args[4]->tcp_offset,
args[3]->tcps_swnd,
args[3]->tcps_snd_ws,
args[3]->tcps_rwnd,
args[3]->tcps_rcv_ws,
args[3]->tcps_cwnd,
args[3]->tcps_cwnd_ssthresh,
args[3]->tcps_sack_fack,
args[3]->tcps_sack_snxt,
args[3]->tcps_rto,
args[3]->tcps_mss,
args[3]->tcps_retransmit
);
}

現在仍然是一個問題,為什麼一台機器落後而另一台機器不落後……

我以前見過這樣的行為。我已經看到了兩個原因:

  • 錯誤的 TCP/IP 流控制協商
  • 壞司機

在您的情況下,TCP/IP 流控制問題的可能性較小,因為兩台機器都執行相同的核心,並且(設備核心模組除外,如果不同)因此執行相同的 TCP/IP 程式碼。

司機雖然。

不久前,我有一台 Windows 2003 伺服器,它根本無法將超過 6-10MB/s 的速度傳輸到某些伺服器,而且因為那是一個備份到磁碟的伺服器,這根本是不可接受的。在查看了一些數據包捕穫後,它們看起來很像您所看到的。解決的方法是將接收伺服器(Server 2003 備份伺服器)上的網路驅動程序(發生的 Broadcom)更新為更新的東西。完成後,我將獲得 60-80MB/s。

由於這是 Linux,您可能會遇到某種大段解除安裝問題。這在某種程度上確實依賴於 NIC 硬體本身處理大段的拆分。如果由於某種原因(壞韌體?)不起作用,它可能會導致這些奇怪的延遲。這是基於每個驅動程序或介面配置的。ethtool -K可以通過設備進行配置。

引用自:https://serverfault.com/questions/270374