http://oldratlee.com/380/tech/java/robustness-of-implement.html
Dubbo 作爲遠程服務暴露、調用和治理的解決方案,是應用運轉的經絡,其本身實現健壯性的重要程度是不言而喻的。
這裏列出一些 Dubbo 用到的原則和方法。
日誌
日誌是發現問題、查看問題一個最常用的手段。日誌質量往往被忽視,沒有日誌使用上的明確約定。重視 Log 的使用,提高 Log 的信息濃度。日誌過多、過於混亂,會導致有用的信息被淹沒。
要有效利用這個工具要注意:
嚴格約定WARN、ERROR級別記錄的內容
- WARN 表示可以恢復的問題,無需人工介入。
- ERROR 表示需要人工介入問題。
有了這樣的約定,監管系統發現日誌文件的中出現 ERROR 字串就報警,又儘量減少了發生。過多的報警會讓人疲倦,使人對報警失去警惕性,使 ERROR 日誌失去意義。再輔以人工定期查看 WARN 級別信息,以評估系統的“亞健康”程度。
日誌中,儘量多的收集關鍵信息
哪些是關鍵信息呢?
- 出問題時的現場信息,即排查問題要用到的信息。如服務調用失敗時,要給出使用 Dubbo 的版本、服務提供者的 IP、使用的是哪個註冊中心;調用的是哪個服務、哪個方法等等。這些信息如果不給出,那麼事後人工收集的,問題過後現場可能已經不能復原,加大排查問題的難度。
- 如果可能,給出問題的原因和解決方法。這讓維護和問題解決變得簡單,而不是尋求精通者(往往是實現者)的幫助。
同一個或是一類問題不要重複記錄多次
同一個或是一類異常日誌連續出現幾十遍的情況,還是常常能看到的。人眼很容易漏掉淹沒在其中不一樣的重要日誌信息。要儘量避免這種情況。在可以預見會出現的情況,有必要加一些邏輯來避免。
如爲一個問題準備一個標誌,出問題後打日誌後設置標誌,避免重複打日誌。問題恢復後清除標誌。
雖然有點麻煩,但是這樣做保證日誌信息濃度,讓監控更有效。
界限設置
資源是有限的,CPU、內存、IO 等等。不要因爲外部的請求、數據不受限的而崩潰。
線程池(ExectorService)的大小和飽和策略
Server 端用於處理請求的 ExectorService 設置上限。ExecutorService 的任務等待隊列使用有限隊列,避免資源耗盡。當任務等待隊列飽和時,選擇一個合適的飽和策略。這樣保證平滑劣化。
在 Dubbo 中,飽和策略是丟棄數據,等待結果也只是請求的超時。
達到飽和時,說明已經達到服務提供方的負荷上限,要在飽和策略的操作中日誌記錄這個問題,以發出監控警報。記得注意不要重複多次記錄哦。(注意,缺省的飽和策略不會有這些附加的操作。)根據警報的頻率,已經決定擴容調整等等,避免系統問題被忽略。
集合容量
如果確保進入集合的元素是可控的且是足夠少,則可以放心使用。這是大部分的情況。如果不能保證,則使用有有界的集合。當到達界限時,選擇一個合適的丟棄策略。
容錯-重試-恢復
高可用組件要容忍其依賴組件的失敗。
Dubbo 的服務註冊中心
目前服務註冊中心使用了數據庫來保存服務提供者和消費者的信息。註冊中心集羣不同註冊中心也通過數據庫來進行同步數據,以感知其它註冊中心上提供者的變化。註冊中心會在內存中保存一份提供者和消費者數據,數據庫不可用時,註冊中心獨立對外提供服務以保證正常運轉,只是拿不到其它註冊中心的數據。當數據庫恢復時,重試邏輯會將內存中修改的數據寫回數據庫,並拿到數據庫中新數據。
服務的消費者
服務消費者從註冊中心拿到提供者列表後,會保存提供者列表到內存和磁盤文件中。這樣註冊中心宕機後消費者可以正常運轉,甚至可以在註冊中心宕機過程中重啓消費者。消費者啓動時,發現註冊中心不可用,會讀取保存在磁盤文件中提供者列表。重試邏輯保證註冊中心恢復後,更新信息。
重試延遲策略
上一點的子問題。Dubbo 中碰到有兩個相關的場景。
數據庫上的活鎖
註冊中心會定時更新數據庫一條記錄的時間戳,這樣集羣中其它的註冊中心感知它是存活。過期註冊中心和它的相關數據 會被清除。數據庫正常時,這個機制運行良好。但是數據庫負荷高時,其上的每個操作都會很慢。這就出現:
A 註冊中心認爲 B 過期,刪除 B 的數據。 B 發現自己的數據沒有了,重新寫入自己的數據的反覆操作。這些反覆的操作又加重了數據庫的負荷,惡化問題。
可以使用下面邏輯:
當 B 發現自己數據被刪除時(寫入失敗),選擇等待這段時間再重試。重試時間可以選擇指數級增長,如第一次等 1 分鐘,第二次 10 分鐘、第三次 100 分鐘。
這樣操作減少後,保證數據庫可以冷卻(Cool Down)下來。
Client 重連註冊中心
當一個註冊中心停機時,其它的 Client 會同時接收事件,而去重連另一個註冊中心。Client 數量相對比較多,會對註冊中心造成衝擊。避免方法可以是 Client 重連時隨機延時 3 分鐘,把重連分散開。