日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

转-聚合查询变慢-详解Elasticsearch的Global Ordinals与High Cardinality

發(fā)布時(shí)間:2023/12/3 60 豆豆
生活随笔 收集整理的這篇文章主要介紹了 转-聚合查询变慢-详解Elasticsearch的Global Ordinals与High Cardinality 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

轉(zhuǎn)自: https://blog.csdn.net/zwgdft/article/details/83215977

?

【README】

?Elasticsearch中的概念很多,本文將從筆者在實(shí)踐過(guò)程中遇到的問(wèn)題出發(fā),逐步詳細(xì)介紹 Global OrdinalsHigh Cardinality ,這也是筆者的認(rèn)知過(guò)程。文中的Elasticsearch 版本為5.5。

背景

??故事是這樣的,因?yàn)闃I(yè)務(wù)需要,我們?cè)陧?xiàng)目中設(shè)計(jì)了一種針對(duì)Elasticsearch數(shù)據(jù)的異步去重方法(注:關(guān)于Elasticsearch數(shù)據(jù)去重,筆者會(huì)在另一篇博文中更加詳細(xì)介紹),基本思路是:

  • 為每一條數(shù)據(jù)計(jì)算hash值,作為document的一個(gè)字段(keyword類型)插入到Elasticsearch中,數(shù)據(jù)格式簡(jiǎn)化如下:
{"timestamp": 1540099182,"msgType": 1210,......"hash": "31a2c683dccb83ef8b8d1ee43290df62" }
  • ?
  • 每隔一段時(shí)間,運(yùn)行一次檢測(cè)腳本,檢查Elasticsearch中的數(shù)據(jù)是否有重復(fù),相關(guān)查詢語(yǔ)句如下(這里,terms聚合用于發(fā)現(xiàn)給定時(shí)間范圍內(nèi)是否有超過(guò)2條hash值一樣的數(shù)據(jù),top_hits聚合用于找出重復(fù)數(shù)據(jù)組中的具體數(shù)據(jù)信息,然后刪除掉重復(fù)的數(shù)據(jù)即可):
{"size": 0,"query": {"bool": {"filter": [{ "range":{ "timestamp":{ "gte": 1540087200,"lt": 1540087500}}}]}},"aggs": {"duplications": {"terms": {"field": "hash","min_doc_count": 2,"size": 500},"aggs": {"top_duplications": {"top_hits": {"size": 3}}}}} }
  • ?

??這樣一個(gè)方案,因?yàn)橹皇窃跀?shù)據(jù)集中增加了一個(gè)hash字段,并且去重是異步的,不會(huì)影響到原有的設(shè)計(jì),所以在通過(guò)相關(guān)的功能性測(cè)試后就上線了。然而,運(yùn)行一段時(shí)間后,出現(xiàn)了嚴(yán)重問(wèn)題:

  • 隨著新數(shù)據(jù)的寫(xiě)入,上述的查詢語(yǔ)句變得越來(lái)越慢,從秒級(jí)逐步變成要20多秒,并且在數(shù)據(jù)量超過(guò)10億條后,每次查詢都會(huì)使內(nèi)存超過(guò)80%;
  • index的存儲(chǔ)空間比原先增加了近一倍

??對(duì)于類似上述的查詢語(yǔ)句,Elasticsearch會(huì)先根據(jù)Filter條件找出匹配的document,然后再進(jìn)行聚合運(yùn)算。在我們的業(yè)務(wù)中,每次查詢2小時(shí)內(nèi)的數(shù)據(jù),并且數(shù)據(jù)的寫(xiě)入是勻速的,這意味著每次匹配出來(lái)的document個(gè)數(shù)基本是固定的,那么為何會(huì)出現(xiàn)這個(gè)查詢?cè)絹?lái)越慢的問(wèn)題?而且,我們發(fā)現(xiàn),即使Filter匹配的document個(gè)數(shù)為0,也同樣需要很久才能返回結(jié)果。

??另一方面,經(jīng)過(guò)對(duì)比驗(yàn)證,可以確定是新增加的hash字段導(dǎo)致了數(shù)據(jù)存儲(chǔ)空間比原先增加了近一倍。
??帶著這些問(wèn)題,筆者進(jìn)行了詳細(xì)的調(diào)研,最終鎖定Global OrdinalsHigh Cardinality兩個(gè)核心概念。其中,github上面的一個(gè)issue Terms aggregation speed is proportional to field cardinality 給了很大的啟發(fā)。

