1. 程式人生 > >大規模Elasticsearch叢集管理心得

大規模Elasticsearch叢集管理心得

【攜程旅行網 吳曉剛】
 ElasticSearch目前在網際網路公司主要用於兩種應用場景,其一是用於構建業務的搜尋功能模組且多是垂直領域的搜尋,資料量級一般在千萬至數十億這個級別;其二用於大規模資料的實時OLAP,經典的如ELKStack,資料規模可能達到千億或更多。 這兩種場景的資料索引和應用訪問模式上差異較大,在硬體選型和叢集優化方面側重點也會有所不同。一般來說後一種場景屬於大資料範疇,資料量級和叢集規模更大,在管理方面也更有挑戰。

應Medcl大大的邀請,為ES中文社群做今年的Advent開篇,分享一下我在管理自家公司用於日誌分析的ES叢集方面的一點心得,蜻蜓點水,泛泛而談,希望大方向上能對大家提供一些幫助。

這裡的自家,即是攜程旅行網。從2013年開始接觸ES,我們團隊先後實踐過0.9.x -> 5.0.0中間各個版本,從最初只用於運維內部IIS日誌的分析,到如今支援IT、呼叫中心、安全、測試、業務研發等多個部門超過200種日誌型資料的實時檢索與分析。 一路走來,愉悅了大家,也死磕了自己。

目前我們最大的日誌單叢集有120個data node,運行於70臺物理伺服器上。資料規模如下:

  • 單日索引資料條數600億,新增索引檔案25TB (含一個複製片則為50TB)
  • 業務高峰期峰值索引速率維持在百萬條/秒
  • 歷史資料保留時長根據業務需求制定,從10天 - 90天不等
  • 叢集共3441個索引、17000個分片、資料總量約9300億, 磁碟總消耗1PB
  • Kibana使用者600多人, 每日來自Kibana和第三方的API呼叫共63萬次
  • 查詢響應時間百分位 75%:0.160s  90%:1.640s 95%:6.691s 99%:14.0039s


運維這樣大規模的ES叢集,有哪些值得注意的地方?

一. 必不可少的工具
工欲善其事必先利其器,從一開始,哪怕就只有幾個node,就應該使用分散式配置管理工具來做叢集的部署。隨著應用的成熟,叢集規模的逐步擴大,效率的提升會凸顯。 官方提供了ES Puppet Module和Chef Cookbook,熟悉這兩個工具的同學可以直接拿過來用。 我們自己則是採用的Ansible,編寫了一套Playbook來達到類似的效果。 用熟這類工具,對於叢集的初始部署,配置批量更改,叢集版本升級,重啟故障結點都會快捷和安全許多。
第二個必備利器就是sense外掛。通過這個外掛直接呼叫叢集的restful API,在做叢集和索引的狀態檢視,索引配置更改的時候非常方便。語法提示和自動補全功能更是實用,減少了翻看文件的頻率。在Kibana5裡面,sense已經成為一個內建的控制檯,無需額外安裝。

二. 硬體配置
我們採用的是32vcoreCPU + 128GB RAM的伺服器,磁碟配置大部分伺服器是12塊4TB SATA機械磁碟做的Raid0,少部分機器是剛上了不久的6塊800GB SSD raid0,主要目的是想做冷熱資料分離,後面談到叢集架構的時候,再進一步解釋一下如何利用硬體資源。

