溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

ElasticSearch讀寫的底層原理是什么

發(fā)布時(shí)間:2021-08-05 16:41:38 來源:億速云 閱讀:308 作者:Leah 欄目:編程語(yǔ)言

ElasticSearch讀寫的底層原理是什么,很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

ES寫入/查詢底層原理

Elasticsearch寫入數(shù)據(jù)流程

1.客戶端隨機(jī)選擇一個(gè)ES集群中的節(jié)點(diǎn),發(fā)送POST/PUT請(qǐng)求,被選擇的節(jié)點(diǎn)為協(xié)調(diào)節(jié)點(diǎn)(coordinating node)2.協(xié)調(diào)節(jié)點(diǎn)查詢集群狀態(tài)信息并計(jì)算路由,將請(qǐng)求發(fā)送到真正處理請(qǐng)求的節(jié)點(diǎn)(primary shard所在的節(jié)點(diǎn))3.包含primary shard的節(jié)點(diǎn)處理寫入請(qǐng)求,并將數(shù)據(jù)同步到包含replica shard的節(jié)點(diǎn)4.coordinating node收到包含primary shard的節(jié)點(diǎn)的響應(yīng)信息,將最終結(jié)果返回給Client端

Elasticsearch讀取數(shù)據(jù)流程

1.客戶端隨機(jī)選擇一個(gè)ES集群中的節(jié)點(diǎn),發(fā)送GET請(qǐng)求,被選擇的節(jié)點(diǎn)為協(xié)調(diào)節(jié)點(diǎn)(coordinating node)2.協(xié)調(diào)節(jié)點(diǎn)查詢集群狀態(tài)信息并使用round-robin隨機(jī)輪詢算法計(jì)算出去此次請(qǐng)求的節(jié)點(diǎn),將請(qǐng)求發(fā)送到真正處理請(qǐng)求的節(jié)點(diǎn)(主分片節(jié)點(diǎn)和副本節(jié)點(diǎn)隨機(jī)分配)3.處理讀請(qǐng)求的節(jié)點(diǎn)將數(shù)據(jù)返回給協(xié)調(diào)節(jié)點(diǎn)4.協(xié)調(diào)節(jié)點(diǎn)會(huì)把文檔信息返回給Client

Elasticsearch檢索數(shù)據(jù)流程

1.客戶端發(fā)送請(qǐng)求到一個(gè)協(xié)調(diào)節(jié)點(diǎn)2.協(xié)調(diào)節(jié)點(diǎn)將搜索請(qǐng)求轉(zhuǎn)發(fā)到所有的shard對(duì)應(yīng)的primary shard或replica shard也可以3.每個(gè)shard將自己的搜索結(jié)果(其實(shí)就是一些doc id),返回給協(xié)調(diào)節(jié)點(diǎn),由協(xié)調(diào)節(jié)點(diǎn)進(jìn)行數(shù)據(jù)的合并、排序、分頁(yè)等操作,產(chǎn)出最終結(jié)果4.接著由協(xié)調(diào)節(jié)點(diǎn),根據(jù)doc id去各個(gè)節(jié)點(diǎn)上拉取實(shí)際的document數(shù)據(jù),最終返回給客戶端

這里需要注意,分頁(yè)查詢,當(dāng)from特別大時(shí)會(huì)造成大量無用數(shù)據(jù)返回到協(xié)調(diào)節(jié)點(diǎn),謹(jǐn)慎使用。

數(shù)據(jù)索引底層原理

