支撐百度搜索引擎99.995%可靠名字服務架構設計
內容來源:2016年12月16日,鄭然在“GIAC 全球互聯網架構大會”進行《支撐百度搜索引擎99.995%可靠名字服務架構設計》演講分享。IT大咖說作為獨家視頻合作方,經主辦方和講者審閱授權發布。
閱讀字數:2783 | 4分鍾閱讀
點擊觀看嘉賓演講視頻
搜索引擎的挑戰
機器數量多,服務數量大:我們有數萬台服務器,數十萬個服務,分布在多個IDC。
服務變更多,變更數據大:每天幾十萬次變更,每周10P量級的文件更新,千餘人並行開發上百個模塊。
檢索流量大,穩定性要高:每秒數萬次請求,滿足99.995%的可用性,極短時間的故障都可能引發大量的拒絕。
服務發現的原理
什麼是服務發現
服務上遊如何找到下遊;服務上遊如何負載均衡;下遊掛了上遊如何感知。
客戶端服務發現
所有服務下遊自行向服務注冊表中進行注冊,同時服務上遊集成注冊表的客戶端,查詢注冊表以獲取服務下遊列表。服務上遊集成負載均衡器,實施負載均衡。
服務端服務發現
服務端服務發現和客戶端服務發現的區別就在於,服務端服務發現所有服務上遊的請求都是通過網關去查詢。
服務發現組件
服務發現主要由服務注冊表、注冊表客戶端和負載均衡組成。
服務注冊表是分布式的存儲,持久化服務地址和自定義屬性,服務名字全局唯一。
注冊表客戶端支持對注冊表的增刪改查,支持高並發高吞吐,對延遲的要求不太高,讀多寫少。
負載均衡對於整個服務係統來說是一個不可或缺的組件。它根據負載選擇某個服務,剔除和探活故障服務。
關鍵技術與實踐難點
Eden架構藍圖
Eden是百度網頁搜索部自行研發的基於百度matrix集群操作係統的PaaS平台。它主要負責服務的部署、擴縮容、故障恢複等一係列服務治理的相關工作。底層是基礎設施層,包括監控、故障檢測以及matrix集群操作係統。
Eden由三部分組成,第一部分是總控服務,分為InstanceMgr和NamingService。底層有多個agent來執行總控下發的命令。所有的源數據保存在zookeeper上,並提供了命令行、web之類的接口來使用。還有一個機器維修仲裁的組件,根據故障類型、服務狀態來決策機器的維修,同時提供了日誌的收集分析,和一個仿真的測試平台。
在這之上是job engine層,提供了封裝日常服務變更的操作,包括升級、數據的變更、服務擴容、故障實例的遷移等,在這層上做了抽象。
最上麵是一些托管的服務,有網頁圖片搜索服務、度秘服務、和信息流。
服務發現組件
對於一個IDC來說,我們會部署一套NamingService,agent複用的是Eden的agent。
服務發現不可避免的是要支持跨機房的服務發現機製,必須要有跨機房查詢的功能,我們就做了一套遠程的跨機房查詢,上層提供了SDK接口把這些過程封裝起來。
為了支持跨機房一定要APP的ID或者名字必須要全局唯一。
技術難點
我覺得一個真正能夠在線上穩定運行的服務發現係統必須要解決以下六個問題:
調用時機:誰來向服務注冊表注冊和注銷服務?
健康檢查:上遊如何感知下遊的健康情況?
無損升級:如何無損的進行服務升級?
變更分級:連接關係變更如何分級?
感知變化:上遊服務如何感知下遊服務列表的變化?
避免單點:如何避免服務注冊表局部故障?
調用時機
第一種方式是服務自己,在啟動或停止的時候注冊或注銷自己。這種方式服務的啟停對注冊表有很強的依賴,服務需要植入SDK,會產生植入成本,容易幹擾運維的可預期性,影響過載保護策略。
第二種方式就是采用第三方組件,有一個代理模塊去實施服務的注冊和注銷。我們使用這種方法的時候是利用agent通過SDK去操作。它的優點就是隻需在服務添加刪除時修改注冊表,不用植入SDK,對注冊表的依賴很弱,更容易進行運維效果監控,降低注冊表的負載。
健康檢查
健康檢查有服務端健康檢查和客戶端健康檢查兩種做法。
服務端健康檢查是服務自己做健康檢查,把健康結果反饋給服務注冊表。但這種方式對注冊表的依賴性很強,而且它自己的健康不一定是上遊看到的健康,所以結果未必準確,感知周期也很長。
客戶端健康檢查則是客戶端和服務端建立心跳和探活機製。它的優點是對注冊表的依賴性弱,感知周期短,準確性更高了。
無損升級
升級就意味著同時重啟的數量要比平時更多。對於上遊來說,不可訪問的服務也比日常要多,這就意味著失敗概率會變大。
重試雖然可以在一定程度上解決問題,但重試的副作用大,通常重試的次數會被嚴格限製。
而健康檢查雖然可以探測到不可用的下遊服務,但是健康檢測存在周期性。
後來我們又有了一個更好的做法::我們采取的方法是下遊服務退出過程中,先不會關閉服務讀寫端口,而僅僅關閉心跳端口,使服務處於"跛腳鴨"狀態,等上遊檢測到下遊心跳異常之後,將流量調度到其他服務實例,然後下遊服務實例再關閉讀寫端口退出,從而實現完全可控的無損服務升級。
變更分級
基於分布式鎖的個數,控製上遊變更的服務,但上遊分級方式具有隨機性,出錯情況損失偏大。
給下遊實例打tag,標記是否被上遊可見。
其實這種分級方式並不是很好,因為變更連接關係高危變更,一旦錯誤,損失很大。更好的方法是通過權重來控製下遊服務的流量比例。
感知變化
我們在實踐中發現zookeeper的通知機製不可靠,對注冊表依賴過重,發生局部故障,影響服務可用性。
而輪詢是一種比較可靠的機製。由agent周期性輪詢服務注冊表,引入版本節點,隻有版本變化時,才獲取全量數據,增強了運維的可預期性。
避免單點
對於IDC來說,它不希望由於服務發現係統局部故障而影響服務。
曆史上我們發生過多次zookeeper的局部故障,比如網絡抖動導致大量session超時所引起的通知機製。
把這些“不可靠”作為設計思路,我們把上遊持久化緩存下遊服務列表,作為容災手段。采用的是輪詢機製。
健康檢查是通過上遊服務探測下遊服務健康狀態。
應用範圍
目前的服務發現係統應用到了萬級的服務數量,支持了十萬級的服務實例數量,覆蓋了百度搜索引擎規模最大的indexer服務,數千個實例擴縮容的索引分布調整,分鍾級完成連接變更。
應用案例
相關對策
原有方案無論是ssdb、proxy還是master,都大量應用了對於zk通知的機製,同時還依賴zk的session機製做探活。
這個方案在實際應用中很容易出現網絡抖動session超時的故障,zk通知機製也容易丟消息,zk故障會導致服務整體不可用,平均1~2個月就會發生故障。
所以我們把它遷移到了NamingService,以解決上述問題。
總結和思考
總結
使用第三方組件進行注冊和注銷;
上遊探測下遊服務健康狀態;
通過服務分組實現無損升級;
連接關係變更一定要有分級機製;
使用輪詢而不使用通知;
以服務注冊不可靠作為假設條件。
思考
我們打算引入類似k8s的endpoint機製;通過控製流量比例更好的實現分級;提升易用性,成為通用的中間件。
以上就是我今天的分享,謝謝大家!
最後更新:2017-08-17 14:32:26