Elasticsearch 用于支持我們的主要媒體監(jiān)控應(yīng)用,,客戶通過(guò)該應(yīng)用可以檢索和分析媒體數(shù)據(jù),,比如新聞文章、(公開(kāi)的)Facebook 帖子,、Instagram 帖子,、博客和微博。我們通過(guò)使用一個(gè)混合 API 來(lái)收集這些內(nèi)容,,并爬取和稍作加工,,使得它們可被 Elasticsearch 檢索到。
Elasticsearch 用于支持我們的主要媒體監(jiān)控應(yīng)用,客戶通過(guò)該應(yīng)用可以檢索和分析媒體數(shù)據(jù),,比如新聞文章,、(公開(kāi)的)Facebook 帖子、Instagram 帖子,、博客和微博,。我們通過(guò)使用一個(gè)混合 API 來(lái)收集這些內(nèi)容,,并爬取和稍作加工,使得它們可被 Elasticsearch 檢索到,。 本文將分享我們所學(xué)到的經(jīng)驗(yàn),、如何調(diào)優(yōu) Elasticsearch,以及要繞過(guò)的一些陷阱,。 數(shù)據(jù)量 每天都有數(shù)量相當(dāng)龐大的新聞和微博產(chǎn)生;在高峰期需要索引大約 300 多萬(wàn)社論文章,,和近 1 億條社交帖子數(shù)據(jù)。其中社論數(shù)據(jù)長(zhǎng)期保存以供檢索(可回溯到 2009 年),,社交帖子數(shù)據(jù)保存近 15 個(gè)月的。當(dāng)前的主分片數(shù)據(jù)使用了大約 200 TB 的磁盤(pán)空間,,副本數(shù)據(jù)大約 600 TB,。 我們的業(yè)務(wù)每分鐘有 3 千次請(qǐng)求。所有的請(qǐng)求通過(guò)一個(gè)叫做“search-service”的服務(wù),,該服務(wù)會(huì)依次完成所有與 Elasticsearch 集群的交互,。大部分檢索規(guī)則比較復(fù)雜,包括在面板和新聞流中,。比如,,一個(gè)客戶可能對(duì) Tesla 和 Elon Musk 感興趣,但希望排除所有關(guān)于 SpaceX 或 PayPal 的信息,。用戶可以使用一種與 Lucene 查詢語(yǔ)法類似的靈活語(yǔ)法,,如下:
我們最長(zhǎng)的此類查詢有 60 多頁(yè)。重點(diǎn)是:除了每分鐘 3 千次請(qǐng)求以外,,沒(méi)有一個(gè)查詢是像在 Google 里查詢“Barack Obama”這么簡(jiǎn)單的;這簡(jiǎn)直就是可怕的野獸,,但 ES 節(jié)點(diǎn)必須努力找出一個(gè)匹配的文檔集。 版本 我們運(yùn)行的是一個(gè)基于 Elasticsearch 1.7.6 的定制版本,。該版本與 1.7.6 主干版本的唯一區(qū)別是,,我們向后移植(backport)了 roaring bitsets/bitmaps 作為緩存。該功能是從 Lucene 5 移植到 Lucene 4 的,,對(duì)應(yīng)移植到了 ES 1.X 版本,。Elasticsearch 1.X 中使用默認(rèn)的 bitset 作為緩存,對(duì)于稀疏結(jié)果來(lái)說(shuō)開(kāi)銷非常大,,不過(guò)在 Elasticsearch 2.X 中已經(jīng)做了優(yōu)化,。 為何不使用較新版本的 Elasticsearch 呢?主要原因是升級(jí)困難。在主版本間滾動(dòng)升級(jí)只適用于從 ES 5 到 6(從 ES 2 到 5 應(yīng)該也支持滾動(dòng)升級(jí),,但沒(méi)有試過(guò)),。因此,我們只能通過(guò)重啟整個(gè)集群來(lái)升級(jí),。宕機(jī)對(duì)我們來(lái)說(shuō)幾乎不可接受,,但或許可以應(yīng)對(duì)一次重啟所帶來(lái)的大約 30-60 分鐘宕機(jī)時(shí)間;而真正令人擔(dān)心的,,是一旦發(fā)生故障并沒(méi)有真正的回滾過(guò)程。 截止目前我們選擇了不升級(jí)集群,。當(dāng)然我們希望可以升級(jí),,但目前有更為緊迫的任務(wù)。實(shí)際上該如何實(shí)施升級(jí)尚未有定論,,很可能選擇創(chuàng)建另一個(gè)新的集群,,而不是升級(jí)現(xiàn)有的。 節(jié)點(diǎn)配置 我們自 2017 年 6 月開(kāi)始在 AWS 上運(yùn)行主集群,,使用 i3.2xlarge 實(shí)例作為數(shù)據(jù)節(jié)點(diǎn),。之前我們?cè)?COLO(Co-located Data Center)里運(yùn)行集群,但后續(xù)遷移到了 AWS 云,,以便在新機(jī)器宕機(jī)時(shí)能贏得時(shí)間,,使得我們?cè)跀U(kuò)容和縮容時(shí)更加彈性。 我們?cè)诓煌目捎脜^(qū)運(yùn)行 3 個(gè)候選 master 節(jié)點(diǎn),,并設(shè)置 discovery.zen.minimum_master_nodes 為 2,。這是避免腦裂問(wèn)題 split-brain problem 非常通用的策略。 我們的數(shù)據(jù)集在存儲(chǔ)方面,,要求 80% 容量和 3 個(gè)以上的副本,,這使得我們運(yùn)行了 430 個(gè)數(shù)據(jù)節(jié)點(diǎn)。起初打算使用不同層級(jí)的數(shù)據(jù),,在較慢的磁盤(pán)上存儲(chǔ)較舊的數(shù)據(jù),,但是由于我們只有相關(guān)的較低量級(jí)舊于 15 個(gè)月的數(shù)據(jù)(只有編輯數(shù)據(jù),因?yàn)槲覀儊G棄了舊的社交數(shù)據(jù)),,然而這并未奏效,。每個(gè)月的硬件開(kāi)銷遠(yuǎn)大于運(yùn)行在 COLO 中,但是云服務(wù)支持?jǐn)U容集群到 2 倍,,而幾乎不用花費(fèi)多少時(shí)間,。 你可能會(huì)問(wèn),為何選擇自己管理維護(hù) ES 集群,。其實(shí)我們考慮過(guò)托管方案,,但最后還是選擇自己安裝,理由是: AWS Elasticsearch Service 暴露給用戶的可控性太差了,, Elastic Cloud 的成本比直接在 EC2 上運(yùn)行集群要高 2-3 倍,。 為了在某個(gè)可用區(qū)宕機(jī)時(shí)保護(hù)我們自身,節(jié)點(diǎn)分散于 eu-west-1 的所有 3 個(gè)可用區(qū),。我們使用 AWS plugin 來(lái)完成該項(xiàng)配置,。它提供了一個(gè)叫做 aws_availability_zone 的節(jié)點(diǎn)屬性,我們把 cluster.routing.allocation.awareness.attributes 設(shè)置為 aws_availability_zone,。這保證了 ES 的副本盡可能地存儲(chǔ)在不同的可用區(qū),,而查詢盡可能被路由到相同可用區(qū)的節(jié)點(diǎn),。 這些實(shí)例運(yùn)行的是 Amazon Linux,臨時(shí)掛載為 ext4,,有約 64GB 的內(nèi)存,。我們分配了 26GB 用于 ES 節(jié)點(diǎn)的堆內(nèi)存,剩下的用于磁盤(pán)緩存,。為何是 26GB?因?yàn)?JVM 是在一個(gè)黑魔法之上構(gòu)建的,。 我們同時(shí)使用 Terraform 自動(dòng)擴(kuò)容組來(lái)提供實(shí)例,并使用 Puppet 完成一切安裝配置,。 索引結(jié)構(gòu) 因?yàn)槲覀兊臄?shù)據(jù)和查詢都是基于時(shí)間序列的,,所以使用了 time-based indexing,類似于 ELK (elasticsearch, logstash, kibana) stack,。同時(shí)也讓不同類型的數(shù)據(jù)保存在不同的索引庫(kù)中,,以便諸如社論文檔和社交文檔類數(shù)據(jù)最終位于不同的每日索引庫(kù)中。這樣可以在需要的時(shí)候只丟棄社交索引,,并增加一些查詢優(yōu)化。每個(gè)日索引運(yùn)行在兩個(gè)分片中的一個(gè),。 該項(xiàng)設(shè)置產(chǎn)生了大量的分片(接近 40k),。有了這么多的分片和節(jié)點(diǎn),集群操作有時(shí)變得更特殊,。比如,,刪除索引似乎成為集群 master 的能力瓶頸,它需要把集群狀態(tài)信息推送給所有節(jié)點(diǎn),。我們的集群狀態(tài)數(shù)據(jù)約 100 MB,,但通過(guò) TCP 壓縮可減少到 3 MB(可以通過(guò) curl localhost:9200/_cluster/state/_all 查看你自己集群的狀態(tài)數(shù)據(jù))。Master 節(jié)點(diǎn)仍然需要在每次變更時(shí)推送 1.3 GB 數(shù)據(jù)(430 節(jié)點(diǎn) x 3 MB 狀態(tài)大小),。除了這 1.3 GB 數(shù)據(jù)外,,還有約 860 MB 必須在可用區(qū)(比如 最基本的通過(guò)公共互聯(lián)網(wǎng))之間傳輸。這會(huì)比較耗時(shí),,尤其是在刪除數(shù)百個(gè)索引時(shí),。我們希望新版本的 Elasticsearch 能優(yōu)化這一點(diǎn),首先從 ES 2.0 支持僅發(fā)送集群狀態(tài)的差分?jǐn)?shù)據(jù)這一特性開(kāi)始,。 性能 如前所述,,我們的 ES 集群為了滿足客戶的檢索需求,需要處理一些非常復(fù)雜的查詢,。 為應(yīng)對(duì)查詢負(fù)載,,過(guò)去幾年我們?cè)谛阅芊矫孀隽舜罅康墓ぷ鳌N覀儽仨殗L試公平分享 ES 集群的性能測(cè)試,,從下列引文就可以看出,。 不幸的是,,當(dāng)集群宕機(jī)的時(shí)候,不到三分之一的查詢能成功完成,。我們相信測(cè)試本身導(dǎo)致了集群宕機(jī),。—— 摘錄自使用真實(shí)查詢?cè)谛?ES 集群平臺(tái)上的第一次性能測(cè)試 為了控制查詢執(zhí)行過(guò)程,,我們開(kāi)發(fā)了一個(gè)插件,,實(shí)現(xiàn)了一系列自定義查詢類型。通過(guò)使用這些查詢類型來(lái)提供 Elasticsearch 官方版本不支持的功能和性能優(yōu)化,。比如,,我們實(shí)現(xiàn)了 phrases 中的 wildcard 查詢,支持在 SpanNear 查詢中執(zhí)行;另一個(gè)優(yōu)化是支持“*”代替 match-all-query;還有其他一系列特性,。 Elasticsearch 和 Lucene 的性能高度依賴于具體的查詢和數(shù)據(jù),,沒(méi)有銀彈。即便如此,,仍可給出一些從基礎(chǔ)到進(jìn)階的參考:
圖表說(shuō)明:響應(yīng)時(shí)間,。有 / 沒(méi)有 重寫(xiě) Lucene 查詢執(zhí)行,。同時(shí)也表明不再有節(jié)點(diǎn)每天發(fā)生多次內(nèi)存不足的情況。 順便說(shuō)明下,,因?yàn)槲抑罆?huì)面臨一個(gè)問(wèn)題:從上一次性能測(cè)試我們知道通過(guò)升級(jí)到 ES 2.X 能小幅提升性能,,但是并不能改變什么。話雖如此,,但如果你已經(jīng)從 ES 1.X 集群遷移到了 ES 2.X,,我們很樂(lè)意聽(tīng)取關(guān)于你如何完成遷移的實(shí)踐經(jīng)驗(yàn)。 |
|
來(lái)自: yxrsky > 《大數(shù)據(jù)》