1.先寫入buffer,在buffer里的時(shí)候數(shù)據(jù)是搜索不到的;同時(shí)將數(shù)據(jù)寫入translog日志文件。2.如果buffer到達(dá)閾值,或者到一定時(shí)間,ES會(huì)將buffer中的數(shù)據(jù)refresh到一個(gè)新的segment file中,但是此時(shí)數(shù)據(jù)不是直接進(jìn)入segment file的磁盤文件的,而是先進(jìn)入os cache的。這個(gè)過程就是refresh。3.每隔1秒鐘,es就會(huì)將buffer中的數(shù)據(jù)寫入到一個(gè)新的segment file,因此每秒鐘產(chǎn)生一個(gè)新的磁盤文件(segment file),這個(gè)segment file中就存儲(chǔ)最近1秒內(nèi)buffer中寫入的數(shù)據(jù)。如果buffer里面此時(shí)沒有數(shù)據(jù),就不會(huì)執(zhí)行refresh操作;如果buffer里面有數(shù)據(jù),默認(rèn)1秒鐘執(zhí)行一次refresh操作,刷入一個(gè)新的segment file中。4.操作系統(tǒng)里面存在操作系統(tǒng)緩存(os cache),數(shù)據(jù)寫入磁盤文件之前會(huì)先進(jìn)入os cache,先進(jìn)入操作系統(tǒng)級(jí)別的一個(gè)內(nèi)存緩存中。只要buffer中的數(shù)據(jù)被refresh到os cache中,數(shù)據(jù)就可以被檢索到了。5.可以通過es的restful api或者java api,手動(dòng)執(zhí)行一次refresh操作,就是手動(dòng)將buffer中的數(shù)據(jù)刷入os cache中,讓數(shù)據(jù)立馬就可以被搜索到。只要數(shù)據(jù)被輸入os cache中,buffer就會(huì)被清空了,因?yàn)椴恍枰A鬮uffer了,數(shù)據(jù)在translog里面已經(jīng)持久化到磁盤去一份了。

這里需要注意,分頁(yè)查詢,當(dāng)from特別大時(shí)會(huì)造成大量無用數(shù)據(jù)返回到協(xié)調(diào)節(jié)點(diǎn),謹(jǐn)慎使用。

性能調(diào)優(yōu)

系統(tǒng)層面

系統(tǒng)層面的調(diào)優(yōu)主要是內(nèi)存的設(shè)定與避免交換內(nèi)存。ES 安裝后默認(rèn)設(shè)置的堆內(nèi)存是 1GB,這很明顯是不夠的,那么接下來就會(huì)有一個(gè)問題出現(xiàn):我們要設(shè)置多少內(nèi)存給 ES 呢?其實(shí)這是要看我們集群節(jié)點(diǎn)的內(nèi)存大小,還取決于我們是否在服務(wù)器節(jié)點(diǎn)上還是否要部署其他服務(wù)。如果內(nèi)存相對(duì)很大,如 64G 及以上,并且不在 ES 集群上部署其他服務(wù),那么建議 ES 內(nèi)存可以設(shè)置為 31G-32G,因?yàn)檫@里有一個(gè) 32G 性能瓶頸問題,直白的說就是即使你給了 ES 集群大于 32G 的內(nèi)存,其性能也不一定會(huì)更加優(yōu)良,甚至?xí)蝗缭O(shè)置為 31G-32G 時(shí)候的性能。設(shè)置 ES 集群內(nèi)存的時(shí)候,還有一點(diǎn)就是確保堆內(nèi)存最小值(Xms)與最大值(Xmx)的大小是相同的,防止程序在運(yùn)行時(shí)改變堆內(nèi)存大小,這是一個(gè)很耗系統(tǒng)資源的過程。

禁止swap,一旦允許內(nèi)存與磁盤的交換,會(huì)引起致命的性能問題。swap空間是一塊磁盤空間,操作系統(tǒng)使用這塊空間保存從內(nèi)存中換出的操作系統(tǒng)不常用page數(shù)據(jù),這樣可以分配出更多的內(nèi)存做page cache。這樣通常會(huì)提升系統(tǒng)的吞吐量和IO性能,但同樣會(huì)產(chǎn)生很多問題。頁(yè)面頻繁換入換出會(huì)產(chǎn)生IO讀寫、操作系統(tǒng)中斷,這些都很影響系統(tǒng)的性能。這個(gè)值越大操作系統(tǒng)就會(huì)更加積極的使用swap空間。通過:在elasticsearch.yml 中 bootstrap.memory_lock: true, 以保持JVM鎖定內(nèi)存,保證ES的性能。

分片及副本層面

