ElasticSearch 配置優(yōu)化

公司的業(yè)務(wù)日志數(shù)據(jù)量暴漲,內(nèi)存很快就不夠用,時(shí)常出現(xiàn)OOM,并且在 failover 的過(guò)程中寫(xiě)入速度不理想,很是揪心??焖賹W(xué)習(xí)了一下原理,進(jìn)行了一系列優(yōu)化,遂紀(jì)錄一下。

背景知識(shí)

了解 LSM 樹(shù)的同學(xué)就不用看這塊了,對(duì)標(biāo) HBase 的概念來(lái)說(shuō):

  • Translog 類似 HLog;
  • Type 類似 HTable;
  • Document 類似 Row;
  • Field 類似 Column;
  • Segment 類似 HFile(數(shù)據(jù)結(jié)構(gòu)當(dāng)然完全不一樣);
  • Optimize/force merge 類似 Compaction;
  • refresh 是 ES 特有的保證數(shù)據(jù)實(shí)時(shí)可被搜索;
  • flush 類似 flush;

Segment 的類似日志式的 append 寫(xiě)入,是為了優(yōu)化寫(xiě)性能;Optimize/force merge 是為了減少 segment 數(shù)量(同時(shí)影響文件句柄/內(nèi)存/消耗CPU等資源),優(yōu)化讀性能。

倒排索引

與傳統(tǒng)的數(shù)據(jù)庫(kù)不同,在 ES 中,每個(gè)字段里面的每個(gè)單詞都是可以被搜索的。如 hobby:"dance,sing,swim,run",我們?cè)谒阉麝P(guān)鍵字 swim 時(shí),所有包含 swim 的文檔都會(huì)被匹配到,ES 的這個(gè)特性也叫做全文搜索。

為了支持這個(gè)特性,ES 中會(huì)維護(hù)一個(gè)叫做 invertedindex(也叫倒排索引)的表,表內(nèi)包含了所有文檔中出現(xiàn)的所有單詞,同時(shí)記錄了這個(gè)單詞在哪個(gè)文檔中出現(xiàn)過(guò)。

例:

當(dāng)前有3個(gè)文檔

Doc1:"brown,fox,quick,the"

Doc2:"fox,quick"

Doc3:"brown,fox,the"

那么 ES 會(huì)維護(hù)如下數(shù)據(jù)結(jié)構(gòu):


image.png

這樣我們隨意搜索任意一個(gè)單詞,ES 只要遍歷一下這個(gè)表,就可以知道有些文檔被匹配到了。

倒排索引里不止記錄了單詞與文檔的對(duì)應(yīng)關(guān)系,它還維護(hù)了很多其他有用的數(shù)據(jù)。如:每個(gè)文檔一共包含了多少個(gè)單詞,單詞在不同文檔中的出現(xiàn)頻率,每個(gè)文檔的長(zhǎng)度,所有文檔的總長(zhǎng)度等等。這些數(shù)據(jù)用來(lái)給搜索結(jié)果進(jìn)行打分,如搜索單詞 apple 時(shí),那么出現(xiàn) apple 這個(gè)單詞次數(shù)最多的文檔會(huì)被優(yōu)先返回,因?yàn)樗ヅ涞拇螖?shù)最多,和我們的搜索條件關(guān)聯(lián)性最大,因此得分也最多。

倒排索引是不可更改的,一旦它被建立了,里面的數(shù)據(jù)就不會(huì)再進(jìn)行更改。這樣做就帶來(lái)了以下幾個(gè)好處:

  1. 沒(méi)有必要給倒排索引加鎖,因?yàn)椴辉试S被更改,只有讀操作,所以就不用考慮多線程導(dǎo)致互斥等問(wèn)題;
  2. 索引一旦被加載到了緩存中,大部分訪問(wèn)操作都是對(duì)內(nèi)存的讀操作,省去了訪問(wèn)磁盤(pán)帶來(lái)的 IO 開(kāi)銷;
  3. 因?yàn)榈古潘饕牟豢勺冃?,所有基于該索引而產(chǎn)生的緩存也不需要更改,因?yàn)闆](méi)有數(shù)據(jù)變更;
  4. 使用倒排索引可以壓縮數(shù)據(jù),減少磁盤(pán) IO 及對(duì)內(nèi)存的消耗;

