支撐百度搜尋引擎99.995%可靠名字服務架構設計

IT大咖說發表於2019-03-04
內容來源:2016年12月16日,鄭然在“GIAC 全球網際網路架構大會”進行《支撐百度搜尋引擎99.995%可靠名字服務架構設計》演講分享。IT大咖說作為獨家視訊合作方,經主辦方和講者審閱授權釋出。
閱讀字數:2783 | 4分鐘閱讀

支撐百度搜尋引擎99.995%可靠名字服務架構設計

摘要

百度搜尋引擎是全球最大的中文搜尋引擎,致力於向人們提供"簡單,可依賴"的資訊獲取方式。百度網頁搜尋部架構師鄭然為我們分享支撐百度搜尋引擎的可靠名字服務架構設計。

嘉賓演講視訊地址:t.cn/R9tkj7F

搜尋引擎的挑戰

機器數量多,服務數量大:我們有數萬臺伺服器,數十萬個服務,分佈在多個IDC。

服務變更多,變更資料大:每天幾十萬次變更,每週10P量級的檔案更新,千餘人並行開發上百個模組。

檢索流量大,穩定性要高:每秒數萬次請求,滿足99.995%的可用性,極短時間的故障都可能引發大量的拒絕。

服務發現的原理

什麼是服務發現

服務上游如何找到下游;服務上游如何負載均衡;下游掛了上游如何感知。

客戶端服務發現

所有服務下游自行向服務登錄檔中進行註冊,同時服務上游整合登錄檔的客戶端,查詢登錄檔以獲取服務下游列表。服務上游整合負載均衡器,實施負載均衡。

服務端服務發現

服務端服務發現和客戶端服務發現的區別就在於,服務端服務發現所有服務上游的請求都是通過閘道器去查詢。

服務發現元件

服務發現主要由服務登錄檔、登錄檔客戶端和負載均衡組成。

服務登錄檔是分散式的儲存,持久化服務地址和自定義屬性,服務名字全域性唯一。

登錄檔客戶端支援對登錄檔的增刪改查,支援高併發高吞吐,對延遲的要求不太高,讀多寫少。

負載均衡對於整個服務系統來說是一個不可或缺的元件。它根據負載選擇某個服務,剔除和探活故障服務。

關鍵技術與實踐難點

Eden架構藍圖

支撐百度搜尋引擎99.995%可靠名字服務架構設計

Eden是百度網頁搜尋部自行研發的基於百度matrix叢集作業系統的PaaS平臺。它主要負責服務的部署、擴縮容、故障恢復等一系列服務治理的相關工作。底層是基礎設施層,包括監控、故障檢測以及matrix叢集作業系統。

Eden由三部分組成,第一部分是總控服務,分為InstanceMgr和NamingService。底層有多個agent來執行總控下發的命令。所有的源資料儲存在zookeeper上,並提供了命令列、web之類的介面來使用。還有一個機器維修仲裁的元件,根據故障型別、服務狀態來決策機器的維修,同時提供了日誌的收集分析,和一個模擬的測試平臺。

在這之上是job engine層,提供了封裝日常服務變更的操作,包括升級、資料的變更、服務擴容、故障例項的遷移等,在這層上做了抽象。

最上面是一些託管的服務,有網頁圖片搜尋服務、度祕服務、和資訊流。

服務發現元件

支撐百度搜尋引擎99.995%可靠名字服務架構設計

對於一個IDC來說,我們會部署一套NamingService,agent複用的是Eden的agent。

服務發現不可避免的是要支援跨機房的服務發現機制,必須要有跨機房查詢的功能,我們就做了一套遠端的跨機房查詢,上層提供了SDK介面把這些過程封裝起來。

為了支援跨機房一定要APP的ID或者名字必須要全域性唯一。

技術難點

我覺得一個真正能夠線上上穩定執行的服務發現系統必須要解決以下六個問題:

呼叫時機:誰來向服務登錄檔註冊和登出服務?

健康檢查:上游如何感知下游的健康情況?

無損升級:如何無損的進行服務升級?

變更分級:連線關係變更如何分級?

感知變化:上游服務如何感知下游服務列表的變化?

避免單點:如何避免服務登錄檔區域性故障?