ES 是一個(gè)分布式的搜索引擎, 索引通常都會(huì)分解成不同部分, 分布在不同節(jié)點(diǎn)的部分?jǐn)?shù)據(jù)就是分片。ES 自動(dòng)管理和組織分片, 并在必要的時(shí)候?qū)Ψ制瑪?shù)據(jù)進(jìn)行再平衡分配, 所以用戶基本上不用擔(dān)心分片的處理細(xì)節(jié)。創(chuàng)建索引時(shí)默認(rèn)的分片數(shù)為 5 個(gè),并且一旦創(chuàng)建不能更改。

ES 默認(rèn)創(chuàng)建一份副本,就是說在 5 個(gè)主分片的基礎(chǔ)上,每個(gè)主分片都相應(yīng)的有一個(gè)副本分片。額外的副本有利有弊,有副本可以有更強(qiáng)的故障恢復(fù)能力,但也占了相應(yīng)副本倍數(shù)的磁盤空間。

對(duì)于副本數(shù),比較好確定,可以根據(jù)我們集群節(jié)點(diǎn)的多少與我們的存儲(chǔ)空間決定,我們的集群服務(wù)器多,并且有足夠大多存儲(chǔ)空間,可以多設(shè)置副本數(shù),一般是 1-3 個(gè)副本數(shù),如果集群服務(wù)器相對(duì)較少并且存儲(chǔ)空間沒有那么寬松,則可以只設(shè)定一份副本以保證容災(zāi)(副本數(shù)可以動(dòng)態(tài)調(diào)整)。

對(duì)于分片數(shù),是比較難確定的。因?yàn)橐粋€(gè)索引分片數(shù)一旦確定,就不能更改,所以我們?cè)趧?chuàng)建索引前,要充分的考慮到,以后我們創(chuàng)建的索引所存儲(chǔ)的數(shù)據(jù)量,否則創(chuàng)建了不合適的分片數(shù),會(huì)對(duì)我們的性能造成很大的影響。

查詢大量小分片使得每個(gè)分片處理數(shù)據(jù)速度更快了,那是不是分片數(shù)越多,我們的查詢就越快,ES 性能就越好呢?其實(shí)也不是,因?yàn)樵诓樵冞^程中,有一個(gè)分片合并的過程,如果分片數(shù)不斷的增加,合并的時(shí)間則會(huì)增加,而且隨著更多的任務(wù)需要按順序排隊(duì)和處理,更多的小分片不一定要比查詢較小數(shù)量的更大的分片更快。如果有多個(gè)并發(fā)查詢,則有很多小碎片也會(huì)降低查詢吞吐量。

如果現(xiàn)在你的場(chǎng)景是分片數(shù)不合適了,但是又不知道如何調(diào)整,那么有一個(gè)好的解決方法就是按照時(shí)間創(chuàng)建索引,然后進(jìn)行通配查詢。如果每天的數(shù)據(jù)量很大,則可以按天創(chuàng)建索引,如果是一個(gè)月積累起來導(dǎo)致數(shù)據(jù)量很大,則可以一個(gè)月創(chuàng)建一個(gè)索引。如果要對(duì)現(xiàn)有索引進(jìn)行重新分片,則需要重建索引,對(duì)于每個(gè)index的shard數(shù)量,可以根據(jù)數(shù)據(jù)總量、寫入壓力、節(jié)點(diǎn)數(shù)量等綜合考量后設(shè)定,然后根據(jù)數(shù)據(jù)增長(zhǎng)狀態(tài)定期檢測(cè)下shard數(shù)量是否合理。

