1.背景綜述
Qunar 的實時日志平台使用的是 ELK 架構,其中 Elasticsearch 叢集(以下簡稱:ES 叢集)和 kibana 平台在機房 A,Logstash 叢集在機房B。
目前機房 A 在使用過程中存在以下一些問題隐患:
- 機房 A 目前為飽和狀态,批量新增機器難以支援
- 機房 A 主要由 Hadoop、ES 叢集組成,業務互動會産生大量跨機房流量,峰值會影響到業務
基于上述因素,與 Ops 同僚溝通後,決定整體遷移 ES 叢集到機房 B。這樣不僅可以解決上述兩個問題,和寫入端的 Logstash 叢集也同在一個機房,網絡通信更有保障。
此文主要介紹 ES 叢集節點遷移實戰過程中的一些實踐與探索演進經驗,對于日常的平台開發與運維也能有所借鑒和參考。
2.遷移方案
2.1 ES日志平台架構
Qunar-ES 日志平台主要存儲全司實時日志,通過 filebeat、fluent-bit 等采集工具将日志采集到 kafka 後,由 Logstash、Flink 按照不同 topic 寫到對應的索引中。一個 appcode 的日志對應到 ES 就是一個索引。
其中 Logstash 層還負責日志資料的 filter 邏輯,平台這邊給業務使用者提供了專門的 logstash-debugger 來進行 logstash的filter 測試與開發。
kibana 對接 ES 叢集資料提供給全司,按照 space=>user=>role=>index pattern 的模式來管理使用者的權限。以下是整體的實時日志平台架構圖:
ES 日志叢集目前是公司最大的一個獨立 ES 叢集,文檔數達到了萬億級,存儲量也在 PB+,節點數(ES 節點非機器數)也在500+,如圖:
叢集使用了多種類型的節點,master 、data 節點獨立部署,角色分離,使用專門的 coordinate node 作為協調節點作為 data node 與外部請求的橋梁,在 coordinate node 外部增加了一層網關 gateway 層,直接接收使用者請求,可以對請求進行審計與處理。叢集架構圖如下:
2.2 遷移難點
- 如何保證遷移中的服務可用性與使用者無感覺
叢集規模大,寫入量大,使用範圍廣,遷移過程中,穩定和服務可用性是第一要務。如何保障穩定性是首先要解決的難點
- 如何提升遷移效率
遷移效率有兩個方面:
- 遷移的速度:主要取決于遷移政策和持續的調優。遷移的總資料在PB級,單機器(機械硬碟)也到了10TB+,優化遷移效率,提升速度是後續持續研究的重點。
- 遷移的人工成本:遷移過程中,每個流程環節都需要人工介入,如何能提升自動化率,降低人工成本,也是研究提高生産力的方向。
2.3 遷移方案
整體方案:按照機櫃梳理出機房A的機器順序,按批次進行節點資料遷移,将機器服務下線,搬遷到機房B中,重新部署,組網,并部署,啟用。反複執行,直到全部遷移完成。可以參考以下流程圖:
而從節點類型和服務次元來看,主要有以下幾類,也是按照從 Data Node依次往後進行遷移:
· Data Node
· Coordinate Node
· Master Node
· Kibana
· Service
本期遷移重點和難點都集中在資料節點的遷移,故而後續大量篇幅都在講解資料節點遷移的演進變化。
3.遷移過程
3.1 初步嘗試(11月)
做好以上前置準備事宜後,開始第一階段的遷移工作,此階段曆時1個月。此階段主要重點在于以下三件事:
a. 手動遷移節點
b. 調參保證穩定性
c. 整理問題,确立後續工作側重點
從機器清單(已排好序)中選取機器,以5台(單個機器有兩個資料節點)為機關,進行exclude._name 操作:
PUT _cluster/settings
{
"transient" :{
"cluster.routing.allocation.exclude._name" : "data1_node1,data2_node1,data1_node2,data2_node2,data1_node3,data2_node3,data1_node4,data2_node4,data1_node5,data2_node5"
}
}
Tips:
遷移節點資料最直接的方法就是官方提供的exclude操作,這個操作是叢集級的,可以直接通過"_cluster/settings"進行修改,執行操作後,叢集會将比對到的節點的分片reroute(同步)到其他節點上。通過exclude分為以下三種操作:
· exclude._name:将比對的node名稱對應的節點資料遷移,多個node名稱逗号分割
· exclude._ip:将比對的node的ip對應的節點資料遷移,多個ip用逗号分割
· exclude._host:将比對的node的主機名對應的節點資料遷移,多個host用逗号分割
運作一段時間,發現存在一些問題:
因為是日志叢集,屬于寫多讀少的場景,中午到晚上是寫入高峰,淩晨到早上屬于寫入低峰,在觀測監控和機器報警中發現,節點在寫入高峰時期會出現大量的load飙高情況(相較于exclude之前),而在低峰,相對要少很多,如圖:
appcode 日志堆積數也會有所上升:
分析後,總結原因有幾下幾點:
a.添加 exclude_name 後,叢集多了很多 relocating shards,此時會出現大量的分片遷移操作,通過_cat/recovery 可以看到期間的分片進行的過程。
b.白天叢集是寫入高峰,壓力不算小,此時還需要同步資料,會造成 exclude name 對應的節點,因為要大量的遷出資料,會進行大量的磁盤讀操作,同時,還有很多分片還在進行目前的寫入操作,磁盤 io 很容易趨近于100%(使用的是機械盤)。
c.遷入分片的節點也因為讀取量的飙升,導緻了磁盤的 io 上漲。繼而影響同步兩側的節點紛紛 load 飙高,影響的就是會有個别的 appcode 寫入堆積。
調整過程:
根據峰值調整 exclude_node 的批次量,做如下調整
- 高峰時期:調整到2個機器節點同時 exclude。
- 低峰時期:保持5個節點同時 exclude。
調整以後,除白天寫入尖峰會有一些 load 飙高外,基本趨于平穩,堆積也大大回落。
3.2 自動化遷移(11月~1月)
有了第一個階段的經驗,熟悉了節點遷移的基本流程和操作。以上作為自動化的前提準備,于是開始了相關的架構設計和實作工作,具體架構圖如下:
主要設計思路如下:
1. 判斷叢集目前狀态。達标才可以繼續下一步操作,否則就等下一次檢測。标準很簡單:
* status:叢集狀态為 Green
* load:叢集 load>30節點不超過7個;load>50的節點不能超過3個(基于日常叢集情況)
2. 判斷 relocating shards count:
* 哪些節點遷移完成:如有,則統計數量
* 目前在遷移的 shard 數量
如果有節點遷移完成,且正在遷移的 shard 數量在40以内,可以進行新節點批次遷移,否則說明尚有多數分片在同步中,需等待下一次判斷
3. 下線遷移完的機器節點。根據第二步得到的機器清單,下線前,需再次校驗是否機器節點無索引分片
4. 擷取下一批 exclude 的清單(順序)
5. 根據時間峰值進行 exclude(基于之前的經驗)
* 高峰:2個機器節點
* 低峰:5個機器節點
注:
*實際遷移的機器節點數為:需要遷移的節點數 X - 已經遷移完成的節點數 Y
*這樣可以保持系統一直遷移機器數一直穩定在峰值對應的數量
按照這樣的架構實作的自動化遷移,在第二個階段運作比較順暢,變化也是十分明顯:
- 節省人力成本(不用去手動操作),同時為第三個階段的優化架構留出了演進基礎
- 保證遷移節點數量保持恒定
3.3 疊代調優(1月~2月)
之前的第二個階段解決了自動化的問題,節省了遷移效率,在自動化穩定運作的同時,也在探索提升穩定性與遷移速率,在1~2月期間,主要做了以下幾個方面的探索與實踐
3.3.1 total_shards_per_node
index.routing.allocation.total_shards_per_node:設定單個索引在單個節點上最多的分片數(包括主副本)。預設無限量
調整原則:保證單個索引在單個節點上保留最少的分片數,以避免資料分片傾斜的情況,已提升整體穩定性。
total_shards_per_node 的調整邏輯如下:
total_shards_per_node: shard_num/(nodes_count * 0.95(buffer系數) * 0.5)
需要注意的是:
buffer 系數是一定要有的,否則一旦有節點當機故障,就會一批分片出現 unassigned 情況,無法配置設定。
索引設定可以使用 template 進行控制,友善控制與修改。
索引級個性化的 template 參考如下:
{
"order": 99,
"index_patterns": [
"log_appcode-*"
],
"settings": {
"index": {
"number_of_shards": "278",
"routing": {
"allocation": {
"total_shards_per_node": "2"
}
},
"refresh_interval": "60s"
}
},
"mappings": {
"properties": {
#索引獨立的結構
}
}
}
注:上面這個template 模闆設定的索引分片單個節點最多配置設定兩個分片。
3.3.2 node_left.delayed_timeout
index.unassigned.node_left.delayed_timeout : 節點脫離叢集後多久配置設定unassigned shards(預設1min),相當于延遲恢複配置設定多久的時間。
這個參數相當重要,尤其是大叢集中,節點當機重新開機時有發生,如果不做設定,節點對應的數百副本分片就會進行恢複操作,期間會耗費大量的 IO 資源,影響叢集穩定性。而且叢集重新開機後,還會進一步做 rebalance 以平衡分片。
索引恢複主要有6個階段,如下:
1.INIT:剛開始恢複的階段
2.INDEX:恢複Lucene檔案
3.VERIFY_INDEX:驗證Lucene index中是否有分片損壞
4.TRANSLOG:重放Translog,同步資料
5.FINALIZE:執行refresh操作
6.DONE:更新分片狀态,完成操作
當機器當機重新開機後,機器對應的所有分片會短暫成為 UNASSIGNED SHARD 狀态,預設60s後叢集 UNASSIGNED SHARD 進行恢複操作,此時會把原本當機機器的未配置設定分片(副本)配置設定到其餘節點,因為是副本分片同步,需要從主分片進行同步資料,比從本地恢複慢了不少,且極為影響性能。過程類似于:
基于此,針對 node_left 的設定做了兩次的嘗試:
a. index.unassigned.node_left.delayed_timeout: 120m
将所有的索引 template 設定延遲配置設定時間設定為120分鐘。
當遇到節點當機後,不會再次出現大量分片遷移的過程,當節點重新開機後,分片會從節點本地進行恢複,效率高,性能影響小。
但是如果是節點故障當機,無法啟動時,會出現在 delyed_timeout 時間到達後,進行集中大量的分片恢複,如果節點分片多,同樣會有性能方面的影響和損耗。
b. index.unassigned.node_left.delayed_timeout: random time
在調大延遲配置設定時間後,還會出現集中分片恢複的情況,主要是因為對于單一節點的索引分片都是同一時間變成的 unassigned,也會在同一時間進行恢複。
基于此,将 delayed_timeout 設定為随機數值,在建立索引的時候,設定為100~300min區間的随機數,類似如下:
delayed_timeout = random.randint(100, 300)
PUT /index/_settings
{
"settings": {
"index.unassigned.node_left.delayed_timeout": delayed_timeout
}
}
調整後,在故障當機觀測,會發現恢複分片是一個持續間斷過程,而非之前的突增突降。如圖對比:
3.3.3 單機器單節點遷移
資料節點的實體機的配置為:32core 128g 14TB(為主,還有9TB、18TB)
單實體機部署兩個節點(data1,data2)執行個體,每個節點占用16core 64g資源,磁盤共用。
之前兩個階段的遷移是以實體機為機關進行遷移,批次遷移多台實體機資料,期間會因為大量的資料同步傳輸導緻磁盤io問題,是以需要在高低峰進行批次調整,以保證穩定性。但是批次量無法提升,導緻速率不太理想。
此次更換為單機器單節點遷移,exclude_node 中隻選擇同批次機器的data1,等 data1節點遷移完成後,遷移 data2。cluster exclude 設定如下:
PUT _cluster/settings
{
"transient" :{
"cluster.routing.allocation.exclude._name" : "data1_node1,data1_node2,..."
}
}
使用單節點遷移後,單批次節點在高峰期可以增加50%,低峰時期增加80%。在遷移過程中,叢集整體寫入,與同步節點的 cpu、磁盤 io 均比較穩定,當 data1遷移完成後,批次節點的 load 整體會控制在10以内,穩定性得到相應的提升。
3.3.4 cluster_concurrent_rebalance
cluster.routing.allocation.cluster_concurrent_rebalance: 用來控制叢集内并發分片的 rebalance 數量,預設為2
ES叢集的 cluster_concurrent_rebalance 參數長期使用的在10(節點數多,增加分片的同步效率)
在遷移節點過程中,同步的節點會非常多,出現很多的 relocating shards,且同時還會有 rebalance 的分片,在遷移之後,還會繼續做 rebalance。
此處為了減少 rebalance 的頻率與周期,設定 cluster_concurrent_rebalance 為0,相當于一直都不做 rebalance。
但是如果長期不進行 rebalance,分片會出現傾斜不均衡的情況,基于此,進行了3.3.4 手動 reroute 操作,來調整分片的均衡。
注:
cluster.routing.rebalance.enable:none 可以等同于cluster.routing.allocation.cluster_concurrent_rebalance:0。都相當于不做任何的分片均衡
每周建立索引後,進行reroute
(1)rebalance 本身存在的問題
rebalance 節點主要有 decider 控制器來決定的,而非目前分片使用的情況,這樣會造成一個情況,機器在 rebalance 後整體分片數均衡,但是寫入不均衡(有些分片是當周分片正在寫入資料,有些分片是上周分片,均衡之後可能會出現一些節點的當周分片數很多,導緻寫入壓力大,磁盤 io 高,反而沒有達到真正的均衡)
現象是會有一些節點在高峰期出現持續高 load,磁盤 io 趨近100%的情況。不得不做一些手動的 reroute 分片,來緩解節點壓力,遇到持續增高,可能會出現 node_left 重新開機的現象。
(2)cluster_concurrent_rebalance為0帶來的問題
因為3.3.3 中将 cluster_concurrent_rebalance 調為0,叢集不會做分片均衡操作,新增索引分片會按照 decider 進行排程,最極端的情況會将某些分片數少的節點配置設定超過一倍的分片數。舉個例子:
周中新上的機器節點 node-300,到了周末統一建立索引的時候,由于 node-300基本沒有分片(除少數新增索引外),會有大量的分片建立到 node-300中。
ES 叢集建立完次周索引後,分片數在10w,資料節點數大緻為450,平均到單個資料節點的分片大緻為220+。而新周的索引分片數大約在5w+,對應的分片數為110+,而 node-300的新周索引分片數即為220+,相當于是其餘節點的1倍以上。
上述兩個現象直覺導緻的現象都是因為個别節點分片不均衡,導緻性能受到影響,繼而會出現 node_left 的情況。
分析了上述兩個原因,決定從寫入的分片均衡 來入手。
因為是日志叢集,索引是以周次元建立,每周日淩晨提前進行建立次周索引(tips:如果不提前建立,會在次周切換索引時,引發大量的 pending_tasks,造成叢集寫入大面積堆積),隻要保證次周寫索引的分片在索引節點均衡即可。
(3)reroute new shard 調整分片均衡
在建立完新周索引後,可以對分片進行調整,流程圖如下:
針對以上流程做一下簡要說明:
1.主要的思路是:計算次周總的分片數/可用資料節點,得到平均分片,然後将分片多的遷移到分片少的節點。
2.因為是空索引,遷移時間基本可以忽略不計。
3.需要注意的是可用資料節點,從_cluster/health 可以擷取到對應的可用 data node 數量,但是還需要将_cluster/settings exclude._name 中對應的節點數排除出去方是真實可用的數量。
4.同步完後,可以達到寫索引的平衡(整體分片數不一定均衡)。
執行完同步腳本後分片均衡,以上問題順利解決。
(4)reroute new node
以上所有的措施已經能解決最核心的兩個問題:穩定性、遷移速度。
按照當時遷移速度估算,可以在剩餘1個月内完成全部的節點遷移,但是是否有更快更好的方法做遷移麼?
在上個優化點 reroute new shard 調整分片均衡 中得到靈感,新分片遷移是很快的,因為沒有資料,基本不費時間且對性能沒有任何影響。那能否用于在遷移節點上來呢?答案是可以的:
在 reroute new shard 基礎上,做了改進,并根據機器配置,做了差異化的處理(包括遷移節點和平衡分片),設計圖如下:
以上設計圖有幾點需要了解:
1.順序:先進行節點遷移=》然後進行分片平衡
2.時間:一般會提前1-2天建立次周索引,可以在建立索引後進行以上流程操作
3.節點遷移增加新節點相當于是将需要遷移的分片遷移到新節點上,因為是新節點,基本上不會有 reroute 沖突
4.可以根據機器的配置進行門檻值的調整,比如遷移節點後計算節點分片門檻值為80(每個節點平均80個次周分片),可以将高配置的機器門檻值提高:
- 48c的機器 門檻值增加20%
- 32c的機器 門檻值降低20%
如果有 ssd 機器,可以在原有門檻值上進一步提升,也可以做點對點分片均衡調整,将高配置節點、分片數較少節點統一作為被同步節點,将配置低節點、分片數遠高于門檻值節點作為同步節點,進行 reroute。
分片均衡,可以參考以下用法:
POST _cluster/reroute
{
"commands": [
{
"move": {
"index": "log_appcode-2023.18",
"shard": 59,
"from_node": "data2_node1",
"to_node": "data2_node10"
}
}
]
}
在做完以上步驟後,等到次周開始,叢集寫入都切到了新的索引後,可以進行 exclude 節點操作,此時由于批次節點都沒有寫入索引,遷移同步分片會非常快,且對性能影響非常小。
總結:
- 用了這個方法,可以說,速度提升了2倍以上,并提前了一周多完成了節點的遷移。
- reroute new shard 思路還适用于平時的平台開發維護,後來也用到了 ES日志叢集的拆分工程中,至于 Qunar-ES 叢集拆分實踐,可以留做後續專門獨立做一個分享。
3.3.5 coordinate node遷移
coordinate node 主要用來做協調作用,負責接收叢集的讀寫請求,繼而傳遞到資料節點進行實際的資料互動。
本身協調節點不進行存儲,主要需要 cpu、記憶體的資源。
ES日志叢集的協調機器大緻在40+,分批次每周5台遷移即可,遷移完成,需要對 Logstash 的 output 端進行重刷服務。
Tips:
建議小叢集可以不用單獨的協調節點
大叢集協調節點建議如下配置(隻做協調作用):
協調節點數:資料節點數 比例建議為:1:8~10
如果有大批量的備用機器(可以沒有獨立硬碟)可以作為協調備份節點,可以先上對等批次的機器節點到叢集,重刷 Logstash 的 output 端連接配接,之後将對應數量的節點服務下線,這樣可以達到1~2批次内完成所有協調節點遷移工作。
3.3.6 master node遷移
master 節點遷移相對來說比較簡單,隻需要找到臨時機器部署在機房 B,部署好對應服務,把機房 A 的 master 服務下掉,把機房 B 的 new master 節點起來即可。
注:
- 唯一需要注意的點是,由于整個叢集的遷移是不停服務的,而 elasticsearch.yml 的 master 與 discovery 子產品配置的 master 選舉的節點清單已經寫的是機房 A 的機器節點,一旦用了機房 B 的 master 服務,是無法感覺對應的 node。
- master 節點需要一個一個遷移,如果低于需要的最小數量,叢集恐無法使用
- master 的 node 名稱感覺問題可以通過以下來做:
- 将 new master 節點 =》 host 到 old master 節點上,效果就是如下:
當然也可以通過負載和服務發現架構來實作動态調整 master 節點。
做完以上步驟,ES 叢集就全部遷移到新機房了,後續就是對應的服務遷移與适配。
4.總結
最終在近三個月的時間裡,不斷的嘗試中,完成了叢集整體遷移,并且提前了一周多的時間,也做到了零故障。
期間遇到元旦峰值,也得到了鍛煉和考驗。
總結下大規模 ES 叢集節點遷移主要的要點有以下:
戰略層面
- 制定遷移計劃:針對不同的節點類型制定不同的方案(提前制定好可預見的問題與應對方案,這點非常重要)
- 能用自動化代替人工的,盡量多走自動化,提升效率,複用性高,穩定性好
- 熟悉對應的底層原理與系統參數,可以更好的指導技術層面的優化與實踐
技術層面
- total_shards_per_node
- node_left.delayed_timeout
- 單機器單節點遷移
- reroute遷移演進
相信以上的經驗和一些技術要點,不僅在叢集節點遷移可以參考,同樣也适用與大規模叢集開發與維護。可以說,就是有了不斷的叢集平台維護開發的經驗與總結,才逐漸總結出各種優化方法。
小感想:
有時候系統性的優化或者方案,從來都不是一蹴而就的,都要通過不斷的嘗試與調整,在對系統原理的把控上,進行方案的優化,進而取得持續的進步。
5.參考文獻
- https://www.elastic.co/cn/blog/how-many-shards-should-i-have-in-my-elasticsearch-cluster
- https://www.elastic.co/guide/en/elasticsearch/reference/7.7/allocation-total-shards.html
- https://www.elastic.co/guide/en/elasticsearch/reference/7.7/delayed-allocation.html
- https://www.elastic.co/guide/en/elasticsearch/reference/7.7/index-modules-translog.html
- https://www.elastic.co/guide/en/elasticsearch/reference/7.7/cluster-reroute.html
- https://cloud.tencent.com/developer/article/1334743?cps_key=6a15b90f1178f38fb09b07f16943cf3e
- https://blog.csdn.net/laoyang360/article/details/108047071
作者介紹
許睿哲
2020年12月加入去哪兒網-資料平台團隊,目前主要負責公司的 esaas 雲服務與實時日志 ELK 平台的開發、維護與優化。主導參與了公司的es平台的SLA規則的制定與開發、 ES 架構更新遷移與jinkela叢集拆分等工作。
來源:微信公衆号:Qunar技術沙龍
出處:https://mp.weixin.qq.com/s/zpz6k4lXQlvvBx756hyWQA