Segment

既然倒排索引是不可更改的,那么如何添加新的數(shù)據(jù),刪除數(shù)據(jù)以及更新數(shù)據(jù)?為了解決這個(gè)問(wèn)題,Lucene 將一個(gè)大的倒排索引拆分成了多個(gè)小的段 (segment)。每個(gè) segment 本質(zhì)上就是一個(gè)倒排索引。在 Lucene 中,同時(shí)還會(huì)維護(hù)一個(gè)文件 commit point,用來(lái)記錄當(dāng)前所有可用的 segment ,當(dāng)我們?cè)谶@個(gè) commit point 上進(jìn)行搜索時(shí),就相當(dāng)于在它下面的 segment 中進(jìn)行搜索,每個(gè) segment 返回自己的搜索結(jié)果,然后進(jìn)行匯總返回給用戶。

引入了segment和commit point的概念之后,數(shù)據(jù)的更新流程如下圖:


image.png
  1. 新增的文檔首先會(huì)被存放在內(nèi)存的緩存中;
  2. 當(dāng)文檔數(shù)足夠多或者到達(dá)一定時(shí)間點(diǎn)時(shí),就會(huì)對(duì)緩存進(jìn)行 commit:
    • 生成一個(gè)新的 segment ,并寫(xiě)入磁盤(pán);
    • 生成一個(gè)新的 commit point ,記錄當(dāng)前所有可用的 segment;
    • 等待所有數(shù)據(jù)都已寫(xiě)入磁盤(pán);
  3. 打開(kāi)新增的 segment,這樣我們就可以對(duì)新增的文檔進(jìn)行搜索了;
  4. 清空緩存,準(zhǔn)備接收新的文檔;

文檔的更新與刪除

segment 是不能更改的,那么如何刪除或者更新文檔?

每個(gè) commit point 都會(huì)維護(hù)一個(gè) .del 文件,文件內(nèi)記錄了在某個(gè) segment 內(nèi)某個(gè)文檔已經(jīng)被刪除。在 segment 中,被刪除的文檔依舊是能夠被搜索到的,不過(guò)在返回搜索結(jié)果前,會(huì)根據(jù) .del 把那些已經(jīng)刪除的文檔從搜索結(jié)果中過(guò)濾掉。

對(duì)于文檔的更新,采用和刪除文檔類似的實(shí)現(xiàn)方式。當(dāng)一個(gè)文檔發(fā)生更新時(shí),首先會(huì)在 .del 中聲明這個(gè)文檔已經(jīng)被刪除,同時(shí)新的文檔會(huì)被存放到一個(gè)新的 segment 中。這樣在搜索時(shí),雖然新的文檔和老的文檔都會(huì)被匹配到,但是 .del 會(huì)把老的文檔過(guò)濾掉,返回的結(jié)果中只包含更新后的文檔。

Refresh

ES 的一個(gè)特性就是提供實(shí)時(shí)搜索,新增加的文檔可以在很短的時(shí)間內(nèi)就被搜索到。在創(chuàng)建一個(gè) commit point 時(shí),為了確保所有的數(shù)據(jù)都已經(jīng)成功寫(xiě)入磁盤(pán),避免因?yàn)閿嚯姷仍驅(qū)е戮彺嬷械臄?shù)據(jù)丟失,在創(chuàng)建 segment 時(shí)需要一個(gè) fsync 的操作來(lái)確保磁盤(pán)寫(xiě)入成功。但是如果每次新增一個(gè)文檔都要執(zhí)行一次 fsync 就會(huì)產(chǎn)生很大的性能影響。在文檔被寫(xiě)入 segment 之后,segment 首先被寫(xiě)入了文件系統(tǒng)的緩存中,這個(gè)過(guò)程僅使用很少的資源。之后 segment 會(huì)從文件系統(tǒng)的緩存中逐漸 flush 到磁盤(pán),這個(gè)過(guò)程時(shí)間消耗較大。但是實(shí)際上存放在文件緩存中的文件同樣可以被打開(kāi)讀取。ES 利用這個(gè)特性,在 segment 被 commit 到磁盤(pán)之前,就打開(kāi)對(duì)應(yīng)的 segment,這樣存放在這個(gè)segment中的文檔就可以立即被搜索到了。