呼叫時機

第一種方式是服務自己,在啟動或停止的時候註冊或登出自己。這種方式服務的啟停對登錄檔有很強的依賴,服務需要植入SDK,會產生植入成本,容易干擾運維的可預期性,影響過載保護策略。

第二種方式就是採用第三方元件,有一個代理模組去實施服務的註冊和登出。我們使用這種方法的時候是利用agent通過SDK去操作。它的優點就是隻需在服務新增刪除時修改登錄檔,不用植入SDK,對登錄檔的依賴很弱,更容易進行運維效果監控,降低登錄檔的負載。

健康檢查

健康檢查有服務端健康檢查和客戶端健康檢查兩種做法。

服務端健康檢查是服務自己做健康檢查,把健康結果反饋給服務登錄檔。但這種方式對登錄檔的依賴性很強,而且它自己的健康不一定是上游看到的健康,所以結果未必準確,感知週期也很長。

客戶端健康檢查則是客戶端和服務端建立心跳和探活機制。它的優點是對登錄檔的依賴性弱,感知週期短,準確性更高了。

無損升級

升級就意味著同時重啟的數量要比平時更多。對於上游來說,不可訪問的服務也比日常要多,這就意味著失敗概率會變大。

重試雖然可以在一定程度上解決問題,但重試的副作用大,通常重試的次數會被嚴格限制。

而健康檢查雖然可以探測到不可用的下游服務,但是健康檢測存在週期性。

後來我們又有了一個更好的做法::我們採取的方法是下游服務退出過程中,先不會關閉服務讀寫埠,而僅僅關閉心跳埠,使服務處於"跛腳鴨"狀態,等上游檢測到下游心跳異常之後,將流量排程到其他服務例項,然後下游服務例項再關閉讀寫埠退出,從而實現完全可控的無損服務升級。

變更分級

基於分散式鎖的個數,控制上游變更的服務,但上游分級方式具有隨機性,出錯情況損失偏大。

給下游例項打tag,標記是否被上游可見。

其實這種分級方式並不是很好,因為變更連線關係高危變更,一旦錯誤,損失很大。更好的方法是通過權重來控制下游服務的流量比例。

感知變化

我們在實踐中發現zookeeper的通知機制不可靠,對登錄檔依賴過重,發生區域性故障,影響服務可用性。

而輪詢是一種比較可靠的機制。由agent週期性輪詢服務登錄檔,引入版本節點,只有版本變化時,才獲取全量資料,增強了運維的可預期性。

避免單點

對於IDC來說,它不希望由於服務發現系統區域性故障而影響服務。

歷史上我們發生過多次zookeeper的區域性故障,比如網路抖動導致大量session超時所引起的通知機制。

把這些“不可靠”作為設計思路,我們把上游持久化快取下游服務列表,作為容災手段。採用的是輪詢機制。

健康檢查是通過上游服務探測下游服務健康狀態。

應用範圍

目前的服務發現系統應用到了萬級的服務數量,支援了十萬級的服務例項數量,覆蓋了百度搜尋引擎規模最大的indexer服務,數千個例項擴縮容的索引分佈調整,分鐘級完成連線變更。

應用案例

支撐百度搜尋引擎99.995%可靠名字服務架構設計

相關對策

原有方案無論是ssdb、proxy還是master,都大量應用了對於zk通知的機制,同時還依賴zk的session機制做探活。

這個方案在實際應用中很容易出現網路抖動session超時的故障,zk通知機制也容易丟訊息,zk故障會導致服務整體不可用,平均1~2個月就會發生故障。

所以我們把它遷移到了NamingService,以解決上述問題。

總結和思考

支撐百度搜尋引擎99.995%可靠名字服務架構設計

總結

使用第三方元件進行註冊和登出;

上游探測下游服務健康狀態;

通過服務分組實現無損升級;

連線關係變更一定要有分級機制;

使用輪詢而不使用通知;

以服務註冊不可靠作為假設條件。

思考

我們打算引入類似k8s的endpoint機制;通過控制流量比例更好的實現分級;提升易用性,成為通用的中介軟體。

以上就是我今天的分享,謝謝大家!

支撐百度搜尋引擎99.995%可靠名字服務架構設計


相關文章