開發反饋有個應用在後端數據庫某次計劃性重啓後常常會出現數據庫鏈接異常問題,經過監控系統的埋點數據,發現應用鏈接數據庫異常有兩類表現:
其一:鏈接超時
131148.00ms Tomcat Connection Pool
其二:鏈接耗時過長
DAL.getConnectionCost 64018mslinux
經過監控數據彙總,出現此異常問題來自應用羣集中的多臺WEB服務器,沒有規律性,數據庫服務器也沒有作過系統版本升級及硬件調整,且數據庫各主要性能指標正常,負載很低。所以最大可疑是網絡通信上的異常致使,因而經過客戶端/服務器端同時抓包進行分析。算法
分析後,發現數據包中有許多TCP Retransmission數據庫
六次重連失敗樣例:
五次重連失敗,第六次鏈接成功樣例:
後端
TCP SYN重傳次數與請求端的tcp_syn_retries參數值有關,本案例中應用WEB服務器設置爲6(查看命令:sudo sysctl -a | grep tcp_syn_retries),即重試的間隔時間從1s開始每次都翻倍,6次的重試時間間隔爲1s, 2s, 4s, 8s,16s,32S總共63s,第6次發出後還要等64s才知道第6次也超時了,因此總共須要 1s + 2s + 4s+ 8s+ 16s + 32s+64S =127S,TCP纔會斷開鏈接。服務器
所以上述問題描述中
「鏈接超時」計算公式爲:1s + 2s + 4s+ 8s+ 16s + 32s+64S =127S
「建連耗時」計算公式與實際重試次數有關,以5次重試爲例:1s + 2s + 4s+ 8s+ 16s + 32s=63S網絡
查詢資料得知TCP Retransmission問題很大可能與tcp_tw_recycle設置有關,在此參數開啓後,服務端會對TCP包中timestamp有效性進行校驗,數據包中的timestamp理應是順序遞增,如最新的數據包timestamp小於前一個包的timestamp,服務端則認爲最新的數據包已過期從而丟棄,此問題常出如今NAT網絡,如負載均衡設備後面,由於數據包通過轉發,source_ip相同,可是後端不一樣機器的timestamp不一樣。負載均衡
檢查數據庫服務器配置,發現tcp_tw_recycle功能被開啓,同時網卡統計中存在由於時間戳被拒的數據包信息
dom
netstat -s |grep reject
251286 passive connections rejected because of time stamp
795 packets rejects in established connections because of timestamp
關閉tcp_tw_recycle功能後,應用鏈接數據庫恢復正常。本案例中爲什麼數據庫服務器重啓後應用報錯,那是由於參數先前只是作了動態關閉,沒有修改配置文件固化,重啓後讀到舊的配置從而致使應用忽然報錯。tcp
本案例中的應用服務器與後端數據庫直連,並不在NAT網絡中,那理論上特定機器發送給DB的TCP包中timestamp數值是遞增,不會出現亂序丟包問題,但實際抓包中的timestamp是亂序的,忽大忽小,沒有規律性。post
在不一樣Kernel版本環境中模擬用戶請求,發如今不一樣內核環境中,timestamp行爲有明顯差別
Kernel 4.10.13,TSecr(請求方timestamp)隨機
Kernel 3.10,TSecr(請求方timestamp)遞增
查詢資料發現timestamp生成算法在linux kernel 4.10以後進行了調整,加入偏移因子,從而變爲隨機性。所以如開啓了tcp_tw_recycle,即便在非NAT網絡環境中也會出現丟包問題,tcp_tw_recycle的弊端更爲突顯,所以在4.12內核中被移除
tcp_tw_recycle在高版本內核中弊大於利,應保持系統默認設置,關閉參數。
https://mp.weixin.qq.com/s/uwykopNnkcRL5JXTVufyBw http://80x86.io/post/linux-kernel-v4.10.1-tcp-timestamps-random-offset-problem