Global Ordinals

什么是Ordinals??

??假設(shè)有10億條數(shù)據(jù),每條數(shù)據(jù)有一個(gè)字段status(keyword類型),其值有三種可能性:status_pending、status_published、status_deleted,那么每條數(shù)據(jù)至少需要14-16 Bytes,也就是說(shuō)需要將近15GB內(nèi)存才能裝下所有數(shù)據(jù)。

Doc | Term ------------------------------- 0 | status_pending 1 | status_deleted 2 | status_published 3 | status_pending
  • ?

??為了減少內(nèi)存使用,考慮將字符串排序后進(jìn)行編號(hào),形成一張映射表,然后在每條數(shù)據(jù)中使用相應(yīng)字符串的序號(hào)來(lái)表示。通過(guò)這樣的設(shè)計(jì),可以將所需內(nèi)存從15 GB減少為1 GB左右。
??這里的映射表,或者說(shuō)映射表中的序號(hào),就是Ordinals。

Ordinal | Term ------------------------------- 0 | status_deleted 1 | status_pending 2 | status_publishedDoc | Ordinal ------------------------------- 0 | 0 # deleted 1 | 2 # published 2 | 1 # pending 3 | 0 # deleted
  • ?

什么是Global Ordinals??

??當(dāng)我們對(duì)status字段做Terms聚合查詢時(shí),請(qǐng)求會(huì)透過(guò)Coordinate Node分散到Shard所在的Node中執(zhí)行,而針對(duì)每個(gè)Shard的查詢又會(huì)分散到多個(gè)Segment中去執(zhí)行。
??上述的Ordinals是per-segment ordinals,是針對(duì)每個(gè)Segment里面的數(shù)據(jù)而言,意味著同一個(gè)字符串在不同的per-segment ordinals中可能對(duì)應(yīng)的序號(hào)是不同的。比如,在Segment 1中只有status_deleted(0)和status_published(1)兩個(gè)值,而Segment 2中有3個(gè)值:status_deleted(0),status_pending(1),status_published(2)。
??這樣就面臨一個(gè)抉擇:方案一,在完成per-segment的查詢后,將相應(yīng)的序號(hào)轉(zhuǎn)換成字符串,返回到Shard層面進(jìn)行合并;方案二,構(gòu)建一個(gè)Shard層面的Global Ordinals,實(shí)現(xiàn)與per-segment ordinals的映射,就可以在Shard層面完成聚合后再轉(zhuǎn)換成字符串。
??經(jīng)過(guò)權(quán)衡,Elasticsearch(Lucene)選擇了方案二作為默認(rèn)方法:構(gòu)建Global Ordinals。

為何會(huì)影響聚合查詢?

??構(gòu)建Global Ordinals的目的是為了減少內(nèi)存使用、加快聚合統(tǒng)計(jì),在大多數(shù)情況下其表現(xiàn)出來(lái)的性能都非常好。之所以會(huì)影響到查詢性能,與其構(gòu)建時(shí)機(jī)有關(guān):

  • 由于Global Ordinals是Shard級(jí)別的,因此當(dāng)一個(gè)Shard的Segment發(fā)生變動(dòng)時(shí)就需要重新構(gòu)建Global Ordinals,比如有新數(shù)據(jù)寫(xiě)入導(dǎo)致產(chǎn)生新的Segment、Segment Merge等情況。當(dāng)然,如果Segment沒(méi)有變動(dòng),那么構(gòu)建一次后就可以一直利用緩存了(適用于歷史數(shù)據(jù))。
  • 默認(rèn)情況下,Global Ordinals是在收到聚合查詢請(qǐng)求并且該查詢會(huì)命中相關(guān)字段時(shí)構(gòu)建,而構(gòu)建動(dòng)作是在查詢最開(kāi)始做的,即在Filter之前。

