什么?-你的服務竟然被探活搞死了?


背景

今年開發了好多服務,着實踩了不少的坑。這不,分分鍾就被探活搞的死去活來。這里我把這些經驗分享給大家,避免大家再繼續犯這種錯誤。

通用tcp探活原理

其實,探活原理特別簡單,只要稍懂計算機網絡就能夠理解。

  • 檢測端 發起tcp三次握手,建立新連接,連接建立成功代表服務活着,建立失敗代表服務死了,之后發送rst包主動斷開連接。
  • 被檢測端 接受檢測端發送的三次握手手建立連接,當接收到檢測端的rst包后,被檢測端斷開連接,釋放資源。

但是假如rst包丟失了,會發生什么樣的情況呢?我們以thrift為例講述一下之后所發生的事情,如下圖所示。

經過三次握手后,服務端已經建立一個新的數據連接,並把連接丟給工作線程。服務端的工作線程監聽連接,並准備接收請求(畢竟,任何一個thrift服務都是先接收請求數據,之后進行計算,最后返回響應數據,所以當新連接建立后,thrift默認首先讀取連接上的數據)。

檢測端建立連接成功后,認為下游服務還活着,所以立刻發送rst包(檢測端認為這個rst包一定會到達被檢測服務),並且釋放連接資源。

但是如果網絡狀態不好,rst包丟失,那么服務端(被檢測端)的工作線程就會無限制的hang在讀取連接數據上(因為檢測端已經單方面認為連接斷開,不會寫任何數據,所以服務端也讀不到任何數據)。如果多丟幾個rst包,那可以預期無論你有多少thrift工作線程,都將會hang死。

此時真正調用服務的客戶端的請求也無限制的hang住,因為這些請求得不到thrift工作線程的處理。

最最可怕的是:由於探活只是單純的建立連接而並不發送或者接受額外數據,並且thrift服務有單獨的線程進行accept,這導致了連接建立每次都成功,但實際上服務已經沒有了計算能力。

最后的結局就是:整個系統流量突然降低,下游接收不到請求(以為是上游調用的鍋),上游發出的請求得不到響應(認為是下游服務的鍋),並且沒有報警短信發出(以為是運維的鍋),對排查問題造成很大的困擾。

出現這種問題時有一個非常明顯的現象:即使在系統流量為0的情況下,服務端也會不斷有新連接建立並處於Establish狀態(這是因為周期性的探活導致的),並且服務端日志不滾動,客戶端請求無響應。如果你的系統有這種情況,那么多半和探活有關。

我當時遇到的情況比較糟糕,因為之前一段時間rst丟包率特別低,平均幾天丟一個rst包,所以服務hang死造成的影響並不大,只要抽空重新啟動服務即可。可是突然某一天,單台服務的rst丟包數達到了秒級:隔幾秒丟一個rst包,導致我的服務短時間內全部hang死。

HTTP探活原理

在實際工作中,對於HTTP服務的探活通常也采取TCP探活原理,畢竟HTTP建立在TCP服務之上,所以TCP探活同樣適用於HTTP服務。很多HTTP服務實現原理和thrift大同小異,所以當TCP探活的rst包丟失后,HTTP服務同樣會hang在讀取連接數據。

為了避免rst包丟失,HTTP服務通常使用HTTP探活請求:探測端對被探測端發送特定的HTTP請求,並且驗證被探測端的響應數據是否符合預期。如果rst包丟失,服務端連接最差的情況下會處於TIME_WAIT狀態,經過2倍超時時間后服務端會主動關閉連接釋放資源,這樣服務端的工作線程不會長時間的被占用,相比於用TCP探活要好的多。HTTP探活原理如下圖所示。

此時rst包雖然丟失,但是由於探測使用的HTTP請求,那么整個請求的交互就會完成(探測端會等待服務端的響應數據,所以能夠確保服務端能夠完成這個響應),服務端發送完響應數據后會主動關閉連接,發送FIN包(一般的HTTP服務框架默認都會這么做),服務端連接處於TIME_WAIT狀態,經過一段時間后連接釋放,不會長時間占用服務端資源。

對於HTTP服務,我們需要提供一個不耗費cpu和內存的調用接口,這個接口只是為了滿足HTTP探活請求調用,如果探活接口死了,可以認為這個服務也死了。

如何確保不被探活搞死?

我們不能保證網絡時時刻刻正常rst包不丟失,所以我們只能改造服務使得其更健壯。
正確解決方案如下:

  • 服務端加入讀超時時間。當rst包丟失導致服務端線程hang在讀取上,超過一定時間后服務端線程會主動斷開連接,釋放資源,從而確保服務端線程能夠服務於其它請求。
  • 客戶端請求服務端加入超時限制並進行重試。當一個服務hang死,導致連接其上的客戶端也hang住后,超過一段時間后,客戶端主動斷開連接並且嘗試請求其它可用服務。

現在我們清楚探活問題的來龍去脈,那么我想問:你的服務加入超時時間了么?你的服務會被探活搞死么?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM