400+節點的 Elasticsearch 集羣運維

本文首發於InfoQ https://www.infoq.cn/article/1sm0Mq5LyY_021HGuXerhtml

做者:Anton Hägerstrandjava

翻譯:楊振濤 node

目錄:

  1. 數據量

  2. 版本

  3. 節點配置

  4. 索引結構

  5. 性能

 

Meltwater天天要處理數百萬量級的帖子數據,所以須要一種能處理該量級數據的存儲和檢索技術。緩存

從0.11.X 版本開始咱們就已是Elasticsearch的忠實用戶了。在經歷了一些波折以後,最終咱們認爲作出了正確的技術選型。性能優化

Elasticsearch 用於支持咱們的主要媒體監控應用,客戶經過該應用能夠檢索和分析媒體數據,好比新聞文章、(公開的)Facebook帖子、Instagram帖子、博客和微博。咱們經過使用一個混合API來收集這些內容,並爬取和稍做加工,使得它們可被 Elasticsearch 檢索到。微信

本文將分享咱們所學到的經驗、如何調優 Elasticsearch,以及要繞過的一些陷阱。oracle

若是想了解更多關於咱們在Elasticsearch方面的點滴,可參考以前博文中的 numad issues 和 batch percolatorapp

 

1.數據量


天天都有數量至關龐大的新聞和微博產生;在高峯期須要索引大約300多萬社論文章,和近1億條社交帖子數據。其中社論數據長期保存以供檢索(可回溯到2009年),社交帖子數據保存近15個月的。當前的主分片數據使用了大約200 TB的磁盤空間,副本數據大約600 TB。curl

咱們的業務每分鐘有3千次請求。全部的請求經過一個叫作 「search-service」 的服務,該服務會依次完成全部與 Elasticsearch 集羣的交互。大部分檢索規則比較複雜,包括在面板和新聞流中。好比,一個客戶可能對 Tesla 和 Elon Musk 感興趣,但但願排除全部關於 SpaceX 或 PayPal 的信息。用戶可使用一種與 Lucene 查詢語法相似的靈活語法,以下:jvm

Tesla AND "Elon Musk" NOT (SpaceX OR PayPal)

咱們最長的此類查詢有60多頁。重點是:除了每分鐘3千次請求之外,沒有一個查詢是像在 Google 裏查詢 「Barack Obama」 這麼簡單的;這簡直就是可怕的野獸,但ES節點必須努力找出一個匹配的文檔集。

 

 

2.版本


咱們運行的是一個基於 Elasticsearch 1.7.6 的定製版本。該版本與1.7.6 主幹版本的惟一區別是,咱們向後移植(backport)了 roaring bitsets/bitmaps 做爲緩存。該功能是從 Lucene 5 移植到 Lucene 4 的,對應移植到了 ES 1.X 版本。Elasticsearch 1.X 中使用默認的 bitset 做爲緩存,對於稀疏結果來講開銷很是大,不過在 Elasticsearch 2.X 中已經作了優化。

爲什麼不使用較新版本的 Elasticsearch 呢?主要緣由是升級困難。在主版本間滾動升級只適用於從ES 5到6(從ES 2到5應該也支持滾動升級,但沒有試過)。所以,咱們只能經過重啓整個集羣來升級。宕機對咱們來講幾乎不可接受,但或許能夠應對一次重啓所帶來的大約30-60分鐘宕機時間;而真正使人擔憂的,是一旦發生故障並無真正的回滾過程。

截止目前咱們選擇了不升級集羣。固然咱們但願能夠升級,但目前有更爲緊迫的任務。實際上該如何實施升級還沒有有定論,極可能選擇建立另外一個新的集羣,而不是升級現有的。

 

3.節點配置


咱們自2017年6月開始在AWS上運行主集羣,使用i3.2xlarge實例做爲數據節點。以前咱們在COLO(Co-located Data Center)裏運行集羣,但後續遷移到了AWS雲,以便在新機器宕機時能贏得時間,使得咱們在擴容和縮容時更加彈性。

咱們在不一樣的可用區運行3個候選 master 節點,並設置 discovery.zen.minimum_master_nodes 爲2。這是避免腦裂問題 split-brain problem 很是通用的策略。

