滴滴 Elasticsearch 多集羣架構實踐

出品 | 滴滴技術
做者 |魏子珺node

圖片描述

Elasticsearch 是基於 Lucene 實現的分佈式搜索引擎,提供了海量數據實時檢索和分析能力。Elastic 公司開源的一系列產品組成的Elastic Stack,能夠爲日誌服務、搜索引擎、系統監控等提供簡單、易用的解決方案。mysql

滴滴 Elasticsearch 簡介
滴滴2016年初開始構建Elasticsearch平臺,現在已經發展到超過3500+Elasticsearch實例,超過5PB的數據存儲,峯值寫入tps超過了2000w/s的超大規模。sql

Elasticsearch在滴滴有着很是豐富的使用場景,例如線上核心的打車地圖搜索,客服、運營的多維度查詢,滴滴日誌服務等近千個平臺用戶。restful

超大的規模和豐富的場景給滴滴Elasticsearch平臺帶來了極大的挑戰,咱們在這期間積累了豐富經驗,也取得了一些成果。本文給你們分享下滴滴在Elasticsearch多集羣架構的實踐。架構

單集羣架構瓶頸
介紹單集羣架構瓶頸前,先來看下滴滴Elasticsearch單集羣的架構。app

滴滴Elasticsearch單集羣架構jvm

圖片描述

滴滴在單集羣架構的時候,寫入和查詢就已經經過Sink服務和Gateway服務管控起來。elasticsearch

| Sink服務
滴滴幾乎全部寫入Elasticsearch的數據都是經由kafka消費入到Elasticsearch。kafka的數據包括業務log數據、mysql binlog數據和業務自主上報的數據,Sink服務將這些數據實時消費入到Elasticsearch。tcp

最初設計Sink服務是想對寫入Elasticsearch集羣進行管控,保護Elasticsearch集羣,防止海量的數據寫入拖垮Elasticsearch,以後咱們也一直沿用了Sink服務,並將該服務從Elasticsearch平臺分離出去,成立滴滴Sink數據投遞平臺,能夠從kafka或者MQ實時同步數據到Elasticsearch、HDFS、Ceph等多個存儲服務。分佈式

有了多集羣架構後,Elasticsearch平臺能夠消費一份MQ數據寫入多個Elasticsearch集羣,作到集羣級別的容災,還能經過MQ回溯數據進行故障恢復。

| Gateway服務
全部業務的查詢都是通過Gateway服務,Gateway服務實現了Elasticsearch的http restful和tcp協議,業務方能夠經過Elasticsearch各語言版本的sdk直接訪問Gateway服務,Gateway服務還實現了SQL接口,業務方能夠直接使用SQL訪問Elasticsearch平臺。

Gateway服務最初提供了應用權限的管控,訪問記錄,限流、降級等基本能力,後面隨着平臺演進,Gateway服務還提供了索引存儲分離、DSL級別的限流、多集羣災備等能力。

| Admin服務
整個Elasticsearch平臺由Admin服務統一管控起來。Admin服務提供了索引的生命週期管理,索引容量自動規劃,索引健康分,集羣監控等豐富的平臺能力,以及爲Sink、Gateway服務提供索引、權限等元數據信息。

Elasticsearch單集羣瓶頸
隨着滴滴Elasticsearch平臺規模的快速發展,Elasticsearch集羣愈來愈大,最大的時候,是由幾百臺物理機組成集羣,當時集羣共 3000+ 的索引,超過了 50000 個 shard,集羣總容量達到了PB級別。超大的Elasticsearch集羣面臨了很大的穩定性風險,這些風險主要來自於如下三個方面:

  • Elasticsearch架構瓶頸
  • 索引資源共享風險
  • 業務場景差別大

Elasticsearch架構瓶頸
Elasticsearch架構在集羣變大到必定的規模會遇到瓶頸,瓶頸主要跟Elasticsearch任務處理模型有關。

Elasticsearch看起來是p2p架構,但實際上,仍然是中心化的分佈式架構。整個集羣只有一個active master。master負責整個集羣的元數據管理。集羣的全部元數據保存在ClusterState對象中,主要包括全局的配置信息、索引信息和節點信息。只要元數據發生修改,都得由master完成。

Elasticsearchmaster的任務處理是單線程完成的,每次處理任務,涉及到ClusterState的改動,都會將最新的ClusterState對象publish給集羣的所有節點,並阻塞等待所有節點接受到變動消息,處理完變動任務後,才完成本次任務。