image.png

上圖中灰色部分即存放在緩存中,還沒(méi)有被 commit 到磁盤(pán)的 segment 。此時(shí)這個(gè) segment 已經(jīng)可以進(jìn)行搜索。

在 ES 中,將緩存中的文檔寫(xiě)入 segment,并打開(kāi) segment 使之可以被搜索的過(guò)程叫做 refresh。默認(rèn)情況下,分片的 refresh 頻率是每秒 1 次。這就解釋了為什么 ES 聲稱提供實(shí)時(shí)搜索功能,新增加的文檔會(huì)在 1s 內(nèi)就可以進(jìn)行搜索了。

Refresh 的頻率通過(guò) index.refresh_interval:1s 參數(shù)控制,一條新寫(xiě)入 ES 的日志,在進(jìn)行 refresh 之前,是在 ES 中不能立即搜索不到的。

通過(guò)執(zhí)行 curl -XPOST 127.0.0.1:9200/_refresh,可以手動(dòng)觸發(fā) refresh 行為。

Flush 與 Translog

前面講到,refresh 行為會(huì)立即把緩存中的文檔寫(xiě)入 segment 中,但是此時(shí)新創(chuàng)建的 segment 是寫(xiě)在文件系統(tǒng)的緩存中的。如果出現(xiàn)斷電等異常,那么這部分?jǐn)?shù)據(jù)就丟失了。所以 ES 會(huì)定期執(zhí)行 flush 操作,將緩存中的 segment 全部寫(xiě)入磁盤(pán)并確保寫(xiě)入成功,同時(shí)創(chuàng)建一個(gè) commit point ,整個(gè)過(guò)程就是一個(gè)完整的 commit 過(guò)程。

但是如果斷電的時(shí)候,緩存中的 segment 還沒(méi)有來(lái)得及被 commit 到磁盤(pán),那么數(shù)據(jù)依舊會(huì)產(chǎn)生丟失。為了防止這個(gè)問(wèn)題,ES 中又引入了 translog 文件。

  1. 每當(dāng) ES 接收一個(gè)文檔時(shí),在把文檔放在 buffer 的同時(shí),都會(huì)把文檔記錄在 translog 中。


    image.png
  2. 執(zhí)行 refresh 操作時(shí),會(huì)將緩存中的文檔寫(xiě)入 segment 中,但是此時(shí) segment 是放在緩存中的,并沒(méi)有落入磁盤(pán),此時(shí)新創(chuàng)建的 segment 是可以進(jìn)行搜索的。


    image.png
  3. 按照如上的流程,新的 segment 繼續(xù)被創(chuàng)建,同時(shí)這期間新增的文檔會(huì)一直被寫(xiě)到 translog 中。


    image.png
  4. 當(dāng)達(dá)到一定的時(shí)間間隔,或者 translog 足夠大時(shí),就會(huì)執(zhí)行 commit 行為,將所有緩存中的 segment 寫(xiě)入磁盤(pán)。確保寫(xiě)入成功后,translog 就會(huì)被清空。
    image.png

    執(zhí)行 commit 并清空 translog 的行為,在 ES 中可以通過(guò) _flush API 進(jìn)行手動(dòng)觸發(fā)。

如:curl -XPOST 127.0.0.1:9200/{INDEX_NAME}|{INDEX_PATTERN}/_flush?v

通常這個(gè) flush 行為不需要人工干預(yù),交給 ES 自動(dòng)執(zhí)行就好了。同時(shí),在重啟 ES 或者關(guān)閉索引之間,建議先執(zhí)行 flush 行為,確保所有數(shù)據(jù)都被寫(xiě)入磁盤(pán),避免照成數(shù)據(jù)丟失。通過(guò)調(diào)用 sh service.sh start/restart,會(huì)自動(dòng)完成 flush 操作。

Segment 的合并

前面講到 ES 會(huì)定期的將收到的文檔寫(xiě)入新的 segment 中,這樣經(jīng)過(guò)一段時(shí)間之后,就會(huì)出現(xiàn)很多 segment 。但是每個(gè) segment 都會(huì)占用獨(dú)立的文件句柄/內(nèi)存/消耗CPU資源,而且,在查詢的時(shí)候,需要在每個(gè)segment上都執(zhí)行一次查詢,這樣是很消耗性能的。