騰訊云CES技術(shù)團(tuán)隊(duì)的推薦方案是:對(duì)于數(shù)據(jù)量較?。?00GB以下)的index,往往寫入壓力查詢壓力相對(duì)較低,一般設(shè)置35個(gè)shard,number_of_replicas設(shè)置為1即可(也就是一主一從,共兩副本)。對(duì)于數(shù)據(jù)量較大(100GB以上)的index:一般把單個(gè)shard的數(shù)據(jù)量控制在(20GB50GB)讓index壓力分?jǐn)傊炼鄠€(gè)節(jié)點(diǎn):可通過index.routing.allocation.total_shards_per_node參數(shù),強(qiáng)制限定一個(gè)節(jié)點(diǎn)上該index的shard數(shù)量,讓shard盡量分配到不同節(jié)點(diǎn)上綜合考慮整個(gè)index的shard數(shù)量,如果shard數(shù)量(不包括副本)超過50個(gè),就很可能引發(fā)拒絕率上升的問題,此時(shí)可考慮把該index拆分為多個(gè)獨(dú)立的index,分?jǐn)倲?shù)據(jù)量,同時(shí)配合routing使用,降低每個(gè)查詢需要訪問的shard數(shù)量。

ES系統(tǒng)方面調(diào)優(yōu)

確定集群CPU占用率高的原因,使用GET_nodes/{node}/hot_threads,如果結(jié)果為elasticsearch[{node}][search][T#10]則為查詢導(dǎo)致,如果結(jié)果為elasticsearch[{node}][bulk][T#1],則為寫入導(dǎo)致。

index.merge.scheduler.max_thread_count

在實(shí)際調(diào)優(yōu)中,cpu使用率很高,使用SSD替代機(jī)械硬盤。SSD與機(jī)械磁盤相比,具有高效的讀寫速度和穩(wěn)定性。如果不是SSD,建議設(shè)置index.merge.scheduler.max_thread_count: 1,即索引merge最大線程數(shù)設(shè)置為1 個(gè),該參數(shù)可以有效調(diào)節(jié)寫入的性能。因?yàn)樵诖鎯?chǔ)介質(zhì)上并發(fā)寫,由于尋址的原因,寫入性能不會(huì)提升,只會(huì)降低。當(dāng)有多個(gè)磁盤時(shí)可以設(shè)置為對(duì)應(yīng)的數(shù)量。

index.refresh_interval

這個(gè)參數(shù)的意思是數(shù)據(jù)寫入后幾秒可以被搜索到,默認(rèn)是 1s。每次索引的 refresh 會(huì)產(chǎn)生一個(gè)新的 lucene 段, 這會(huì)導(dǎo)致頻繁的合并行為,如果業(yè)務(wù)需求對(duì)實(shí)時(shí)性要求沒那么高,可以將此參數(shù)調(diào)大。

indices.memory.index_buffer_size

如果我們要進(jìn)行非常重的高并發(fā)寫入操作,那么最好將它調(diào)大一些,index buffer的大小是所有的shard公用的,對(duì)于每個(gè) shard來說,最多給512MB,因?yàn)樵俅笮阅芫蜎]什么提升了。ES會(huì)將這個(gè)設(shè)置作為每個(gè)shard共享的index buffer,那些特別活躍的shard會(huì)更多的使用這個(gè) buffer。默認(rèn)這個(gè)參數(shù)的值是10%,也就是jvm堆內(nèi)存的10%。

translog

ES為了保證數(shù)據(jù)不丟失,每次index、bulk、delete、update完成的時(shí)候,一定會(huì)觸發(fā)刷新translog到磁盤上。在提高數(shù)據(jù)安全性的同時(shí)當(dāng)然也降低了性能。如果你不在意這點(diǎn)可能性,還是希望性能優(yōu)先,可以設(shè)置如下參數(shù):

"index.translog": {
 "sync_interval": "120s",     #sync間隔調(diào)高
 "durability": "async",      # 異步更新
 "flush_threshold_size":"1g" #log文件大小
}

這樣設(shè)定的意思是開啟異步寫入磁盤,并設(shè)定寫入的時(shí)間間隔與大小,有助于寫入性能的提升。

replica數(shù)目

為了讓創(chuàng)建的es index在每臺(tái)datanode上均勻分布,同一個(gè)datanode上同一個(gè)index的shard數(shù)目不應(yīng)超過3個(gè)。計(jì)算公式: (number_of_shard*(1+number_of_replicas)) < 3*number_of_datanodes每臺(tái)機(jī)器上分配的shard數(shù)目,index.routing.allocation.total_shards_per_node: 2

merge相關(guān)參數(shù)

