億級 Elasticsearch 性能優(yōu)化

前言

最近一年使用 Elasticsearch 完成億級別日志搜索平臺「ELK」权纤,億級別的分布式跟蹤系統(tǒng)。在設(shè)計(jì)這些系統(tǒng)的過程中仆葡,底層都是采用 Elasticsearch 來做數(shù)據(jù)的存儲逻悠,并且數(shù)據(jù)量都超過億級別,甚至達(dá)到百億級別蚯窥。

所以趁著有空掸鹅,就花點(diǎn)時(shí)間整理一下具體怎么做 Elasticsearch 性能優(yōu)化,希望能對 Elasticsearch 感興趣的同學(xué)有所幫助拦赠。

背景

Elasticsearch 是一個(gè)基于 Lucene 的搜索服務(wù)器巍沙。它提供了一個(gè)分布式多用戶能力的全文搜索引擎,基于 RESTful web 接口荷鼠。Elasticsearch 是用 Java 開發(fā)的句携,并作為 Apache 許可條款下的開放源碼發(fā)布,是當(dāng)前流行的企業(yè)級搜索引擎允乐。設(shè)計(jì)用于云計(jì)算中矮嫉,能夠達(dá)到實(shí)時(shí)搜索,穩(wěn)定牍疏,可靠蠢笋,快速,安裝使用方便鳞陨。

作為一個(gè)開箱即用的產(chǎn)品昨寞,在生產(chǎn)環(huán)境上線之后,我們其實(shí)不一定能確保其的性能和穩(wěn)定性厦滤。如何根據(jù)實(shí)際情況提高服務(wù)的性能援岩,其實(shí)有很多技巧。

下面我就從三個(gè)方面分別來講解下優(yōu)化服務(wù)的性能:

  1. 索引效率優(yōu)化
  2. 查詢效率優(yōu)化
  3. JVM 配置優(yōu)化

索引效率優(yōu)化

索引優(yōu)化主要是在 Elasticsearch 插入層面優(yōu)化馁害,如果瓶頸不在這塊窄俏,而是在產(chǎn)生數(shù)據(jù)部分,比如 DB 或者 Hadoop 上碘菜,那么優(yōu)化方向就需要改變下凹蜈。同時(shí),Elasticsearch 本身索引速度其實(shí)還是蠻快的忍啸,具體數(shù)據(jù)仰坦,我們可以參考官方的 benchmark 數(shù)據(jù)。

批量提交

當(dāng)有大量數(shù)據(jù)提交的時(shí)候计雌,建議采用批量提交悄晃。

比如在做 ELK 過程中 ,Logstash indexer 提交數(shù)據(jù)到 Elasticsearch 中 ,batch size 就可以作為一個(gè)優(yōu)化功能點(diǎn)妈橄。但是優(yōu)化 size 大小需要根據(jù)文檔大小和服務(wù)器性能而定庶近。

像 Logstash 中提交文檔大小超過 20MB ,Logstash 會請一個(gè)批量請求切分為多個(gè)批量請求眷蚓。

如果在提交過程中鼻种,遇到 EsRejectedExecutionException 異常的話,則說明集群的索引性能已經(jīng)達(dá)到極限了沙热。這種情況叉钥,要么提高服務(wù)器集群的資源,要么根據(jù)業(yè)務(wù)規(guī)則篙贸,減少數(shù)據(jù)收集速度投队,比如只收集 Warn、Error 級別以上的日志爵川。

優(yōu)化硬件

優(yōu)化硬件設(shè)備一直是最快速有效的手段敷鸦。

  1. 在經(jīng)濟(jì)壓力能承受的范圍下, 盡量使用固態(tài)硬盤 SSD寝贡。SSD 相對于機(jī)器硬盤轧膘,無論隨機(jī)寫還是順序?qū)懀驾^大的提升兔甘。
  2. 磁盤備份采用 RAID0。因?yàn)?Elasticsearch 在自身層面通過副本鳞滨,已經(jīng)提供了備份的功能洞焙,所以不需要利用磁盤的備份功能,同時(shí)如果使用磁盤備份功能的話拯啦,對寫入速度有較大的影響澡匪。

增加 Refresh 時(shí)間間隔

為了提高索引性能,Elasticsearch 在寫入數(shù)據(jù)時(shí)候褒链,采用延遲寫入的策略唁情,即數(shù)據(jù)先寫到內(nèi)存中,當(dāng)超過默認(rèn) 1 秒 (index.refresh_interval)會進(jìn)行一次寫入操作甫匹,就是將內(nèi)存中 segment 數(shù)據(jù)刷新到操作系統(tǒng)中甸鸟,此時(shí)我們才能將數(shù)據(jù)搜索出來,所以這就是為什么 Elasticsearch 提供的是近實(shí)時(shí)搜索功能兵迅,而不是實(shí)時(shí)搜索功能抢韭。