為了解決這個(gè)問(wèn)題,ES 會(huì)自動(dòng)定期的將多個(gè)小 segment 合并為一個(gè)大的 segment 。前面講到刪除文檔的時(shí)候,并沒(méi)有真正從 segment 中將文檔刪除,而是維護(hù)了一個(gè) .del 文件,但是當(dāng) segment 合并的過(guò)程中,就會(huì)自動(dòng)將 .del 中的文檔丟掉,從而實(shí)現(xiàn)真正意義上的刪除操作。

當(dāng)新合并后的 segment 完全寫(xiě)入磁盤(pán)之后,ES 就會(huì)自動(dòng)刪除掉那些零碎的 segment,之后的查詢都在新合并的segment 上執(zhí)行。Segment 的合并會(huì)消耗大量的 IO 和 CPU 資源,這會(huì)影響查詢性能。

在 ES 中,可以使用 optimize/force merge 接口,來(lái)控制 segment 的合并。

如:curl -X POST/{INDEX_NAME}|{INDEX_PATTERN}/_optimize?max_num_segments=1

這樣,ES 就會(huì)將 segment 合并為 1 個(gè)。但是對(duì)于那些更新比較頻繁的索引,不建議使用 optimize/force merge 去執(zhí)行分片合并,交給后臺(tái)自己處理就好了。

內(nèi)存優(yōu)化

為什么會(huì)導(dǎo)致OOM?

為什么會(huì)導(dǎo)致我們的ES出現(xiàn)了OOM?這個(gè)問(wèn)題比較復(fù)雜,不能一概而論,先從內(nèi)存占用組成說(shuō)起。

  • Segment Memory(段內(nèi)存,永駐)

每個(gè) segment 對(duì)標(biāo)一個(gè) Lucene 倒排索引,而倒排索引是通過(guò)詞典 ( Term Dictionary ) 到文檔列表 (Postings List) 的映射關(guān)系,用于快速查詢。 由于詞典的 size 會(huì)很大,全部裝載到 heap 并里不現(xiàn)實(shí),因此 Lucene 為詞典做了一層前綴索引 ( Term Index ) ,這個(gè)索引在 Lucene4.0 以后采用的數(shù)據(jù)結(jié)構(gòu)是 FST ( Finite State Transducer ) 。 這種數(shù)據(jù)結(jié)構(gòu)占用空間很小,Lucene 打開(kāi)索引的時(shí)候?qū)⑵淙垦b載到內(nèi)存中,加快磁盤(pán)上詞典查詢速度的同時(shí)減少隨機(jī)磁盤(pán)訪問(wèn)次數(shù)。因此 segment 越多,占用的 heap 也越多,并且這部分內(nèi)存是無(wú)法被 GC 的。理解這點(diǎn)對(duì)于監(jiān)控和管理集群容量很重要,當(dāng)一個(gè) node 的 segment memory 占用過(guò)多,就需要考慮刪除、歸檔數(shù)據(jù),或者擴(kuò)容了。

查看 segment 的占用情況 API:

  • 按照索引維度進(jìn)行查詢:
GET _cat/segments/{INDEX_NAME}|{INDEX_PATTERN}?v&h=shard,segment,size,size.memory
  • 按照節(jié)點(diǎn)維度進(jìn)行查詢:
GET _cat/nodes?v&h=name,port,sm
  • Filter Cache(Filter結(jié)果集,永駐)

Filter cache 是用來(lái)緩存使用過(guò)的 filter 的結(jié)果集的,需要注意的是這個(gè)緩存也是常駐 heap,無(wú)法 GC。

  • Field Data Cache