"index.merge.policy.floor_segment": "100mb"
"index.merge.scheduler.max_thread_count": "1"
"index.merge.policy.min_merge_size": "10mb"

超時(shí)參數(shù)

discovery.zen.ping_timeout 判斷 master 選舉過程中,發(fā)現(xiàn)其他 node 存活的超時(shí)設(shè)置
discovery.zen.fd.ping_interval 節(jié)點(diǎn)被 ping 的頻率,檢測(cè)節(jié)點(diǎn)是否存活
discovery.zen.fd.ping_timeout 節(jié)點(diǎn)存活響應(yīng)的時(shí)間,默認(rèn)為 30s,如果網(wǎng)絡(luò)可能存在隱患,可以適當(dāng)調(diào)大
discovery.zen.fd.ping_retries ping 失敗/超時(shí)多少導(dǎo)致節(jié)點(diǎn)被視為失敗,默認(rèn)為 3

Linux層面相關(guān)調(diào)優(yōu)

Linux中,每個(gè)進(jìn)程默認(rèn)打開的最大文件句柄數(shù)是1000,對(duì)于服務(wù)器進(jìn)程來說,顯然太小,通過修改/etc/security/limits.conf來增大打開最大句柄數(shù)* - nofile 65535

vm.dirty_background_ratio: 這個(gè)參數(shù)指定了當(dāng)文件系統(tǒng)緩存臟頁(yè)數(shù)量達(dá)到系統(tǒng)內(nèi)存百分之多少時(shí)(如5%)就會(huì)觸發(fā)pdflush/flush/kdmflush等后臺(tái)回寫進(jìn)程運(yùn)行,將一定緩存的臟頁(yè)異步地刷入外存;

vm.dirty_ratio: 該參數(shù)則指定了當(dāng)文件系統(tǒng)緩存臟頁(yè)數(shù)量達(dá)到系統(tǒng)內(nèi)存百分之多少時(shí)(如10%),系統(tǒng)不得不開始處理緩存臟頁(yè)(因?yàn)榇藭r(shí)臟頁(yè)數(shù)量已經(jīng)比較多,為了避免數(shù)據(jù)丟失需要將一定臟頁(yè)刷入外存);在此過程中很多應(yīng)用進(jìn)程可能會(huì)因?yàn)橄到y(tǒng)轉(zhuǎn)而處理文件IO而阻塞。

把該參數(shù)適當(dāng)調(diào)小。如果cached的臟數(shù)據(jù)所占比例(這里是占MemTotal的比例)超過這個(gè)設(shè)置,系統(tǒng)會(huì)停止所有的應(yīng)用層的IO寫操作,等待刷完數(shù)據(jù)后恢復(fù)IO。所以萬一觸發(fā)了系統(tǒng)的這個(gè)操作,對(duì)于用戶來說影響非常大的。

sysctl -w vm.dirty_ratio=10
sysctl -w vm.dirty_background_ratio=5

可以修改/etc/sysctl.conf文件進(jìn)行持久化。

ES使用建議

讀數(shù)據(jù)

避免大結(jié)果集和深翻,ES 提供了 Scroll 和 Scroll-Scan 這兩種查詢模式。

Scroll:是為檢索大量的結(jié)果而設(shè)計(jì)的。例如,我們需要查詢 1~100 頁(yè)的數(shù)據(jù),每頁(yè) 100 條數(shù)據(jù)。

如果使用Search查詢:每次都需要在每個(gè)分片上查詢得分最高的 from+100 條數(shù)據(jù),然后協(xié)同節(jié)點(diǎn)把收集到的 n×(from+100)條數(shù)據(jù)聚合起來再進(jìn)行一次排序。

每次返回from+1開始的100條數(shù)據(jù),并且要重復(fù)執(zhí)行100次。

如果使用Scroll查詢:在各個(gè)分片上查詢10000條數(shù)據(jù),協(xié)同節(jié)點(diǎn)聚合n×10000條數(shù)據(jù)進(jìn)行合并、排序,并將排名前10000的結(jié)果快照起來。這樣做的好處是減少了查詢和排序的次數(shù)。