這樣的架構模型致使在集羣規模變大的時候出現很嚴重的穩定性風險。

  • 若是有節點假死,好比jvm內存被打滿,進程還存活着,響應master任務時間會很長,影響單個任務的完成時間。
  • 有大量恢復任務的時候,因爲master是單線程處理的,全部任務須要排隊處理,產生大量的pending_tasks。恢復時間變得很長。
  • Elasticsearch的任務分了優先級,例如put-mapping任務優先級低於建立、恢復索引,若是一些業務上低優先級索引在恢復,正常索引有新字段寫入時會被阻塞。
  • master任務處理模型,在任務執行完成後,會回調大量listener處理元數據變動。其中有些回調邏輯在索引、shard膨脹後,會出現處理緩慢的問題,當shard膨脹到5-6w時,一些任務處理須要8-9s的時間,嚴重影響了集羣的恢復能力。

針對這些問題,Elasticsearch也在不斷優化,針對相同類型的任務,好比put-mapping任務,master會一次性處理全部堆積在隊列裏的相同任務。ClusterState對象只傳遞diff內容,優化回調listener模塊的處理耗時環節等等。

可是因爲整個集羣的任務都集中在一個master的一個線程中處理,在線程中須要同步元數據變動給集羣的每一個節點,並阻塞等待所有節點同步完成。這個模型在集羣規模不斷膨脹時,穩定性會不斷降低。

| 索引資源共享風險
Elasticsearch索引是由多個shard組成,master會動態給這些shard分配節點資源。不一樣的索引會存在資源混部的狀況。
圖片描述

Elasticsearch經過Shard Allocation Awareness的設計,能夠將集羣的節點按集合劃分紅不一樣的rack。在分配索引時能夠指定rack列表,這樣索引就只會分配在指定rack對應的節點列表中,從而作到物理資源的隔離。

可是實際使用中,不少容量小的索引因爲佔用資源有限,會混部在一些節點中。這種狀況下,會由於個別索引的查詢、寫入量飆升,而影響到其餘索引的穩定性。若是出現了節點故障,就會影響到整個集羣的穩定性。

整個集羣master、clientnode資源是共享的,master風險前面已經單獨說起,clientnode共享帶來的gc、抖動、異常問題都會影響到集羣內的所有索引。

| 業務場景差別大
Elasticsearch適用的業務場景差別特別大。

  • 針對線上核心的入口搜索,通常按城市劃分索引後,索引容量不大,數據沒有實時寫入或者實時寫入tps很小,好比地圖poi數據採用離線更新的方式,外賣商家、菜品寫入量也很小。可是查詢的qps很高,查詢對rt的平均時間和抖動狀況要求很高。
  • 針對日誌檢索的的場景,實時寫入量特別大,有些索引甚至超過了100w/s的tps,該場景對吞吐量要求很高,但對查詢qps和查詢rt要求不高。
  • 針對binlog數據的檢索,寫入量相比日誌會小不少,可是對查詢的複雜度、qps和rt有必定的要求。
  • 針對監控、分析類的場景,聚合查詢需求會比較多,對Elasticsearch內存壓力較大,容易引發節點的抖動和gc。

這些場景各異,穩定性、性能要求各不相同的場景,一個Elasticsearch集羣即便使用各類優化手段,很難所有知足需求,最好的方式仍是按業務場景劃分Elasticsearch集羣。

多集羣挑戰
正是單集羣面臨了很是大的穩定性風險,咱們開始規劃多集羣的架構。咱們在設計多集羣方案的時候,指望對業務方是零感知的。

寫入仍是通過kafka,Sink服務能夠將不一樣topic的數據入到不一樣的Elasticsearch集羣。查詢繼續經過Gateway服務,並且業務方仍然像以前同樣傳遞索引名稱,而無需感知到平臺內部的索引分佈。全部的索引在不一樣集羣的分佈細節,均由Gateway服務屏蔽。

整個改造最大的挑戰在於查詢方式的兼容。Elasticsearch查詢索引的方式很是靈活,能夠支持*號做爲通配符匹配。這樣一個索引query可能查詢的是多個索引,好比有以下3個索引:

  • index_a
  • index_b
  • index_c

使用index*查詢的時候,能夠同時查詢到index_a、index_b、index_c三個索引。 Elasticsearch這種實現方式很是簡單,因爲一次query最終查詢的是多個shard的數據,因此不管對於具體的索引,仍是模糊的索引,都是先根據索引名稱獲得shard列表,再將多個shard的query結果merge到一塊兒返回。

