<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      日常問題排查-空閑一段時間再請求就超時

      日常問題排查-空閑一段時間再請求就超時

      前言

      最近買了臺mac mini用來寫博客,但遲遲沒有動筆。雖然積累了非常多的素材,但寫一篇《解Bug之路》系列的博客實在是太累人了。同時也很久沒有那種讓我感到興奮的問題了。但總歸不能讓這臺新買的mac mini成為擺設,于是就寫一些平時遇到的小問題吧。

      問題現場

      問題是喜聞樂見的調用超時。這個問題的顯著特征是:

      1.流量小的時候容易出現偶發性訪問超時,一般是空閑很長時間后的第一筆請求超時。
      2.調大超時時間沒有任何效果,平常請求在1s內就能返回。但出現這類超時的時候就算調整到1min超時時間依舊會超時。
      3.超時后的重試調用一般都會成功。
      4.同一時間其它相同調用不會出現問題。
      5.在內網調用不會出現這個問題,在非內網調用不管是專線還是互聯網都容易出現這個問題。
      6.服務端無法搜索到任何日志,仿佛這個超時請求沒有出現過。
      

      猜想1:服務端關閉了連接

      一個非常直觀的猜想就是服務端關閉了這個鏈接,請求直接被拒絕了。但熟悉tcp協議的筆者很快否定了這個猜想,如果連接被關閉了,會有下面圖中所示的兩種情況:

      sequenceDiagram client ->> +server: 請求 server -->> -client: 正常返回 server ->> server: close連接 alt client未收到FIN包 rect rgb(255, 150, 255) client ->> server: tcp packet server -->> client: tcp reset end else client收到FIN包 rect rgb(255, 150, 255) client ->> client: socket has already closed end end

      第一種情況,client端沒有收到服務端返回的FIN包,那么在請求發送后應該是直接被對端Reset,立刻感知到報錯。

      第二種情況,client端收到了服務端返回的FIN包,那么在請求發送前會直接報socket has already closed,立刻感知到報錯。

      根據上面的判斷,無論什么情況都是立刻返回,而不是等待很長時間之后超時,和特征2不符,于是可以否定由于服務端關閉連接導致。

      猜想2:偶發性路由翻動

      因為過了非常長的時間才超時,這時候,我們的就可以考慮是在網絡層丟包了。那么到底為什么丟包呢?難道是偶發性的路由翻動?這個想法立馬被筆者否決了。因為,如果是路由翻動一般會在分鐘級別的收斂,而我們觀察到在5s超時后的重試都是成功的。而且一旦路由翻動這段時間內所有的請求都應該收到影響,而問題現場其它請求確實正常的。這就和特征3/特征4不符合。

      猜想3(真正的原因)

      其實這個問題筆者一直遇到,而且解決方案也一直有,但從沒有真正的仔細思考過。但最近讀《tcpip路由技術》卷二突然靈光一閃,將書中的一些闡述和這個問題莫名的關聯想通了其中的關竅。人們由于IPv4地址即將耗盡而不得不開發出NAT技術,而NAT畢竟只是個補丁,其無法完整的融合進TCP導致出現種種因為這個補丁而出現的問題。我們通過NAT設備中的轉發表項維護內網的ip:port和外網的ip:port之間的映射,入下圖所示:

      很明顯的,由于client和server的數量是非常多的(因為多個服務可能公用一個公網IP),所以轉發表是一個非常寶貴的資源,一旦轉發表滿了,就無法創建新的連接路徑了。所以,一些長期沒有流量需要有一個定時的清理機制騰出轉發表以供新的連接創建。如下圖所示,在tcp連接estalbish狀態后一定時間內沒有任何流量,NAT會直接清空這個轉發表項,而client和server端無法感知到這一點,于是client端只好在多次NAT重傳后超時。這個和Bug現場的各種特征完全一致。當然無論是NAT-1和NAT-2都有可能清理轉發表,只要有一個過期那么這個連接就會出現超時。

      使用LVS做NAT的默認超時時間

      那么我們看一下我們最常用的使用LVS做NAT的默認超時時間是多少,讓我們來番一下LVS源代碼:

      static const int tcp_timeouts[IP_VS_TCP_S_LAST+1] = {
      	[IP_VS_TCP_S_NONE]		=	2*HZ,
      	[IP_VS_TCP_S_ESTABLISHED]	=	15*60*HZ, // 這邊設定了ESTABLISHED狀態的超時時間為15min
      	[IP_VS_TCP_S_SYN_SENT]		=	2*60*HZ,
      	[IP_VS_TCP_S_SYN_RECV]		=	1*60*HZ,
      	[IP_VS_TCP_S_FIN_WAIT]		=	2*60*HZ,
      	[IP_VS_TCP_S_TIME_WAIT]		=	2*60*HZ,
      	[IP_VS_TCP_S_CLOSE]		=	10*HZ,
      	[IP_VS_TCP_S_CLOSE_WAIT]	=	60*HZ,
      	[IP_VS_TCP_S_LAST_ACK]		=	30*HZ,
      	[IP_VS_TCP_S_LISTEN]		=	2*60*HZ,
      	[IP_VS_TCP_S_SYNACK]		=	120*HZ,
      	[IP_VS_TCP_S_LAST]		=	2*HZ,
      };
      
      struct ip_vs_conn *ip_vs_conn_new(......)
      {
      	......
      	timer_setup(&cp->timer, ip_vs_conn_expire, 0); // 在初始化連接的時候設置超時函數ip_vs_conn_expire
      	......
      }
      
      static void ip_vs_conn_expire(struct timer_list *t){
      	......
      	if (likely(ip_vs_conn_unlink(cp))) { // 在這里清理轉發表
      	......
      	}
      	......
      }
      static inline void set_tcp_state(......) 
      {
      
      	......
      	// 通過狀態在tcp_timeout表中找到相應的超時時間并設置進timeout
      	cp->timeout = pd->timeout_table[cp->state = new_state];
      	......
      }
      

      從上面代碼中我們可以看到,LVS通過設置的timeout_table來設置轉發表項超時時間,而不同的tcp狀態會有不同的超時時間,而默認的established的超時時間是15 * 60 * HZ也就是15min。也就是說,在默認不設置的情況下,15min中之后這個連接就會GG。

      解決方案

      好了,了解完原理之后,我們就可以有解決方案了。第一種方案,就是使用短連接。也就是每次請求的時候新建一個連接,NAT本身對tcp的FIN包做了處理,一旦發生四次揮手會自動清理表項。用完即回收,即減少了NAT設備轉發表的壓力也不會產生過一段時間超時的問題。但這個方案有個缺陷,也是短連接的固有缺陷。由于復用不了連接,短時候有海量的請求過來產生大量的短連接,由于TCP 2MSL機制的存在,client即有可能出現端口耗盡。而端口耗盡后會導致Kernel在搜索可用端口號的時候性能急劇劣化(每次搜索端口從數次循環急劇劣化到每次搜多端口都要數萬次循環),這會導致client端的機器CPU利用率急劇上升,一直陷在搜索端口號的循環里面導致整體不可用! 如下圖所示:

      具體分析可以見筆者的另一篇博客: https://my.oschina.net/alchemystar/blog/4436558

      為了解決第一種的方案的問題,我們可以依舊復用連接,只不過這個復用時間特別短,例如6s之內復用,超過6s的連接就直接丟棄。這樣既能在大量請求涌過來的時候扛住,又能解決長時間不用的超時問題。HttpClient其實提供這個機制,如下所示:

      HttpClients.custom().evictIdleConnections(6, TimeUnit.SECONDS)
      

      第三種方案,我們可以輪詢每一個connection發送心跳包,但這個實現起來比較麻煩,遠沒有上面的HttpClient內置方案省心。

      還有一個需要提到的是Http的Keep-alive,連接的保持時間是在Server端設置的。而這個Keep-alive timeout可能 > NAT的清理時間。對于Client端來說很難約束Server端的配置。所以筆者還是建議采用第二種方案。

      總結

      NAT雖然大幅度延長了IPV4地址耗盡的時間,但由于只是打了補丁,它的固有缺陷會導致很多問題。不過我們會根據遇到問題的原因給出各種解決的方案,從而讓系統穩定的運行。如果具備相應的基礎知識,這個問題非常容易解決。但如果沒有對整個通信過程有一個大致的理解,會無從著手,所以系統化的學習非常重要。

      題外話

      解Bug/日常問題排查 系列寫了很多了,呈現的一個個復雜的技術點。筆者這幾年一直在搞穩定性建設,由點入面,在穩定性方面有了一定的沉淀。所以筆者準備開新坑《高可用之路》系列,敬請期待。

      posted @ 2025-05-06 09:20  無毀的湖光-Al  閱讀(3711)  評論(12)    收藏  舉報
      主站蜘蛛池模板: 一区二区三区综合在线视频| 亚洲成人一区二区av| 盐城市| 在线精品亚洲区一区二区| 久久99国产精品尤物| 亚洲精品国模一区二区| 国产人妻大战黑人第1集| 一区二区在线欧美日韩中文| 99久久精品国产综合一区| 日本熟妇色xxxxx日本免费看| 熟女一区| 亚洲夜色噜噜av在线观看| 国产成人精品久久性色av| xxxx丰满少妇高潮| 亚洲午夜成人精品电影在线观看| 亚洲www永久成人网站| 部精品久久久久久久久| 精品少妇无码一区二区三批| 国产自国产自愉自愉免费24区| 九九视频热最新在线视频| 国产99青青成人A在线| 成 人色 网 站 欧美大片| 欧美私人情侣网站| 国产播放91色在线观看| 亚洲av与日韩av在线| 久久精品国产亚洲av麻豆长发| 亚洲国产精品日韩在线| 成人无码一区二区三区网站| 久久精品国产91精品亚洲| 久久自己只精产国品| 18成禁人视频免费| 九九热视频在线观看视频| 色色97| 日本免费精品| 久久精品国产亚洲av高| 国产成人精品视频网站| 一本大道av人久久综合| 97精品尹人久久大香线蕉| 少妇高潮激情一区二区三| 午夜国产精品福利一二| 人人妻一区二区三区|