咱們的數據集在存儲方面,要求80%容量和3個以上的副本,這使得咱們運行了430個數據節點。起初打算使用不一樣層級的數據,在較慢的磁盤上存儲較舊的數據,可是因爲咱們只有相關的較低量級舊於15個月的數據(只有編輯數據,由於咱們丟棄了舊的社交數據),然而這並未奏效。每月的硬件開銷遠大於運行在COLO中,可是雲服務支持擴容集羣到2倍,而幾乎不用花費多少時間。

你可能會問,爲什麼選擇本身管理維護ES集羣。其實咱們考慮過託管方案,但最後仍是選擇本身安裝,理由是: AWS Elasticsearch Service

暴露給用戶的可控性太差了,Elastic Cloud 的成本比直接在EC2上運行集羣要高2-3倍。

爲了在某個可用區宕機時保護咱們自身,節點分散於eu-west-1的全部3個可用區。咱們使用 AWS plugin 來完成該項配置。它提供了一個叫作aws_availability_zone 的節點屬性,咱們把 cluster.routing.allocation.awareness.attributes 設置爲 aws_availability_zone。這保證了ES的副本儘量地存儲在不一樣的可用區,而查詢儘量被路由到相同可用區的節點。

這些實例運行的是 Amazon Linux,臨時掛載爲 ext4,有約64GB的內存。咱們分配了26GB用於ES節點的堆內存,剩下的用於磁盤緩存。爲什麼是26GB?由於 JVM 是在一個黑魔法之上構建的 。

咱們同時使用 Terraform 自動擴容組來提供實例,並使用 Puppet 完成一切安裝配置。

 

4.索引結構


由於咱們的數據和查詢都是基於時間序列的,因此使用了 time-based indexing ,相似於ELK (elasticsearch, logstash, kibana) stack。同時也讓不一樣類型的數據保存在不一樣的索引庫中,以便諸如社論文檔和社交文檔類數據最終位於不一樣的每日索引庫中。這樣能夠在須要的時候只丟棄社交索引,並增長一些查詢優化。每一個日索引運行在兩個分片中的一個。

該項設置產生了大量的分片(接近40k)。有了這麼多的分片和節點,集羣操做有時變得更特殊。好比,刪除索引彷佛成爲集羣master的能力瓶頸,它須要把集羣狀態信息推送給全部節點。咱們的集羣狀態數據約100 MB,但經過TCP壓縮可減小到3 MB(能夠經過 curl localhost:9200/_cluster/state/_all 查看你本身集羣的狀態數據)。Master 節點仍然須要在每次變動時推送1.3 GB數據(430 節點 x 3 MB 狀態大小)。除了這1.3 GB數據外,還有約860 MB必須在可用區(好比 最基本的經過公共互聯網)之間傳輸。這會比較耗時,尤爲是在刪除數百個索引時。咱們但願新版本的 Elasticsearch 能優化這一點,首先從 ES 2.0支持僅發送集羣狀態的差分數據 這一特性開始。

 

5.性能


如前所述,咱們的ES集羣爲了知足客戶的檢索需求,須要處理一些很是複雜的查詢。

爲應對查詢負載,過去幾年咱們在性能方面作了大量的工做。咱們必須嘗試公平分享ES集羣的性能測試,從下列引文就能夠看出。

不幸的是,當集羣宕機的時候,不到三分之一的查詢能成功完成。咱們相信測試自己致使了集羣宕機。 

—— 摘錄自使用真實查詢在新ES集羣平臺上的第一次性能測試

爲了控制查詢執行過程,咱們開發了一個插件,實現了一系列自定義查詢類型。經過使用這些查詢類型來提供Elasticsearch官方版本不支持的功能和性能優化。好比,咱們實現了 phrases 中的 wildcard 查詢,支持在 SpanNear 查詢中執行;另外一個優化是支持「*」代替 match-all-query ;還有其餘一系列特性。

Elasticsearch 和 Lucene 的性能高度依賴於具體的查詢和數據,沒有銀彈。即使如此,仍可給出一些從基礎到進階的參考:

限制你的檢索範圍,僅涉及相關數據。好比,對於每日索引庫,只按相關日期範圍檢索。對於檢索範圍中間的索引,避免使用範圍查詢/過濾器。