三. 叢集的管理

  1. 首先很有必要對ES的結點做角色劃分和隔離。大家知道ES的data node除了放資料以外,也可以兼任master和client的角色,多數同學會將這些角色混入到data node。然而對於一個規模較大,使用者較多的叢集,master和client在一些極端使用情況下可能會有效能瓶頸甚至記憶體溢位,從而使得共存的data node故障。data node的故障恢復涉及到資料的遷移,對叢集資源有一定消耗,容易造成資料寫入延遲或者查詢減慢。如果將master和client獨立出來,一旦出現問題,重啟後幾乎是瞬間就恢復的,對使用者幾乎沒有任何影響。另外將這些角色獨立出來的以後,也將對應的計算資源消耗從data node剝離出來,更容易掌握data node資源消耗與寫入量和查詢量之間的聯絡,便於做容量管理和規劃。
  2. 避免過高的併發,包括控制shard數量和threadpool的數量。在寫入量和查詢效能能夠滿足的前提下,為索引分配儘量少的分片。分片過多會帶來諸多負面影響,例如:每次查詢後需要彙總排序的資料更多;過多的併發帶來的執行緒切換造成過多的CPU損耗;索引的刪除和配置更新更慢Issue#18776; 過多的shard也帶來更多小的segment,而過多的小segment會帶來非常顯著的heap記憶體消耗,特別是如果查詢執行緒配置得很多的情況下。 配置過大的threadpool更是會產生很多詭異的效能問題Issue#18161裡所描述的問題就是我們所經歷過的。 預設的Theadpool大小一般來說工作得很不錯了。
  3. 冷熱資料最好做分離。對於日誌型應用來說,一般是每天建立一個新索引,當天的熱索引在寫入的同時也會有較多的查詢。如果上面還存有比較長時間之前的冷資料,那麼當用戶做大跨度的歷史資料查詢的時候,過多的磁碟IO和CPU消耗很容易拖慢寫入,造成資料的延遲。所以我們用了一部分機器來做冷資料的儲存,利用ES可以給結點配置自定義屬性的功能,為冷結點加上"boxtype":"weak"的標識,每晚通過維護指令碼更新冷資料的索引路由設定index.routing.allocation.{require|include|exclude},讓資料自動向冷結點遷移。 冷資料的特性是不再寫入,使用者查的頻率較低,但量級可能很大。比如我們有個索引每天2TB,並且使用者要求保持過去90天資料隨時可查。保持這麼大量的索引為open狀態,並非只消耗磁碟空間。ES為了快速訪問磁碟上的索引檔案,需要在記憶體裡駐留一些資料(索引檔案的索引),也就是所謂的segment memory。稍微熟悉ES的同學知道,JVM heap分配不能超過32GB,對於我們128GB RAM, 48TB磁碟空間的機器而言,如果只跑一個ES例項,只能利用到32GB不到的heap,當heap快用飽和的時候,磁碟上儲存的索引檔案還不到10TB,這樣顯然是不經濟的。 因此我們決定在冷結點上跑3個ES例項,每個分配31GB heap空間,從而可以在一臺物理伺服器上儲存30多TB的索引資料並保持open狀態,供使用者隨時搜尋。 實際使用下來,由於冷資料搜尋頻率不高,也沒有寫入,即時只剩餘35GB記憶體給os做檔案系統快取,查詢效能還是可以滿足需求的。
  4. 不同資料量級的shard最好隔離到不同組別的結點。 大家知道ES會自己平衡shard在叢集的分佈,這個自動平衡的邏輯主要考量三個因素。其一同一索引下的shard儘量分散到不同的結點;其二每個結點上的shard數量儘量接近;其三結點的磁碟有足夠的剩餘空間。這個策略只能保證shard數量分佈均勻,而並不能保證資料大小分佈均勻。 實際應用中,我們有200多種索引,資料量級差別很大,大的一天幾個TB,小的一個月才幾個GB,並且每種型別的資料保留時長又千差萬別。丟擲的問題,就是如何能比較平衡並充分的利用所有節點的資源。 針對這個問題,我們還是通過對結點新增屬性標籤來做分組,結合index routing控制的方式來做一些精細化的控制。儘量讓不同量級的資料使用不同組別的結點,使得每個組內結點上的資料量比較容易自動平衡。
  5. 定期做索引的force merge,並且最好是每個shard merge成一個segment。前面提到過,heap消耗與segment數量也有關係,force merge可以顯著降低這種消耗。 如果merge成一個segment還有一個好處,就是對於terms aggregation,搜尋時無需構造Global Ordinals,可以提升聚合速度。