當(dāng)然像我們的內(nèi)部系統(tǒng)對數(shù)據(jù)延遲要求不高的話,我們可以通過延長 refresh 時(shí)間間隔恍箭,可以有效的減少 segment 合并壓力刻恭,提供索引速度。在做全鏈路跟蹤的過程中扯夭,我們就將 index.refresh_interval 設(shè)置為 30s鳍贾,減少 refresh 次數(shù)鞍匾。

同時(shí),在進(jìn)行全量索引時(shí)骑科,可以將 refresh 次數(shù)臨時(shí)關(guān)閉橡淑,即 index.refresh_interval 設(shè)置為 -1,數(shù)據(jù)導(dǎo)入成功后再打開到正常模式纵散,比如 30s梳码。

減少副本數(shù)量

Elasticsearch 默認(rèn)副本數(shù)量為 3 個(gè),雖然這樣會提高集群的可用性伍掀,增加搜索的并發(fā)數(shù)掰茶,但是同時(shí)也會影響寫入索引的效率。

在索引過程中蜜笤,需要把更新的文檔發(fā)到副本節(jié)點(diǎn)上濒蒋,等副本節(jié)點(diǎn)生效后在進(jìn)行返回結(jié)束。使用 Elasticsearch 做業(yè)務(wù)搜索的時(shí)候把兔,建議副本數(shù)目還是設(shè)置為 3 個(gè)沪伙,但是像內(nèi)部 ELK 日志系統(tǒng)、分布式跟蹤系統(tǒng)中县好,完全可以將副本數(shù)目設(shè)置為 1 個(gè)围橡。

查詢效率優(yōu)化

路由

當(dāng)我們查詢文檔的時(shí)候,Elasticsearch 如何知道一個(gè)文檔應(yīng)該存放到哪個(gè)分片中呢缕贡?它其實(shí)是通過下面這個(gè)公式來計(jì)算出來

shard = hash(routing) % number_of_primary_shards

routing 默認(rèn)值是文檔的 id翁授,也可以采用自定義值,比如用戶 id晾咪。

不帶 routing 查詢

在查詢的時(shí)候因?yàn)椴恢酪樵兊臄?shù)據(jù)具體在哪個(gè)分片上收擦,所以整個(gè)過程分為 2 個(gè)步驟

  • 分發(fā):請求到達(dá)協(xié)調(diào)節(jié)點(diǎn)后,協(xié)調(diào)節(jié)點(diǎn)將查詢請求分發(fā)到每個(gè)分片上谍倦。
  • 聚合: 協(xié)調(diào)節(jié)點(diǎn)搜集到每個(gè)分片上查詢結(jié)果塞赂,在將查詢的結(jié)果進(jìn)行排序,之后給用戶返回結(jié)果昼蛀。

帶 routing 查詢

查詢的時(shí)候宴猾,可以直接根據(jù) routing 信息定位到某個(gè)分配查詢,不需要查詢所有的分配叼旋,經(jīng)過協(xié)調(diào)節(jié)點(diǎn)排序鳍置。

向上面自定義的用戶查詢,如果 routing 設(shè)置為 userid 的話送淆,就可以直接查詢出數(shù)據(jù)來税产,效率提升很多。

Filter VS Query

Ebay 曾經(jīng)分享過他們使用 Elasticsearch 的經(jīng)驗(yàn)中說到:

Use filter context instead of query context if possible.
盡可能使用過濾器上下文(Filter)替代查詢上下文(Query

  • Query:此文檔與此查詢子句的匹配程度如何?
  • Filter:此文檔和查詢子句匹配嗎辟拷?

Elasticsearch 針對 Filter 查詢只需要回答「是」或者「否」撞羽,不需要像 Query 查詢一下計(jì)算相關(guān)性分?jǐn)?shù),同時(shí) Filter 結(jié)果可以緩存衫冻。

大翻頁

在使用 Elasticsearch 過程中诀紊,應(yīng)盡量避免大翻頁的出現(xiàn)。

正常翻頁查詢都是從 From 開始 Size 條數(shù)據(jù)隅俘,這樣就需要在每個(gè)分片中查詢打分排名在前面的 From + Size 條數(shù)據(jù)邻奠。協(xié)同節(jié)點(diǎn)收集每個(gè)分配的前 From + Size 條數(shù)據(jù)。協(xié)同節(jié)點(diǎn)一共會受到 N * ( From + Size )條數(shù)據(jù)为居,然后進(jìn)行排序碌宴,再將其中 From 到 From + Size 條數(shù)據(jù)返回出去。

如果 From 或者 Size 很大的話蒙畴,導(dǎo)致參加排序的數(shù)量會同步擴(kuò)大很多贰镣,最終會導(dǎo)致 CPU 資源消耗增大。

可以通過使用 Elasticsearch scroll 和 scroll-scan 高效滾動的方式來解決這樣的問題膳凝。具體寫法碑隆,可以參考 Elasticsearch: 權(quán)威指南 - scroll 查詢

JVM 設(shè)置

32G 現(xiàn)象