使用wildcards時忽略前綴wildcards - 除非你能對term創建倒排索引。雙端wildcards難以優化。

關注資源消耗的相關跡象 數據節點的CPU佔用持續飆高嗎?IQ等待走高嗎?看看GC統計。這些能夠從profilers工具或者經過 JMX 代理得到。若是 ParNewGC 消耗了超過15%的時間,去檢查下內存日誌。若是有任何的 SerialGC 停頓,你可能真的遇到問題了。不太瞭解這些內容?

不要緊,這個系列博文很好地介紹了JVM性能 。記住,ES和G1垃圾回收器一塊兒並不是最佳 。

若是遇到垃圾回收問題,請不要嘗試調整GC設置。這一點常常發生,由於默認設置已經很合理了。相反,應該聚焦在減小內存分配上。具體怎麼作?參考下文。

若是遇到內存問題,但沒有時間解決,可考慮查詢Azul Zing。這是一個很貴的產品,但僅僅使用它們的JVM就能夠提高2倍的吞吐量。不過最終咱們並無使用它,由於咱們沒法證實物有所值。

考慮使用緩存,包括 Elasticsearch 外緩存和 Lucene 級別的緩存。在 Elasticsearch 1.X 中能夠經過使用 filter 來控制緩存。以後的版本中看起來更難一些,但貌似能夠實現本身用於緩存的查詢類型。咱們在將來升級到2.X的時候可能會作相似的工做。

查看是否有熱點數據(好比某個節點承擔了全部的負載)。能夠嘗試均衡負載,使用分片分配過濾策略 shard allocation filtering ,或者嘗試經過集羣從新路由 cluster rerouting 來自行遷移分片。咱們已經使用線性優化自動從新路由,但使用簡單的自動化策略也大有幫助。

搭建測試環境(我更喜歡筆記本)可從線上環境加載一部分表明性的數據(建議至少有一個分片)。使用線上的查詢回放加壓(較難)。使用本地設置來測試請求的資源消耗。

綜合以上各點,在 Elasticsearch 進程上啓用一個 profiler。這是本列表中最重要的一條。

咱們同時經過Java Mission Control 和 VisualVM 使用飛行記錄器。在性能問題上嘗試投機(包括付費顧問/技術支持)的人是在浪費他們(以及你本身)的時間。排查下 JVM 哪部分消耗了時間和內存,而後探索下 Elasticsearch/Lucene 源代碼,檢查是哪部分代碼在執行或者分配內存。

一旦搞清楚是請求的哪一部分致使了響應變慢,你就能夠經過嘗試修改請求來優化(好比,修改term聚合的執行提示 ,或者切換查詢類型)。修改查詢類型或者查詢順序,能夠有較大影響。若是不湊效,還能夠嘗試優化 ES/Lucene 代碼。這看起來太誇張,卻能夠爲咱們下降3到4倍的CPU消耗和4到8倍的內存使用。某些修改很細微(好比 indices query ),但其餘人可能要求咱們徹底重寫查詢執行。最終的代碼嚴重依賴於咱們的查詢模式,因此可能適合也可能不適合他人使用。所以目前爲止咱們並無開源這部分代碼。不過這多是下一篇博文的好素材。

圖表說明:響應時間。有/沒有 重寫 Lucene 查詢執行。同時也代表再也不有節點天天屢次發生內存不足。

順便說明下,由於我知道會面臨一個問題:從上一次性能測試咱們知道經過升級到 ES 2.X 能小幅提高性能,可是並不能改變什麼。話雖如此,但若是你已經從 ES 1.X 集羣遷移到了 ES 2.X,咱們很樂意聽取關於你如何完成遷移的實踐經驗。

若是讀到了這裏,說明你對 Elasticsearch 是真愛啊(或者至少你是真的須要它)。咱們很樂意學習你的經驗,以及任何能夠分享的內容。歡迎在評論區分享你的反饋和問題。

英文原文連接:http://underthehood.meltwater.com/blog/2018/02/06/running-a-400+-node-es-cluster/


更多內容敬請關注 vivo 互聯網技術微信公衆號。

 

注:轉載文章請先與微信號:labs2020 聯繫。

相關文章
相關標籤/搜索