在有大量排序、數(shù)據(jù)聚合的應(yīng)用場(chǎng)景,可以說(shuō) field data cache 是性能和穩(wěn)定性的殺手。 對(duì)搜索結(jié)果做排序或者聚合操作,需要將倒排索引里的數(shù)據(jù)進(jìn)行解析,然后進(jìn)行一次倒排。 這個(gè)過(guò)程非常耗費(fèi)時(shí)間,因此 ES 2.0 以前的版本主要依賴這個(gè) cache 緩存已經(jīng)計(jì)算過(guò)的數(shù)據(jù),提升性能。但是由于 heap 空間有限,當(dāng)遇到用戶對(duì)海量數(shù)據(jù)做計(jì)算的時(shí)候,就很容易導(dǎo)致 heap 吃緊,集群頻繁 GC,根本無(wú)法完成計(jì)算過(guò)程。 ES2.0以后,正式默認(rèn)啟用Doc Values 特性 ( 1.x需要手動(dòng)更改mapping開(kāi)啟 ),將 field data 在 indexing time 構(gòu)建在磁盤(pán)上,經(jīng)過(guò)一系列優(yōu)化,可以達(dá)到比之前采用 field data cache 機(jī)制更好的性能。因此需要限制對(duì) field data cache 的使用,最好是完全不用,可以極大釋放 heap 壓力。 需要注意的是,很多同學(xué)已經(jīng)升級(jí)到 ES2.0,或者 1.0 里已經(jīng)設(shè)置 mapping 啟用了 doc values,在 kibana 里仍然會(huì)遇到問(wèn)題。 這里一個(gè)陷阱就在于 kibana 的 table panel 可以對(duì)所有字段排序。 設(shè)想如果有一個(gè)字段是 analyzed 過(guò)的,而用戶去點(diǎn)擊對(duì)應(yīng)字段的排序是什么后果? 一來(lái)排序的結(jié)果并不是用戶想要的,排序的對(duì)象實(shí)際是詞典; 二來(lái) analyzed 過(guò)的字段無(wú)法利用 doc values ,需要裝載到 field data cache,數(shù)據(jù)量很大的情況下可能集群就在忙著 GC 或者根本出不來(lái)結(jié)果。

  • Bulk Queue

一般來(lái)說(shuō),Bulk queue 不會(huì)消耗很多的 heap,但是見(jiàn)過(guò)一些用戶為了提高 bulk 的速度,客戶端設(shè)置了很大的并發(fā)量,并且將 Bulk Queue 設(shè)置到不可思議的大,比如好幾千。 Bulk Queue 是做什么用的?當(dāng)所有的 bulk thread 都在忙,無(wú)法響應(yīng)新的 bulk request 的時(shí)候,將 request 在內(nèi)存里排列起來(lái),然后慢慢清掉。 這在應(yīng)對(duì)短暫的請(qǐng)求爆發(fā)的時(shí)候有用,但是如果集群本身索引速度一直跟不上,設(shè)置的好幾千的 queue 都滿了會(huì)是什么狀況呢? 取決于一個(gè) bulk 的數(shù)據(jù)量大小,乘上 queue 的大小,heap 很有可能就不夠用,內(nèi)存溢出了。

  • Indexing Buffer

Indexing Buffer 是用來(lái)緩存新數(shù)據(jù),由 data node 上所有 shards 共享,當(dāng)其滿了或者 flush interval 到了,就會(huì)以 segment file 的形式寫(xiě)入到磁盤(pán)。

  • Cluster State Buffer

ES 被設(shè)計(jì)成每個(gè) node 都可以響應(yīng)用戶的 API 請(qǐng)求,因此每個(gè) node 的內(nèi)存里都包含有一份集群狀態(tài)的拷貝。這個(gè) cluster state 包含諸如集群有多少個(gè) node,多少個(gè) index,每個(gè) index 的 mapping 是什么?有多少 shard,每個(gè) shard 的分配情況等等 ( ES 有各類 stats API 獲取這類數(shù)據(jù))。 在一個(gè)規(guī)模很大的集群,這個(gè)狀態(tài)信息可能會(huì)非常大的,耗用的內(nèi)存空間就不可忽視了。并且在 ES2.0 之前的版本,state 的更新是由 master node 做完以后全量散播到其他結(jié)點(diǎn)的。 頻繁的狀態(tài)更新都有可能給 heap 帶來(lái)壓力。

  • 超大搜索聚合結(jié)果集的 fetch

ES 是分布式搜索引擎,搜索和聚合計(jì)算除了在各個(gè) data node 并行計(jì)算以外,還需要將結(jié)果返回給匯總節(jié)點(diǎn)進(jìn)行匯總和排序后再返回。無(wú)論是搜索,還是聚合,如果返回結(jié)果的 size 設(shè)置過(guò)大,都會(huì)給 heap 造成很大的壓力,特別是數(shù)據(jù)匯聚節(jié)點(diǎn)。超大的 size 多數(shù)情況下都是用戶用例不對(duì),比如本來(lái)是想計(jì)算 cardinality,卻用了 terms aggregation + size:0 這樣的方式,對(duì)大結(jié)果集做深度分頁(yè)、一次性拉取全量數(shù)據(jù)等等。