插入索引自動(dòng)生成 id

當(dāng)寫入端使用特定的 id 將數(shù)據(jù)寫入 ES 時(shí),ES 會(huì)檢查對(duì)應(yīng)的索引下是否存在相同的 id,這個(gè)操作會(huì)隨著文檔數(shù)量的增加使消耗越來越大,所以如果業(yè)務(wù)上沒有硬性需求建議使用 ES 自動(dòng)生成的 id,加快寫入速率。

避免稀疏索引

索引稀疏之后,會(huì)導(dǎo)致索引文件增大。ES的keyword,數(shù)組類型采用doc_values結(jié)構(gòu),即使字段是空值,每個(gè)文檔也會(huì)占用一定的空間,所以稀疏索引會(huì)造成磁盤增大,導(dǎo)致查詢和寫入效率降低。

參數(shù)調(diào)優(yōu)匯總

index.merge.scheduler.max_thread_count:1 # 索引 merge 最大線程數(shù)
indices.memory.index_buffer_size:30% # 內(nèi)存
index.translog.durability:async # 這個(gè)可以異步寫硬盤,增大寫的速度
index.translog.sync_interval:120s #translog 間隔時(shí)間
discovery.zen.ping_timeout:120s # 心跳超時(shí)時(shí)間
discovery.zen.fd.ping_interval:120s     # 節(jié)點(diǎn)檢測(cè)時(shí)間
discovery.zen.fd.ping_timeout:120s     #ping 超時(shí)時(shí)間
discovery.zen.fd.ping_retries:6 # 心跳重試次數(shù)
thread_pool.bulk.size:20 # 寫入線程個(gè)數(shù) 由于我們查詢線程都是在代碼里設(shè)定好的,我這里只調(diào)節(jié)了寫入的線程數(shù)
thread_pool.bulk.queue_size:1000 # 寫入線程隊(duì)列大小
index.refresh_interval:300s #index 刷新間隔
bootstrap.memory_lock: true#以保持JVM鎖定內(nèi)存,保證ES的性能。

ES大批量寫入提高性能的策略

用bulk批量寫入

你如果要往es里面灌入數(shù)據(jù)的話,那么根據(jù)你的業(yè)務(wù)場(chǎng)景來,如果你的業(yè)務(wù)場(chǎng)景可以支持讓你將一批數(shù)據(jù)聚合起來,一次性寫入es,那么就盡量采用bulk的方式,每次批量寫個(gè)幾百條這樣子。

bulk批量寫入的性能比你一條一條寫入大量的document的性能要好很多。但是如果要知道一個(gè)bulk請(qǐng)求最佳的大小,需要對(duì)單個(gè)es node的單個(gè)shard做壓測(cè)。先bulk寫入100個(gè)document,然后200個(gè),400個(gè),以此類推,每次都將bulk size加倍一次。如果bulk寫入性能開始變平緩的時(shí)候,那么這個(gè)就是最佳的bulk大小。并不是bulk size越大越好,而是根據(jù)你的集群等環(huán)境具體要測(cè)試出來的,因?yàn)樵酱蟮腷ulk size會(huì)導(dǎo)致內(nèi)存壓力過大,因此最好一個(gè)請(qǐng)求不要發(fā)送超過10mb的數(shù)據(jù)量。

先確定一個(gè)是bulk size,此時(shí)就盡量是單線程,一個(gè)es node,一個(gè)shard,進(jìn)行測(cè)試。看看單線程最多一次性寫多少條數(shù)據(jù),性能是比較好的。

使用多線程將數(shù)據(jù)寫入es