Elasticsearch 默認(rèn)安裝后設(shè)置的堆內(nèi)存是 1 GB。 對于任何一個(gè)業(yè)務(wù)部署來說蹬音, 這個(gè)設(shè)置都太小了上煤。

比如機(jī)器有 64G 內(nèi)存,那么我們是不是設(shè)置的越大越好呢著淆?

其實(shí)不是的楼入。

主要 Elasticsearch 底層使用 Lucene。Lucene 被設(shè)計(jì)為可以利用操作系統(tǒng)底層機(jī)制來緩存內(nèi)存數(shù)據(jù)結(jié)構(gòu)牧抽。 Lucene 的段是分別存儲到單個(gè)文件中的。因?yàn)槎问遣豢勺兊囊W@些文件也都不會變化扬舒,這是對緩存友好的,同時(shí)操作系統(tǒng)也會把這些段文件緩存起來凫佛,以便更快的訪問讲坎。

如果你把所有的內(nèi)存都分配給 Elasticsearch 的堆內(nèi)存,那將不會有剩余的內(nèi)存交給 Lucene愧薛。 這將嚴(yán)重地影響全文檢索的性能晨炕。

標(biāo)準(zhǔn)的建議是把 50% 的可用內(nèi)存作為 Elasticsearch 的堆內(nèi)存,保留剩下的 50%毫炉。當(dāng)然它也不會被浪費(fèi)瓮栗,Lucene 會很樂意利用起余下的內(nèi)存。

同時(shí)了解過 ES 的同學(xué)都聽過過「不要超過 32G」的說法吧。

其實(shí)主要原因是 :JVM 在內(nèi)存小于 32 GB 的時(shí)候會采用一個(gè)內(nèi)存對象指針壓縮技術(shù)费奸。

在 Java 中弥激,所有的對象都分配在堆上,并通過一個(gè)指針進(jìn)行引用愿阐。 普通對象指針(OOP)指向這些對象微服,通常為 CPU 字長 的大小:32 位或 64 位缨历,取決于你的處理器以蕴。指針引用的就是這個(gè) OOP 值的字節(jié)位置。

對于 32 位的系統(tǒng)辛孵,意味著堆內(nèi)存大小最大為 4 GB丛肮。對于 64 位的系統(tǒng), 可以使用更大的內(nèi)存觉吭,但是 64 位的指針意味著更大的浪費(fèi)腾供,因?yàn)槟愕闹羔槺旧泶罅恕8愀獾氖牵?更大的指針在主內(nèi)存和各級緩存(例如 LLC鲜滩,L1 等)之間移動數(shù)據(jù)的時(shí)候伴鳖,會占用更多的帶寬.

所以最終我們都會采用 31 G 設(shè)置

-Xms 31g
-Xmx 31g

假設(shè)你有個(gè)機(jī)器有 128 GB 的內(nèi)存,你可以創(chuàng)建兩個(gè)節(jié)點(diǎn)徙硅,每個(gè)節(jié)點(diǎn)內(nèi)存分配不超過 32 GB榜聂。 也就是說不超過 64 GB 內(nèi)存給 ES 的堆內(nèi)存,剩下的超過 64 GB 的內(nèi)存給 Lucene

參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嗓蘑,一起剝皮案震驚了整個(gè)濱河市须肆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌桩皿,老刑警劉巖豌汇,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異泄隔,居然都是意外死亡拒贱,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門佛嬉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逻澳,“玉大人,你說我怎么就攤上這事暖呕⌒弊觯” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵湾揽,是天一觀的道長瓤逼。 經(jīng)常有香客問我笼吟,道長,這世上最難降的妖魔是什么抛姑? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任赞厕,我火速辦了婚禮,結(jié)果婚禮上定硝,老公的妹妹穿的比我還像新娘皿桑。我一直安慰自己,他們只是感情好蔬啡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布诲侮。 她就那樣靜靜地躺著,像睡著了一般箱蟆。 火紅的嫁衣襯著肌膚如雪沟绪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天空猜,我揣著相機(jī)與錄音绽慈,去河邊找鬼。 笑死辈毯,一個(gè)胖子當(dāng)著我的面吹牛坝疼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播谆沃,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼钝凶,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了唁影?” 一聲冷哼從身側(cè)響起拓售,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤晾剖,失蹤者是張志新(化名)和其女友劉穎对湃,沒想到半個(gè)月后鸠珠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锌介,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年嗜诀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掏湾。...
    茶點(diǎn)故事閱讀 39,926評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖肿嘲,靈堂內(nèi)的尸體忽然破棺而出融击,到底是詐尸還是另有隱情,我是刑警寧澤雳窟,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布尊浪,位于F島的核電站匣屡,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏拇涤。R本人自食惡果不足惜捣作,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鹅士。 院中可真熱鬧券躁,春花似錦、人聲如沸掉盅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽趾痘。三九已至慢哈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間永票,已是汗流浹背卵贱。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留侣集,地道東北人键俱。 一個(gè)月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像肚吏,于是被迫代替她去往敵國和親方妖。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容