1. 程式人生 > 實用技巧 >ElasticSearch多叢集構架實戰

ElasticSearch多叢集構架實戰

單叢集構架瓶頸:
在這裡插入圖片描述
單叢集構架,寫入和查詢分別通過Sink服務和Gateway服務管控起來。

Sink服務:
所有的寫入ElasticSearch的資料都是經由Kafka消費入到ElasticSearch。
Kafka業務資料包括 log資料,Binlog資料和業務自主上報資料,Sink服務將這些資料實時消費入到ElasticSearch
Sink服務設計是想對寫入ElasticSearch叢集進行管控,保護ElasticSearch叢集,防止海量的資料寫入拖垮ElasticSearch
可以從Kafka或者Mq實時同步資料到ES,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服務提供索引,許可權等元資料資訊。

ES單叢集瓶頸:
叢集越來越大,當叢集共有3000+索引,超過了50000個Shard,叢集總容量達到了PB級別。

風險主要來自於一下3個方面:
ElasticSearch構架瓶頸
索引資源共享風險
業務場景差異大

ElasticSearch構架瓶頸
ES看起來是個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對應的節點列表,從而做到物理資源的隔離。

但是實際使用中,很多容量小的索引由於佔用資源有限,會混在一些節點中,這種情況下,會因為個別索引的查詢,寫入量飆升,而影響到其他索引的穩定性。如果出現了節點故障,就會影響到整個叢集的穩定性。

業務場景差異大
ElasticSearch適用的業務場景差異特別大:

  • 針對線上核心入口搜尋,一般按城市劃分喉,索引容量不大,資料沒有實時寫入or實時寫入TPS很小
  • 針對日誌檢索的場景,實時寫入量特別大,有些索引甚至超過了100w/s的TPS,該場景對雲餘量要求很高,但對QPS和查詢RT要求不高
  • 針對Binlog資料的檢索,寫入量相比日誌會小很多,但是對查詢的複雜度,QPS和RT有一定的要求
  • 這對監控,分析類的場景,聚合查詢需求會比較多,對ElasticSearch記憶體壓力比較大,容易引起節點的抖動和GC。

這些場景個億,穩定性,效能要求各不相同,一個ElasticSearch叢集即使使用各種優化手段,很難全部滿足需求,最好還是按照業務場景劃分ElasticSearch叢集

多叢集挑戰
最大挑戰在於查詢方式的相容。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介紹
特性可以很好的滿足多叢集查詢的特性
Trienode 中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到一起,形成一個對外部訪問使用的Cluster物件,對外提供服務。
Tribenode 除了註冊 Listener 和 Merge ClusterState,其他的所有邏輯都是複用了 Clientnode 的程式碼。

優點:
能夠滿足多叢集訪問的需求,對外使用是透明的。
實現的簡單、優雅,可靠性有保證。
不足:

  • Tribenode 必須以 Clientnode 加入到每個 Elasticsearch 叢集,Master 的變更任務必須等待 Tribenode 的迴應才能繼續,可能影響到原叢集的穩定性。
  • Tribenode 不會持久化 ClusterState 物件,重啟時需要從每個 Elasticsearch 叢集獲取元資料。而在獲取元資料期間,Tribenode 就已經能夠提供訪問,會導致查詢到還在初始化中的叢集索引訪問失敗。
  • Tribenode 連線的叢集多了,初始化會變得很慢。針對該缺陷,我們平臺在重啟某個 Tribenode 叢集時,將 Gateway 訪問該叢集的全部流量切到備份 Tribenode 叢集解決。
  • 如果多個叢集有相同的索引名稱,Tribenode 只能設定一種 Perfer 規則:隨機、丟棄、Prefer 指定叢集。這可能帶來查到不符合預期的異常。
  • Elasticsearch 平臺通過統一管控索引,避免了同一個索引名稱出現在 Tribenode 連線的多個叢集中。

多叢集架構拓補:
在這裡插入圖片描述
平臺將 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 平臺多叢集的架構已經演進了一年半時間,這期間也遇到一些多叢集架構帶來的挑戰。

①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 平臺可以動態的規劃索引的容量。當一個叢集容量規劃不足時,平臺可以動態的遷移一部分索引到空閒的叢集中。