怎么進(jìn)行內(nèi)存優(yōu)化?

  • Segment Memory

那么有哪些途徑減少 data node 上的 segment memory 呢? 總結(jié)起來(lái)有三種方法:

  • 刪除不用的索引;

刪除索引 API:

DELETE {INDEX_NAME}|{INDEX_PATTERN}
  • 關(guān)閉索引 (文件仍然存在于磁盤(pán),只是釋放掉內(nèi)存),需要的時(shí)候可以重新打開(kāi);

關(guān)閉索引 API:

POST {INDEX_NAME}|{INDEX_PATTERN}/_close
  • 定期對(duì)不再更新的索引做 optimize (ES2.0以后更改為 force merge API)。這Optimze的實(shí)質(zhì)是對(duì)segment file 強(qiáng)制做合并,可以節(jié)省大量的 segment memory;(會(huì)占用大量 IO,建議業(yè)務(wù)低峰期觸發(fā))

在合并前需要對(duì)合并速度進(jìn)行合理限制,默認(rèn)是20MBps:

PUT /_cluster/settings
{
    "persistent" : {
        "indices.store.throttle.max_bytes_per_sec" : "20mb"
    }
}

強(qiáng)制合并 API,示例表示的是最終合并為一個(gè) segment file:

POST /{INDEX_NAME}|{INDEX_PATTERN}/_forcemerge?max_num_segments=1
  • Filter Cache

默認(rèn)的 10% heap 設(shè)置工作得夠好,如果實(shí)際使用中 heap 沒(méi)什么壓力的情況下,才考慮加大這個(gè)設(shè)置。

  • Field Data Cache

升級(jí)至 ES 2.0+(我想現(xiàn)在至少是5.X了吧?),并且對(duì)需要排序的字段不進(jìn)行 analyzed,盡量使用 doc values。對(duì)于不參與搜索的字段 ( fields ), 將其 index 方法設(shè)置為 no,如果對(duì)分詞沒(méi)有需求,對(duì)參與搜索的字段,其 index方法設(shè)置為 not_analyzed

  • Bulk Queue

一般來(lái)說(shuō)官方默認(rèn)的 thread pool 設(shè)置已經(jīng)能很好的工作了,建議不要隨意去調(diào)優(yōu)相關(guān)的設(shè)置,很多時(shí)候都是適得其反的效果。

  • Indexing Buffer

這個(gè)參數(shù)的默認(rèn)值是10% heap size。根據(jù)經(jīng)驗(yàn),這個(gè)默認(rèn)值也能夠很好的工作,應(yīng)對(duì)很大的索引吞吐量。 但有些用戶認(rèn)為這個(gè) buffer 越大吞吐量越高,因此見(jiàn)過(guò)有用戶將其設(shè)置為 40% 的。到了極端的情況,寫(xiě)入速度很高的時(shí)候,40%都被占用,導(dǎo)致OOM。

  • Cluster State Buffer

在超大規(guī)模集群的情況下,可以考慮分集群并通過(guò) tribe node 連接做到對(duì)用戶透明,這樣可以保證每個(gè)集群里的 state 信息不會(huì)膨脹得過(guò)大。

  • 超大搜索聚合結(jié)果集的 fetch

避免用戶 fetch 超大搜索聚合結(jié)果集,確實(shí)需要大量拉取數(shù)據(jù)可以采用 scan & scroll API 來(lái)實(shí)現(xiàn)。

開(kāi)啟慢查詢?nèi)罩?/h3>

不論是數(shù)據(jù)庫(kù)還是搜索引擎,對(duì)于問(wèn)題的排查,開(kāi)啟慢查詢?nèi)罩臼鞘直匾模珽S 開(kāi)啟慢查詢的方式有多種,但是最常用的是調(diào)用模板 API 進(jìn)行全局設(shè)置:

PUT  /_template/{TEMPLATE_NAME}
{

  "template":"{INDEX_PATTERN}",
  "settings" : {
    "index.indexing.slowlog.level": "INFO",
    "index.indexing.slowlog.threshold.index.warn": "10s",
    "index.indexing.slowlog.threshold.index.info": "5s",
    "index.indexing.slowlog.threshold.index.debug": "2s",
    "index.indexing.slowlog.threshold.index.trace": "500ms",
    "index.indexing.slowlog.source": "1000",
    "index.search.slowlog.level": "INFO",
    "index.search.slowlog.threshold.query.warn": "10s",
    "index.search.slowlog.threshold.query.info": "5s",
    "index.search.slowlog.threshold.query.debug": "2s",
    "index.search.slowlog.threshold.query.trace": "500ms",
    "index.search.slowlog.threshold.fetch.warn": "1s",
    "index.search.slowlog.threshold.fetch.info": "800ms",
    "index.search.slowlog.threshold.fetch.debug": "500ms",
    "index.search.slowlog.threshold.fetch.trace": "200ms"
  },
  "version"  : 1
}

對(duì)于已經(jīng)存在的 index 使用 settings API:

PUT {INDEX_PAATERN}/_settings
{
    "index.indexing.slowlog.level": "INFO",
    "index.indexing.slowlog.threshold.index.warn": "10s",
    "index.indexing.slowlog.threshold.index.info": "5s",
    "index.indexing.slowlog.threshold.index.debug": "2s",
    "index.indexing.slowlog.threshold.index.trace": "500ms",
    "index.indexing.slowlog.source": "1000",
    "index.search.slowlog.level": "INFO",
    "index.search.slowlog.threshold.query.warn": "10s",
    "index.search.slowlog.threshold.query.info": "5s",
    "index.search.slowlog.threshold.query.debug": "2s",
    "index.search.slowlog.threshold.query.trace": "500ms",
    "index.search.slowlog.threshold.fetch.warn": "1s",
    "index.search.slowlog.threshold.fetch.info": "800ms",
    "index.search.slowlog.threshold.fetch.debug": "500ms",
    "index.search.slowlog.threshold.fetch.trace": "200ms"
}

這樣,在日志目錄下的慢查詢?nèi)罩揪蜁?huì)有輸出記錄必要的信息了。

{CLUSTER_NAME}_index_indexing_slowlog.log
{CLUSTER_NAME}_index_search_slowlog.log

寫(xiě)入性能優(yōu)化

之前描述了 ES 在內(nèi)存管理方面的優(yōu)化,接下來(lái)梳理下如何對(duì)寫(xiě)入性能進(jìn)行優(yōu)化,寫(xiě)入性能的優(yōu)化也和 HBase 類似,無(wú)非就是增加吞吐,而增加吞吐的方法就是增大刷寫(xiě)間隔、合理設(shè)置線程數(shù)量、開(kāi)啟異步刷寫(xiě)(允許數(shù)據(jù)丟失的情況下)。

增大刷寫(xiě)間隔

通過(guò)修改主配置文件 elasticsearch.yml 或者 Rest API 都可以對(duì) index.refresh_interval 進(jìn)行修改,增大該屬性可以提升寫(xiě)入吞吐。

PUT  /_template/{TEMPLATE_NAME}
{
  "template":"{INDEX_PATTERN}",
  "settings" : {
    "index.refresh_interval" : "30s"
  }
}
PUT {INDEX_PAATERN}/_settings
{
    "index.refresh_interval" : "30s"
}

合理設(shè)置線程數(shù)量

調(diào)整 elasticsearch.yml ,對(duì) bulk/flush 線程池進(jìn)行調(diào)優(yōu),根據(jù)本機(jī)實(shí)際配置:

threadpool.bulk.type:fixed
threadpool.bulk.size:8 #(CPU核數(shù))
threadpool.flush.type:fixed
threadpool.flush.size:8 #(CPU核數(shù))

開(kāi)啟異步刷寫(xiě)

如果允許數(shù)據(jù)丟失,可以對(duì)特定 index 開(kāi)啟異步刷寫(xiě):

PUT  /_template/{TEMPLATE_NAME}
{
  "template":"{INDEX_PATTERN}",
  "settings" : {
    "index.translog.durability": "async"
  }
}
PUT  {INDEX_PAATERN}/_settings
{
  "index.translog.durability": "async"
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容