這樣的使用方式,對於多集羣方案就會遇到問題,好比index_a在A集羣,index_b在B集羣、index_c在C集羣,對於index*的query,就沒法在一個集羣上完成。

tribenode介紹

通過調研,咱們發現Elasticsearchtribenode特性能夠很好的知足多集羣查詢的特性。tribenode的實現很是巧妙。org.elasticsearch.tribe包下只有三個文件,核心類是TribeService。tribenode的核心原理就是merge每一個集羣的ClusterState對象成一個公共的ClusterState對象,ClusterState包含了索引、shard和節點數據分佈表。而Elasticsearch的工做邏輯都是基於ClusterState元數據驅動的,因此對外看起來就是一個包含所有索引的的clientnode。

圖片描述

tribenode經過配置多個Elasticsearch集羣地址,而後以clientnode角色分別鏈接每一個集羣,每一個集羣看起來會多了一個clientnode。tribenode經過該clientnode角色獲取到集羣的ClusterState信息,並綁定listener監聽ClusterState變化。tribenode將獲取的全部集羣的ClusterState信息merge到一塊兒,造成一個對外部訪問使用的ClusterState對象,對外提供服務。tribenode除了註冊listener和merge ClusterState,其餘的全部邏輯都是複用了clientnode的代碼。

能夠看到tribenode的優勢:

  • 可以知足多集羣訪問的需求,對外使用是透明的。
  • 實現的簡單、優雅,可靠性有保證。

同時tribenode有些不足的地方:

  • tribenode必須以clientnode加入到每一個Elasticsearch集羣,master的變動任務必須等待tribenode的迴應才能繼續,可能影響到原集羣的穩定性。
  • tribenode不會持久化ClusterState對象,重啓時須要從每一個Elasticsearch集羣獲取元數據。而在獲取元數據期間,tribenode就已經可以提供訪問,會致使查詢到還在初始化中的集羣索引訪問失敗。
  • tribenode鏈接的集羣多了,初始化會變得很慢。針對該缺陷,咱們平臺在重啓某個tribenode集羣時,將Gateway訪問該集羣的所有流量切到備份tribenode集羣解決。

若是多個集羣有相同的索引名稱,tribenode只能設置一種perfer規則:隨機、丟棄、prefer指定集羣。這可能帶來查到不符合預期的異常。滴滴Elasticsearch平臺經過統一管控索引,避免了同一個索引名稱出如今tribenode鏈接的多個集羣中。

正是tribenode有了這些瑕疵,Elasticsearch在高版本引入了Cross ClusterSearch的設計,Cross Cluster不會以節點的形式鏈接到其餘集羣,只是將請求代理。目前咱們還在評估Cross Cluster的方案,這裏不展開介紹。

多集羣架構拓撲
最終改造後,咱們的集羣架構拓撲以下:

圖片描述

按照不一樣的應用場景,平臺將Elasticsearch集羣劃分紅四種類型,Log集羣、Binlog集羣、文檔數據集羣、獨立集羣。公共集羣通常最多100臺datanode爲基準組成一個集羣。咱們利用滴滴雲實現了集羣的自動化部署和彈性擴縮容,能夠很方便的水平擴展集羣。

Elasticsearch集羣前面是多組tribenode集羣,主要是爲了解決tribenode的穩定性問題。

Gateway會同時鏈接tribenode集羣和Elasticsearch集羣,根據應用訪問的索引列表,配置應用訪問的集羣名稱,Gateway根據集羣名稱,將請求代理到指定集羣訪問,若是訪問的是tribenode集羣,則該應用能夠訪問到多個集羣的索引。

Admin服務則管控了全部的Elasticsearch集羣,以及索引和集羣的對應關係。一系列功能都針對多集羣作了改造。

Sink服務已經從Elasticsearch平臺分離出去,成立DSink數據投遞平臺,DSink Manager負責管理DSink節點,DSink Manager從Elasticsearch Admin服務獲取索引的元數據信息,下發給對應的DSink節點。

多集羣架構實踐總結

