內容來源: 2016年12月16日,鄭然在「GIAC 全球互聯網架構大會」進行《支撐百度搜索引擎99.995%可靠名字服務架構設計》演講分享。IT大咖說做爲獨家視頻合做方,經主辦方和講者審閱受權發佈。
閱讀字數:2783 | 4分鐘閱讀
百度搜索引擎是全球最大的中文搜索引擎,致力於向人們提供"簡單,可依賴"的信息獲取方式。百度網頁搜索部架構師鄭然爲咱們分享支撐百度搜索引擎的可靠名字服務架構設計。html
機器數量多,服務數量大:咱們有數萬臺服務器,數十萬個服務,分佈在多個IDC。
web
服務變動多,變動數據大:天天幾十萬次變動,每週10P量級的文件更新,千餘人並行開發上百個模塊。
小程序
檢索流量大,穩定性要高:每秒數萬次請求,知足99.995%的可用性,極短期的故障均可能引起大量的拒絕。緩存
全部服務下游自行向服務註冊表中進行註冊,同時服務上游集成註冊表的客戶端,查詢註冊表以獲取服務下游列表。服務上游集成負載均衡器,實施負載均衡。服務器
服務端服務發現和客戶端服務發現的區別就在於,服務端服務發現全部服務上游的請求都是經過網關去查詢。網絡
服務發現主要由服務註冊表、註冊表客戶端和負載均衡組成。session
服務註冊表是分佈式的存儲,持久化服務地址和自定義屬性,服務名字全局惟一。架構
註冊表客戶端支持對註冊表的增刪改查,支持高併發高吞吐,對延遲的要求不過高,讀多寫少。併發
負載均衡對於整個服務系統來講是一個不可或缺的組件。它根據負載選擇某個服務,剔除和探活故障服務。負載均衡
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機制;經過控制流量比例更好的實現分級;提高易用性,成爲通用的中間件。
以上就是我今天的分享,謝謝你們!