What 本篇應該是穩定性「三十六計」系列的一篇:超時重試。但是「設置預設的超時和重試是一個基礎設施的基本素養」這句話我在我們組內三次開會的時候都說了。表達了我的一個理念。 Why 為什麼一個基礎設施要設置預設的超時和重試?想象下麵一個場景。 TCP協議里有一些基本的概念:MSL、TTL、RTT。 ...
What
本篇應該是穩定性「三十六計」系列的一篇:超時重試。但是「設置預設的超時和重試是一個基礎設施的基本素養」這句話我在我們組內三次開會的時候都說了。表達了我的一個理念。
Why
為什麼一個基礎設施要設置預設的超時和重試?想象下麵一個場景。
TCP協議里有一些基本的概念:MSL、TTL、RTT。
MSL(Maximum Segment Lifetime)
報文最大生存時間,它是任何報文在網路上存在的最長時間。超時報文就被丟棄。
TTL(Time To Live)
生存時間,是由源主機設置初始值,經常存的是ip數據包可以經過的最大路由數,每經過一個處理路由數減1,當值為0則報文被丟棄。
RTT(Round-trip time)
客戶端到伺服器往返所花時間。
嗯?不是很明白?這就對了。想象這些東西都沒有預設值,需要我們自己去設置,是不是很頭大?
作為基礎設施,自己應該是做過數據統計的、做過壓測的。自己的性能是什麼樣的,怎麼使用更為合理,基礎設施的開發團隊最為清楚,不應該將這種設置的責任交給調用方或者客戶端來做,加大對基礎設施的學習成本。
再來討論一個問題:為什麼要超時和重試?
長尾問題
如上圖,隨便找了一個調用的耗時。從上面可以看到平均耗時13.9ms,百分之99的耗時在30ms內,最大耗時有488ms。那對於超過100ms的請求來說,是不是在30ms內還不返回就直接丟棄這個請求重新發起一個,新請求有99%的概率在30ms內返回結果,從時間上更划算?
而之所以對同一個請求性能差距很大,原因很多,常見的有服務過載和隊列過長。
死鎖問題
想象一個分散式鎖,沒有超時時間。萬一釋放鎖時失敗了,其他人永遠不能獲取這個鎖。而如果有超時時間,鎖過期後,其他的請求通過重試是可以獲取到鎖的。
How
怎麼設置超時和重試。guava-trying是個不錯的java實現。其實不管什麼語言都不是難事,難的是超時和重試條件是什麼,設置多少合理。
超時和重試條件根據業務不同有差異。
一般的超時條件可設置為TP95(95%的請求)的2倍。或者智能一點,根據大數據統計一下,用個機器學習演算法看看怎麼設置總體耗時最小。
重試的一個比較好的實踐是每次重試的時間間隔成指數級增長,並且根據集群情況設置合理上限。這樣就避免本來服務已經過載了,短時間內大量重試造成多米諾骨牌效應(雪崩)。
合理的上限相當重要,因為有些請求不應該再重試了。比如伺服器過載時限流策略收到請求不會將請求交給執行層而是直接返回一個響應。而如果客戶端判斷:“我去,這麼快就給我結果啦!太好了,下個請求繼續給力哦~~”這種錯誤的正反饋循壞可能會成為資源耗盡的最後一根稻草。
相關閱讀