1、現(xiàn)場問題:
客戶端A通過NAT網(wǎng)關(guān)訪問應(yīng)用服務(wù)成功,而客戶端B通過NAT網(wǎng)關(guān)訪問 應(yīng)用服務(wù)經(jīng)常性出現(xiàn)connect失敗。在服務(wù)端抓包發(fā)現(xiàn):服務(wù)端已經(jīng)收到了syn包,但沒有回復(fù)synack包;客戶端A 關(guān)閉了tcp_tw_recycle,而客戶端B開啟了tcp_tw_recycle;據(jù)當(dāng)事人稱開啟 tcp_tw_recycle 是為了減少tcp的TIME_WAIT狀態(tài)。
2. 問題分析:
大致可以推測上述問題和tcp_tw_recycle有關(guān),查看linux內(nèi)核對應(yīng)的代碼?
tcp_v4_conn_request()函數(shù):
if (tmp_opt.saw_tstamp &&
? ? ?tcp_death_row.sysctl_tw_recycle &&
? ? ?(dst = inet_csk_route_req(sk, req)) != NULL &&
? ? ?(peer = rt_get_peer((struct rtable *)dst)) != NULL &&
? ? ?peer->v4daddr == saddr) {
? ? ? ? ?if (get_seconds() < peer->tcp_ts_stamp + TCP_PAWS_MSL &&
? ? ? ? ? ? ?(s32)(peer->tcp_ts - req->ts_recent) > TCP_PAWS_WINDOW) {
? ? ? ? ? ? ? ? ?goto drop_and_release;
? ? ? }
}
其中:
sysctl_tw_recycle:本機(jī)系統(tǒng)開啟tcp_tw_recycle選項? ?
TCP_PAWS_MSL:60s,該條件判斷表示該源ip的上次tcp通訊發(fā)生在60s
TCP_PAWS_WINDOW:1,該條件判斷表示該源ip的上次tcp通訊的timestamp 大于 本次tcp。
tmp_opt.saw_tstamp:該socket支持tcp_timestamp
??? ?簡單說就是在tcp_tw_recycle/tcp_timestamps都開啟的條件下,60s內(nèi)同一源ip主機(jī)的tcp 鏈接請求中的timestamp必須是遞增的。?
結(jié)合問題分析:主機(jī)client1和client2通過NAT網(wǎng)關(guān)訪問服務(wù)時,而client1和client2的timestamp(tcp報文的時間戳與系統(tǒng)時鐘有關(guān))不相同;? 根據(jù)上述syn包處理源碼,在tcp_tw_recycle和tcp_timestamps同時開啟的條件下,timestamp大的客戶端訪問服務(wù)成功,而timestmap小的主機(jī)訪問失敗。
3. 解決方法:? ? echo 0 > /proc/sys/net/ipv4/tcp_tw_recycle;?
tcp_tw_recycle默認(rèn)是關(guān)閉的。 為了解決上述問題,需要建議關(guān)閉tcp_tw_recycle選項,而不是timestamp;因?yàn)?在tcp timestamp關(guān)閉的條件下,開啟tcp_tw_recycle是不起作用的;?tcp_timestamp選項開啟,可以提高TCP RTT的計算精度,提高TCP的性能。linux許多參數(shù)調(diào)優(yōu),需要根據(jù)業(yè)務(wù)場景以及參數(shù)背景的工作原理進(jìn)行綜合考慮,不存在一個配置文件搞定所有問題的情況。
??4、進(jìn)一步深入
上面的代碼究竟是處于什么考慮呢?是BUG嗎?實(shí)際上這個屬于TCP協(xié)議棧的PAWS機(jī)制的邏輯。PAWS (Protection Against Wrapped Sequence numbers),防止序號回繞。?
tcp報文頭中使用了32位的整數(shù)做序號。在高速網(wǎng)絡(luò)中,一個TCP鏈接的tcp序號很快就會出現(xiàn)回繞的情況。?
例如,下圖中之前消息的序號為A的數(shù)據(jù)包,由于網(wǎng)絡(luò)路徑或其他原因剛好在當(dāng)前數(shù)據(jù)流要接收序號為A的數(shù)據(jù)包時,又被服務(wù)端收到,?那么服務(wù)端就錯誤地把這個數(shù)據(jù)包當(dāng)做新消息的一部分,從而可能會導(dǎo)致上層業(yè)務(wù)使用錯誤數(shù)據(jù)。

在通過實(shí)際數(shù)據(jù)計算看一下,感受一下發(fā)送回繞需要的網(wǎng)路速度。假設(shè)網(wǎng)絡(luò)帶寬為B bytes/s,那么序號回繞的時間為 2^31/B。對于?1Gbps速率(125MBps),計算一下,發(fā)現(xiàn)只需要17秒就序號就回繞了,而TCP標(biāo)準(zhǔn)中MSL(Maximum Segment Lifetime)是2分鐘。
?為了避免這種情況的發(fā)送,需要TCP的PAWS機(jī)制,而為了說清楚PAWS,就需要說一下tcp timestamp。

如上所示,開啟tcp timestamp時,發(fā)送端的報文攜帶時間戳,接受端接受到報文進(jìn)行應(yīng)答時,會把發(fā)送的時間戳再返回給發(fā)送端。這樣發(fā)送端可以有效計算TCP的RTT值。這是tcp timestamp的一個功能,另一個功能就是用于PAWS。
PAWS如何解決序號回繞問題呢??由于接收的每個數(shù)據(jù)包都攜帶了時間戳,對于一個TCP鏈接來說,數(shù)據(jù)包的時間戳是單調(diào)遞增的,所以若數(shù)據(jù)包時間戳的數(shù)值小于當(dāng)前鏈接已處理數(shù)據(jù)包的時間戳,那么就認(rèn)定序號發(fā)生了回繞,將消息丟棄。
關(guān)于PAWS的詳細(xì)信息,可參考https://www.ietf.org/rfc/rfc1323.txt
更多內(nèi)容請關(guān)注http://www.duckula.cn