??這樣的構(gòu)建方式,在遇到某個(gè)字段的值種類很多(即下文所述的High Cardinary問(wèn)題)時(shí)會(huì)變的非常慢,會(huì)嚴(yán)重影響聚合查詢速度,即使Filter出來(lái)的document很少也需要花費(fèi)很久,也就是上文筆者遇到的問(wèn)題,即在High Cardinary情況下,構(gòu)建Global Ordinals非常慢。因?yàn)槲覀冃录拥膆ash字段對(duì)于每條數(shù)據(jù)都不一樣,所以當(dāng)寫(xiě)入越來(lái)越多的數(shù)據(jù)后,聚合查詢?cè)絹?lái)越慢(大概超過(guò)5000W條之后)。

有哪些優(yōu)化方法?

??雖然在Lucene 7.1中,針對(duì)global ordinals的構(gòu)建有些優(yōu)化(LUCENE-7905),但是仍然不能避免這樣的問(wèn)題。目前有這樣幾種優(yōu)化方法(或者說(shuō)是緩解之法,目前尚未發(fā)現(xiàn)完美的方法):

  • 增加Shard個(gè)數(shù)。因?yàn)镚lobal Ordinals是Shard層面的,增加Shard個(gè)數(shù)也許可以緩解問(wèn)題,前提是:第一,要能確定有問(wèn)題的字段的值種類可以通過(guò)該方式減少在單個(gè)Shard中的量;第二,確保Shard的個(gè)數(shù)增加不會(huì)影響到整體的性能。
  • 延長(zhǎng)refresh interval,即減少構(gòu)建Global Ordinals的次數(shù)來(lái)緩解其影響,前提是要能接受數(shù)據(jù)的非實(shí)時(shí)性。
  • 修改execution_hint的值。在Terms聚合中,可以設(shè)置執(zhí)行方式是map還是global_ordinals,前者的意思是直接使用該字段的字符串值來(lái)做聚合,即無(wú)需構(gòu)建Global Ordinals。這樣的方式,適用于可以確定匹配文檔數(shù)據(jù)量的場(chǎng)景,并且不會(huì)引起內(nèi)存的暴增,比如在筆者的業(yè)務(wù)場(chǎng)景中,每次只查詢2小時(shí)內(nèi)的數(shù)據(jù)量。這也是當(dāng)前我們的優(yōu)化方法。
GET /_search {"aggs" : {"tags" : {"terms" : {"field" : "status","execution_hint": "map" }}} }
  • ?

High Cardinality?

??相信看完上文,讀者已經(jīng)知道什么是High Cardinality了。所謂High Cardinality,指的是Large Number of Unique Values,即某個(gè)字段的值有很多很多種,比如筆者業(yè)務(wù)中的那個(gè)hash字段。在Elasticsearch,High Cardinality會(huì)帶來(lái)各種問(wèn)題,百害而無(wú)一利,所以應(yīng)該盡量避免,避免不了也要做到心中有數(shù),在出問(wèn)題時(shí)可以及時(shí)調(diào)整。

  • High Cardinality會(huì)導(dǎo)致構(gòu)建Global Ordinals過(guò)程變慢,從而導(dǎo)致聚合查詢變慢、內(nèi)存使用過(guò)高。
  • High Cardinality會(huì)導(dǎo)致壓縮比率降低,從而導(dǎo)致存儲(chǔ)空間增加,特別是像hash值這樣完全隨機(jī)的字符串。
  • 對(duì)High Cardinality字段執(zhí)行Cardinality聚合查詢時(shí),會(huì)受到精度控制從而導(dǎo)致結(jié)果不精確。

?

??本文結(jié)合筆者在實(shí)踐過(guò)程中遇到的由High Cardinality引起Global Ordinals構(gòu)建過(guò)慢,從而導(dǎo)致聚合查詢變慢的問(wèn)題,闡述了Global Ordinals和High Cardinality兩個(gè)核心概念,希望對(duì)遇到類似問(wèn)題的人有所幫助。目前,針對(duì)我們的業(yè)務(wù)場(chǎng)景,相關(guān)的調(diào)整有:第一,使用"execution_hint": "map"來(lái)避免構(gòu)建Global Ordinals;第二,嘗試在數(shù)據(jù)上傳端增加對(duì)壓縮友好的唯一鍵來(lái)作為去重對(duì)象,比如uuid4;第三,減小index的切割時(shí)間,比如從weekly index變成daily index,從而降低index中單個(gè)shard的數(shù)據(jù)量。

?

?

總結(jié)

以上是生活随笔為你收集整理的转-聚合查询变慢-详解Elasticsearch的Global Ordinals与High Cardinality的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。