單線程發(fā)送bulk請(qǐng)求是無法最大化es集群寫入的吞吐量的。如果要利用集群的所有資源,就需要使用多線程并發(fā)將數(shù)據(jù)bulk寫入集群中。為了更好的利用集群的資源,這樣多線程并發(fā)寫入,可以減少每次底層磁盤fsync的次數(shù)和開銷。首先對(duì)單個(gè)es節(jié)點(diǎn)的單個(gè)shard做壓測(cè),比如說,先是2個(gè)線程,然后是4個(gè)線程,然后是8個(gè)線程,16個(gè),每次線程數(shù)量倍增。一旦發(fā)現(xiàn)es返回了TOO_MANY_REQUESTS的錯(cuò)誤,JavaClient也就是EsRejectedExecutionException。此時(shí)那么就說明es是說已經(jīng)到了一個(gè)并發(fā)寫入的最大瓶頸了,此時(shí)我們就知道最多只能支撐這么高的并發(fā)寫入了。

增加refresh間隔

默認(rèn)的refresh間隔是1s,用index.refresh_interval參數(shù)可以設(shè)置,這樣會(huì)其強(qiáng)迫es每秒中都將內(nèi)存中的數(shù)據(jù)寫入磁盤中,創(chuàng)建一個(gè)新的segment file。正是這個(gè)間隔,讓我們每次寫入數(shù)據(jù)后,1s以后才能看到。但是如果我們將這個(gè)間隔調(diào)大,比如30s,可以接受寫入的數(shù)據(jù)30s后才看到,那么我們就可以獲取更大的寫入吞吐量,因?yàn)?0s內(nèi)都是寫內(nèi)存的,每隔30s才會(huì)創(chuàng)建一個(gè)segment file。

禁止refresh和replia

如果我們要一次性加載大批量的數(shù)據(jù)進(jìn)es,可以先禁止refresh和replia復(fù)制,將index.refresh_interval設(shè)置為-1,將index.number_of_replicas設(shè)置為0即可。這可能會(huì)導(dǎo)致我們的數(shù)據(jù)丟失,因?yàn)闆]有refresh和replica機(jī)制了。但是不需要?jiǎng)?chuàng)建segment file,也不需要將數(shù)據(jù)replica復(fù)制到其他的replica shasrd上面去。此時(shí)寫入的速度會(huì)非???,一旦寫完之后,可以將refresh和replica修改回正常的狀態(tài)。

禁止swapping交換內(nèi)存

如果要將es jvm內(nèi)存交換到磁盤,再交換回內(nèi)存,大量磁盤IO,性能很差

給filesystem cache更多的內(nèi)存

filesystem cache被用來執(zhí)行更多的IO操作,如果我們能給filesystemcache更多的內(nèi)存資源,那么es的寫入性能會(huì)好很多。

使用自動(dòng)生成的id

如果我們要手動(dòng)給es document設(shè)置一個(gè)id,那么es需要每次都去確認(rèn)一下那個(gè)id是否存在,這個(gè)過程是比較耗費(fèi)時(shí)間的。如果我們使用自動(dòng)生成的id,那么es就可以跳過這個(gè)步驟,寫入性能會(huì)更好。對(duì)于你的業(yè)務(wù)中的表id,可以作為es document的一個(gè)field。

用性能更好的硬件

我們可以給filesystem cache更多的內(nèi)存,也可以使用SSD替代機(jī)械硬盤,避免使用NAS等網(wǎng)絡(luò)存儲(chǔ),考慮使用RAID 0來?xiàng)l帶化存儲(chǔ)提升磁盤并行讀寫效率,等等。

index buffer

如果我們要進(jìn)行非常重的高并發(fā)寫入操作,那么最好將index buffer調(diào)大一些,indices.memory.index_buffer_size,這個(gè)可以調(diào)節(jié)大一些,設(shè)置的這個(gè)index buffer大小,是所有的shard公用的,但是如果除以shard數(shù)量以后,算出來平均每個(gè)shard可以使用的內(nèi)存大小,一般建議,但是對(duì)于每個(gè)shard來說,最多給512mb,因?yàn)樵俅笮阅芫蜎]什么提升了。es會(huì)將這個(gè)設(shè)置作為每個(gè)shard共享的index buffer,那些特別活躍的shard會(huì)更多的使用這個(gè)buffer。默認(rèn)這個(gè)參數(shù)的值是10%,也就是jvm heap的10%,如果我們給jvmheap分配10gb內(nèi)存,那么這個(gè)index buffer就有1gb,對(duì)于兩個(gè)shard共享來說,是足夠的了。