| 多集羣架構收益
Elasticsearch多集羣架構改造給Elasticsearch平臺帶來了以下收益:

  • Elasticsearch平臺的隔離性能夠從物理節點級別上升到Elasticsearch集羣級別。對於核心的線上應用,可使用獨立的Elasticsearch集羣支持。
  • 不一樣類型的數據按集羣劃分,避免相互影響,減少了故障的影響面,對平臺穩定性帶來極大的提高。
  • Elasticsearch平臺的擴展能力進一步提高,經過新增集羣能夠很好的作到水平擴展。
  • 多集羣架構最終作到了對業務方無感知,業務看起來,Elasticsearch平臺就像一個無限大的Elasticsearch集羣,而無需感知索引真實的集羣分佈。

| 多集羣架構實踐經驗
滴滴Elasticsearch平臺多集羣的架構已經演進了一年半時間,這期間也遇到一些多集羣架構帶來的挑戰。
tribenode穩定性挑戰:

  • 隨着集羣數量愈來愈多,前面提到的tribenode不足愈來愈明顯,好比初始化的時間愈來愈長等等。咱們採起的應對策略是部署多組tribenode集羣,有幾組鏈接全量的集羣,互爲災備,有幾組只鏈接核心的一些集羣,用做更爲重要的跨集羣訪問場景。
  • tribenode的ClusterState元數據包含了太多的索引和shard,Elasticsearch的search邏輯在有些case處理下容易出現耗時過長的狀況。Elasticsearch在client接收到search請求時,是在netty的io線程中完成請求轉發給每一個shard的,低版本的Elasticsearch尚未限制一次query的shard數量,在一些複雜的模糊索引匹配shard的邏輯中,以及給每一個shard發送query請求時,會出現較高的耗時,可能有超過1-2s的case,這會影響到該netty worker上的其餘的請求,形成部分響應飆高的狀況。咱們優化了tribenode search流程中一些索引、shard膨脹以後的耗時邏輯,解決了該問題。

多集羣配置、版本統一的挑戰:

  • 在只有一個集羣的時候,平臺只用維護一份集羣的配置和版本。當集羣數量增多後,不一樣集羣間的_cluster
    settings信息會出現部分差別,這些差別,可能會致使集羣間的負載不均,恢復速度過快或者過慢等問題,每一個集羣還有一份基礎的索引模板配置,這裏面也出現了部分差別。這個問題目前咱們還在解決中,咱們計劃將Admin服務分離成索引管理服務和集羣管理服務,集羣管理會專一於集羣版本、配置、部署、擴容、監控等方面對Elasticsearch集羣進行更全面的管控。
  • 咱們作的一些Elasticsearch源碼優化,會前後在部分集羣上線,這樣致使了集羣間的版本混亂的問題。咱們的解決方案是在Elasticsearch和Lucene內增長內部的版本號,經過公司內部的發佈系統,發佈Elasticsearch的更新,後續集羣管理服務會將集羣的版本管理起來。

多集羣間容量均衡的挑戰:

  • 咱們主要從跨集羣索引遷移和容量規劃解決集羣間容量均衡的挑戰,在單Elasticsearch集羣的時候,數據遷移能夠依賴Elasticsearch的rebalance能力完成。在使用多集羣架構後,平臺內部的Elasticsearch集羣會出現資源分配不均的問題,例若有些索引容量增加的很快,致使所在集羣的資源緊張,有些索引數據減小,不須要佔用太多資源,致使集羣資源空閒。因而產生了索引跨集羣遷移的需求。針對這個需求,咱們經過給索引添加版本號,解決了索引跨集羣遷移問題。以後咱們有文章會詳細的介紹該方案。
  • 滴滴Elasticsearch平臺實現了索引容量的自動規劃,解決了集羣間的容量均衡。Elasticsearch平臺能夠動態的規劃索引的容量。當一個集羣容量規劃不足時,平臺能夠動態的遷移一部分索引到空閒的集羣中。新的索引接入需求會優先接入在空閒的集羣資源中。滴滴Elasticsearch平臺是如何實現索引容量的自動規劃,也請期待後續的分享。

總結滴滴的多集羣架構,最初是爲了解決Elasticsearch單集羣架構的瓶頸。爲了支持多集羣架構,後面的不少組件都須要考慮鏈接多個集羣的場景,給平臺架構帶來了必定的複雜性。可是多Elasticsearch集羣帶來的穩定性和隔離性的提高,它所帶來的收益遠遠大於架構的複雜性。改形成多集羣架構後,咱們扛住了Elasticsearch平臺規模爆炸式增加,Elasticsearch平臺的規模翻了5倍多,多集羣架構很好的支撐了業務的快速發展。

相關文章
相關標籤/搜索