四. 版本選擇
我們在2.4版本上穩定跑了很長時間,比較保守的同學可以上2.4,激進有精力折騰的可以考慮最新的5.0。 我們叢集兩週前從v2.4.0升級到了v5.0.0這個版本,除了升級第一週遇到一個不穩定的問題以外,感覺新版本帶來的以下特性還是非常值得去升級的:

  • 結點啟動的Bootstrap過程加入了很多關鍵系統引數設定的核驗,比如Max File Descriptors, Memory Lock, Virtual Memory設定等等,如果設定不正確會拒絕啟動並丟擲異常。 與其帶著錯誤的系統引數啟動,並在日後造成效能問題,不如啟動失敗告知使用者問題,是個很好的設計!
  • 索引效能提升。升級後在同樣索引速率下,我們看到cpu消耗下降非常明顯,除了對索引速率提升有幫助,也會一定程度提升搜尋速率。
  • 新的數值型資料結構,儲存空間更小,Range和地理位置計算更快速
  • Instant Aggregation對於類似now-7d to now這樣的範圍查詢聚合能夠做cache了,實際使用下來,效果明顯,使用者在Kibana上跑個過去一週資料的聚合,頭2次重新整理慢點,之後有cache了幾乎就瞬間刷出!
  • 更多的保護措施保證叢集的穩定,比如對一次搜尋hit的shard數量做了限制,增強了circuit breaker的特性,更好的防護叢集資源被壞查詢耗盡。


升級第一週,我們的冷資料結點出現間歇性不響應問題,從而刨出3個issue提交給官方:
Issue#21595 Issue#21612 Issue#21611
第一個問題確認為Bug,將在5.0.2修復,其他兩個目前還不清楚根源,看起來也只在我們的應用場景裡遇到了。所幸問題都找到了了規避措施,實施這些措施以後,最近一週我們的叢集重新回到以前2.4版本時期的穩定狀態。


五. 監控
不差錢沒空折騰的建議還是買官方的xpack省心,有精力折騰的,利用ES各種豐富的stats api,用自己熟悉的監控工具採集資料,可視化出來就好了。 那麼多監控指標,最最關鍵的還是以下幾類:

  1. 各類Thread pool的使用情況,active/queue/reject可視化出來。 判斷叢集是否有效能瓶頸了,看看業務高峰期各類queue是不是很高,reject是不是經常發生,基本可以做到心裡有數。
  2. JVM的heap used%以及old GC的頻率,如果old GC頻率很高,並且多次GC過後heap used%幾乎下不來,說明heap壓力太大,要考慮擴容了。(也有可能是有問題的查詢或者聚合造成的,需要結合使用者訪問記錄來判斷)。
  3. Segment memory大小和Segment的數量。節點上存放的索引較多的時候,這兩個指標就值得關注,要知道segment memory是常駐heap不會被GC回收的,因此當heap壓力太大的時候,可以結合這個指標判斷是否是因為節點上存放的資料過多,需要擴容。Segement的數量也是比較關鍵的,如果小的segment非常多,比如有幾千,即使segment memory本身不多,但是在搜尋執行緒很多的情況下,依然會吃掉相當多的heap,原因是lucene為每個segment會在thread local裡記錄狀態資訊,這塊的heap記憶體開銷和(segment數量* thread數量)相關。
  4. 很有必要記錄使用者的訪問記錄。我們只開放了http api給使用者,前置了一個nginx做http代理,將使用者第三方api的訪問記錄通過access log全部記錄下來。通過分析訪問記錄,可以在叢集出現效能問題時,快速找到問題根源,對於問題排查和效能優化都很有幫助。


最後就是多上手實踐,遇到問題多查官方資料,多Google看是否有其他人遇到同類問題,精力充足有程式設計背景的同學也可以多刨刨原始碼。