ES查詢提高性能的策略

1.query_string 或 multi_match的查詢字段越多, 查詢?cè)铰???梢栽趍apping階段,利用copy_to屬性將多字段的值索引到一個(gè)新字段,multi_match時(shí),用新的字段查詢。2.日期字段的查詢, 尤其是用now 的查詢實(shí)際上是不存在緩存的,因此, 可以從業(yè)務(wù)的角度來考慮是否一定要用now, 畢竟利用query cache 是能夠大大提高查詢效率的。3.查詢結(jié)果集的大小不能隨意設(shè)置成大得離譜的值, 如query.setSize不能設(shè)置成 Integer.MAX_VALUE, 因?yàn)镋S內(nèi)部需要建立一個(gè)數(shù)據(jù)結(jié)構(gòu)來放指定大小的結(jié)果集數(shù)據(jù)。4.盡量避免使用script,萬不得已需要使用的話,選擇painless & experssions 引擎。一旦使用script查詢,一定要注意控制返回,千萬不要有死循環(huán)(如下錯(cuò)誤的例子),因?yàn)镋S沒有腳本運(yùn)行的超時(shí)控制,只要當(dāng)前的腳本沒執(zhí)行完,該查詢會(huì)一直阻塞。

如:{
   “script_fields”:{
       “test1”:{
           “l(fā)ang”:“groovy”,
           “script”:“while(true){print 'don’t use script'}”
       }
   }
}

5. 避免層級(jí)過深的聚合查詢, 層級(jí)過深的group by , 會(huì)導(dǎo)致內(nèi)存、CPU消耗,建議在服務(wù)層通過程序來組裝業(yè)務(wù),也可以通過pipeline的方式來優(yōu)化。

6. 復(fù)用預(yù)索引數(shù)據(jù)方式來提高AGG性能:

如通過 terms aggregations 替代 range aggregations, 如要根據(jù)年齡來分組,分組目標(biāo)是: 少年(14歲以下) 青年(14-28) 中年(29-50) 老年(51以上), 可以在索引的時(shí)候設(shè)置一個(gè)age_group字段,預(yù)先將數(shù)據(jù)進(jìn)行分類。從而不用按age來做range aggregations, 通過age_group字段就可以了。

7. Cache的設(shè)置及使用:

a) QueryCache: ES查詢的時(shí)候,使用filter查詢會(huì)使用query cache, 如果業(yè)務(wù)場(chǎng)景中的過濾查詢比較多,建議將querycache設(shè)置大一些,以提高查詢速度。

indices.queries.cache.size:10%(默認(rèn)),可設(shè)置成百分比,也可設(shè)置成具體值,如256mb。

當(dāng)然也可以禁用查詢緩存(默認(rèn)是開啟), 通過index.queries.cache.enabled:false設(shè)置。

b) FieldDataCache: 在聚類或排序時(shí),field data cache會(huì)使用頻繁,因此,設(shè)置字段數(shù)據(jù)緩存的大小,在聚類或排序場(chǎng)景較多的情形下很有必要,可通過indices.fielddata.cache.size:30% 或具體值10GB來設(shè)置。但是如果場(chǎng)景或數(shù)據(jù)變更比較頻繁,設(shè)置cache并不是好的做法,因?yàn)榫彺婕虞d的開銷也是特別大的。

c) ShardRequestCache: 查詢請(qǐng)求發(fā)起后,每個(gè)分片會(huì)將結(jié)果返回給協(xié)調(diào)節(jié)點(diǎn)(Coordinating Node), 由協(xié)調(diào)節(jié)點(diǎn)將結(jié)果整合。

如果有需求,可以設(shè)置開啟; 通過設(shè)置index.requests.cache.enable: true來開啟。

不過,shard request cache只緩存hits.total, aggregations, suggestions類型的數(shù)據(jù),并不會(huì)緩存hits的內(nèi)容。也可以通過設(shè)置indices.requests.cache.size: 1%(默認(rèn))來控制緩存空間大小。

 看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝您對(duì)億速云的支持。
向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI