這是一次我維護runningdoctor時候遇到的問題
現象:
1.使用者無法打開web.runningdoctor.cn
2.監控狀态無異常、無報警
3.tracert結果無異常、丢包率正常
4.使用者無法通路的時候,我們能打開網站
5.多地代理通路網站,結果正常
6.有打開網站特别慢的時候,延遲30S
猜測問題

複現問題
偶然的一次 刷到了頁面不存在
于是趕緊tracert一下 看看網絡連通性
(但是不科學 因為這次請求被拒絕 我tracert并不及時 也許這個時候的tracert結果是能請求到頁面時的 是以最後知道結果反推這次嘗試應該說是一次失敗的嘗試)
試着解決問題

做出這種嘗試但是還是沒有确定問題到底出現在C端還是S端 ,是以隻能每種都去試試,推測一下,改了再觀察。
Try
plus:
- Netstat 看到很多Time_wait
- 檢視TIME_wait的解決思路
- 修改核心參數,重新開機應用程式
當時的核心一些網絡配置參數:
net.ipv4.tcp_syncookies = 1(半開連接配接攻擊????)
打開TCP SYN cookie選項,有助于保護伺服器免受SyncFlood攻擊。
net.ipv4.tcp_tw_reuse = 1(socket重用)
懷疑是不是socket占用太多導緻建立不起tcp連結
net.ipv4.tcp_tw_recycle = 0(罪魁兩巨頭之一 default=1)
打開socket的快速回收機制
net.ipv4.tcp_fin_timeout = 20
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_max_tw_buckets = 180000
net.ipv4.icmp_echo_ignore_all=0
(這裡無非就是打開一些上限 其實并沒有達到上限)
net.ipv4.tcp_timestamps = 0 (罪魁禍首)
校驗資料標頭的時間戳 亂序的包将會被丢棄 滿足遞增的條件才保留
後來我被派到了醫院裡去 于是我打算通過一個小程式去監測我們web的80和443端口,看看他們這邊有沒有發生請求我們伺服器的情況 并且傳回時間戳(最後通過這個時間戳去搜尋tcpdump出來的日志 去定位這次請求到底是在醫院内被拒絕的還是請求走到公網到了我們的伺服器被拒絕的)
最後通過程式傳回的時間戳去tcpdump搜尋附近的連接配接情況 終于找到了原因。就是被伺服器拒絕了!
于是我又去谷歌搜為什麼會被伺服器拒絕 于是看到了這樣一些結論,以及别人遇到的類似問題:
come to conclusion :
what makes our website server can be succed to ping and tracert but can not open it on broswer?
近來線上陸續出現了一些connect失敗的問題,經過分析試驗,最終确認和proc參數tcp_tw_recycle/tcp_timestamps相關;
-
現象
第一個現象:子產品A通過NAT網關通路服務S成功,而子產品B通過NAT網關通路服務S經常性出現connect失敗,抓包發現:服務S端已經收到了syn包,但沒有回複synack;另外,子產品A關閉了tcp timestamp,而子產品B開啟了tcp timestamp;
第二個現象:不同主機上的子產品C(開啟timestamp),通過NAT網關(1個出口ip)通路同一服務S,主機C1 connect成功,而主機C2 connect失敗;
分析
根據現象上述問題明顯和tcp timestmap有關;檢視linux 2.6.32核心源碼,發現tcp_tw_recycle/tcp_timestamps都開啟的條件下,60s内同一源ip主機的socket connect請求中的timestamp必須是遞增的。
源碼函數:tcp_v4_conn_request(),該函數是tcp層三次握手syn包的處理函數(服務端);
源碼片段:
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) {
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
goto drop_and_release;
}
tmp_opt.saw_tstamp:該socket支援tcp_timestamp
sysctl_tw_recycle:本機系統開啟tcp_tw_recycle選項
TCP_PAWS_MSL:60s,該條件判斷表示該源ip的上次tcp通訊發生在60s内
TCP_PAWS_WINDOW:1,該條件判斷表示該源ip的上次tcp通訊的timestamp 大于 本次tcp
分析:主機client1和client2通過NAT網關(1個ip位址)通路serverN,由于timestamp時間為系統啟動到目前的時間,是以,client1和client2的timestamp不相同;根據上述syn包處理源碼,在tcp_tw_recycle和tcp_timestamps同時開啟的條件下,timestamp大的主機通路serverN成功,而timestmap小的主機通路失敗;
參數:/proc/sys/net/ipv4/tcp_timestamps - 控制timestamp選項開啟/關閉
/proc/sys/net/ipv4/tcp_tw_recycle - 減少timewait socket釋放的逾時時間
解決方法
echo 0 > /proc/sys/net/ipv4/tcp_tw_recycle;
tcp_tw_recycle預設是關閉的,有不少伺服器,為了提高性能,開啟了該選項;
為了解決上述問題,個人建議關閉tcp_tw_recycle選項,而不是timestamp;因為 在tcp timestamp關閉的條件下,開啟tcp_tw_recycle是不起作用的;而tcp timestamp可以獨立開啟并起作用。
源碼函數: tcp_time_wait()
if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp)
recycle_ok = icsk->icsk_af_ops->remember_stamp(sk);
if (timeo < rto)
timeo = rto;
if (recycle_ok) {
tw->tw_timeout = rto;
} else {
tw->tw_timeout = TCP_TIMEWAIT_LEN;
if (state == TCP_TIME_WAIT)
timeo = TCP_TIMEWAIT_LEN;
}
inet_twsk_schedule(tw, &tcp_death_row, timeo,
TCP_TIMEWAIT_LEN);
linux 伺服器 無法建立TCP連接配接 時間戳 net.ipv4.tcp_timestamps
一.情況表現為
1.在公司内網對站點的http通路:
linux主機出現故障:curl以及抓包分析,發現服務端不響應linux用戶端的請求,無法建立TCP連接配接,浏覽器傳回“無法連接配接到伺服器”
windows主機正常
2.http通路品質下降:
基調顯示,新架構上線後,通路品質下滑,主要表現為
2.1.通路提示“無法連接配接到伺服器”
2.2.僅少數人遇到這種故障,并且一天中不是每次通路都會遇到,而是出現時好時壞的現象
二.處理過程
直接上google搜尋關鍵字“伺服器無法建立TCP連接配接”。
翻了幾頁後,發現這篇博文:“
http://www.sunchis.com/html/os/linux/2012/0518/413.html”。
看了一下,和我們公司内網的表現一模一樣,但各種問題(1為這方面基礎知識薄弱,2為沒有時間驗證此配置)
然後這種問題持續了n久…一直以為是内部裝置問題
後期搞不定了,大膽線上上啟用這個參數“net.ipv4.tcp_timestamps = 0”,做了下測試後,發現故障解除,原故障機每次通路都正常了!
不過還是不明其中原理,隻是大意了解,同樣處于NAT上網方式的使用者裡(與别人共用出口IP位址),如果你的時間戳小于别人的,那麼伺服器不會響應你的TCP請求,要忽略此項,将net.ipv4.tcp_timestamps = 0(/etc/sysctl.conf)
三.總結
後期學習時,看見了一個更加詳細的部落格,講的很詳細,也引入了新的問題:
http://huoding.com/2012/01/19/142其實,linux伺服器原本對時間戳(timestamps)預設是不開啟的,Linux是否啟用這種行為取決于tcp_timestamps和tcp_tw_recycle,因為tcp_timestamps預設就是開啟的,是以當tcp_tw_recycle被開啟後,實際上這種行為就被激活了。
net.ipv4.tcp_tw_recycle又是啥呢,搜尋了一下基本上是TIME_WAIT連接配接的回收參數
當 net.ipv4.tcp_timestamps 沒有設定(預設為開啟),并且 net.ipv4.tcp_tw_recycle 也開啟時,這個坑爹的錯誤就出現了,但是注意,隻表現在NAT網絡環境中。而且,大多數部落格,以及一些大牛們,都有說過要開啟 net.ipv4.tcp_tw_recycle …
啟示錄
1.三種網絡模式
The network in hospital (our clients)
Nat mode ,ipaddr exchange
這是事故的出現就是因為醫院内部是一個巨大的區域網路(每個使用我們SaaS的醫院都是數千人員工的醫院),他們通路外網是通過nat來實作的。也就是所有請求都要從外端路由到達公網,是以最終會被伺服器認為是一個使用者在請求。一旦某個標頭時間戳亂序,就會造成其他的請求被拒絕。而其他一些針對個人使用者的Saas不會出現這種情況的原因就是因為使用者分散在各個場景,各個網絡中,并不由一個路由把包從公網傳到伺服器上。
另外兩種網絡模式簡述一下怎麼用的吧:
HOST 可以用一張圖來了解:
這種模式我覺得就相當于你的每台主機與路由都是平行位址,外部能ping到你的路由就能ping你的主機,這種做法在雲端的話非常占有ip位址資源,是以一般是内部環境才能用用。一般你拉一條專線隻會給你幾個公網位址,如果你都用brige的話伺服器又多,不可能每個都配一個公網位址的。是以這種網絡模式我一般就是在虛拟機上做做實驗的時候會使用到,當然伺服器内部比如docker之類的也用docker0與eth0橋接 進而達到一個share的作用 你才能再真機上ping172的那些網絡位址。
2.三次握手協定
解決這次問題也幫我回顧了一下三次握手協定。作為一個運維,我覺得有一大塊的工作重心就在“”what happend when you input a url in your broswer?“ 排除故障要是這個思路,請求到沒有到伺服器?伺服器給你的狀态碼是什麼?通過狀态碼判斷是資源不存在還是程式錯誤?資源不存在的話是路由的問題還是權限的問題,是路由的問題的話是開發與你溝通的nginx轉發配置的問題還是程式内部路由的問題;是代碼的問題的話你就要去判斷是啟動報錯還是什麼情況?當然有了這種思路你就要通過去排查日志或者網絡抓包去定位問題,進而解決問題。
當然,我們這次故障就是出現在握手協定上,是以這裡
也順便溫習一下握手協定
男:妹子我喜歡你
女:我知道你喜歡我了,帥哥我也喜歡你
男:你知道我喜歡你了啊!你喜歡我我也喜歡你啊!
于是倆人就。。。。。。。。。。了
。。。。。。。。。。之後
男:睡覺吧
女:哦
女:那我也睡了
男: 好
前文能夠定位到問題就是握手沒建立起來 一直是妹子我喜歡你 喜歡你 喜歡你 。。。其實妹子是個聾子,根本不曉得你說的什麼,也就沒了後文………
專業一點:TCP狀态遷移:CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED服務伺服器TCP狀态遷移:CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED
不管是程式員還是運維都要關注這個問題,比如你http不設定逾時,那麼伺服器就會有大量的連接配接被占用,linux萬物皆檔案,高并發情況下資源損耗就會比較大,每個連接配接都是要占用句柄的。調優的話就是要依據這些來做,是啟用長連接配接還是短連接配接?keepalive時間設定多少,請求頻率做不做限制,核心如何調優?http傳回什麼狀态碼才友善等等,這都是要關注的細節問題。
3.經驗都是慘痛的代價走出來的
以前從來沒有遇到過這種場景,這次故障基于業務線的url監控,系統層級的監控全部沒有發現醫院出現的通路故障。這個問題也一直持續了很長一段時間,如果這是一個高頻,高價值的生産線出現這種故障必定是緻命的。未來的路還長,要學的東西還有很多很多……….
以下是我的csdn的位址:
https://blog.csdn.net/qq_15800363/article/details/78424101版權聲明:本文為部落客原創文章,轉載請附上博文連結!