ElasticSearch在性能優(yōu)化上分為兩大部分,一個(gè)是單機(jī)的參數(shù)優(yōu)化(這個(gè)占大部分),另一個(gè)是集群的設(shè)置,集群從一定程度上可以看做是多個(gè)單機(jī)組成的,所以它的調(diào)試偏向于集群配置。
寫在前面:
我們針對(duì)于每個(gè)點(diǎn)的調(diào)試只說一點(diǎn),因?yàn)楣俜轿臋n敘述的太繁多,無關(guān)緊要的項(xiàng)沒必要全列出來,有興趣的可以自行參考,具體的設(shè)置是否開啟,開啟比例等需要根據(jù)業(yè)務(wù)場(chǎng)景來衡量。
分片數(shù)
ES數(shù)據(jù)存在索引中,一個(gè)索引由多個(gè)分片組成,每個(gè)查詢?cè)诿總€(gè)分片的單個(gè)線程中執(zhí)行,也就是可以并行處理多個(gè)分片,對(duì)同一分片也可以進(jìn)行多個(gè)查詢和聚合。
所以我們可以適當(dāng)?shù)臑槊總€(gè)索引設(shè)置合理的分片數(shù),來提高查詢的并行能力,以此來提高速度
ES中默認(rèn)是5個(gè)分片
案例:400G的索引文件默認(rèn)分片下,聚合全部數(shù)據(jù)的一個(gè)字段需要4~5s,分片數(shù)提升到20片,速度在1s內(nèi)。
JVM內(nèi)存值設(shè)置
Elasticsearch通過 jvm.options文件中的Xms 和 Xmx來設(shè)置大小內(nèi)存
-Xms2g
-Xmx2g
注意:這個(gè)內(nèi)存并非是越大越好
由于JVM自帶了zero-based compressed oops(零基壓縮優(yōu)化):
從JDK 1.6 update14開始,64 bit JVM正式支持了 -XX:+UseCompressedOops ,這個(gè)可以壓縮指針,起到節(jié)約內(nèi)存占用的新參數(shù)。
Compressed OOPS,即對(duì)象壓縮技術(shù),壓縮引用到32位,以降低堆的占用空間。Zero Based Compressed OOPS(零基壓縮優(yōu)化)進(jìn)一步提高了壓解壓效率。
但是在超過臨界值32G內(nèi)存時(shí),這個(gè)優(yōu)化策略將會(huì)失效,通常64位JVM消耗的內(nèi)存會(huì)比32位的大1.5倍,這是因?yàn)閷?duì)象指針在64位架構(gòu)下,長(zhǎng)度會(huì)翻倍(事實(shí)上當(dāng)內(nèi)存到達(dá)40-50GB的時(shí)候,有效內(nèi)存才相當(dāng)于使用Compressed OOPS技術(shù)時(shí)候的32G內(nèi)存)
所以,一般設(shè)置到32G就可以。
禁止Swap(內(nèi)存交換)
大多數(shù)操作系統(tǒng)都試圖盡可能多地使用文件系統(tǒng)緩存,并急切地交換未使用的應(yīng)用程序內(nèi)存,可以通俗的理解為:
swap=內(nèi)存與硬盤交換數(shù)據(jù)
這種操作對(duì)于性能和節(jié)點(diǎn)的穩(wěn)定性都是非常不利的,它會(huì)導(dǎo)致垃圾收集持續(xù)數(shù)分鐘而不是毫秒,并且會(huì)導(dǎo)致節(jié)點(diǎn)響應(yīng)緩慢甚至斷開與集群的連接。
有三種方法來設(shè)置swap
停掉本機(jī)所有swap
sudo swapoff -a
降低swappiness優(yōu)先級(jí)
sudo sysctl vm.swappiness = 1
針對(duì)elasticsearch.yml設(shè)置內(nèi)存lock
bootstrap.memory_lock: true
三種方法對(duì)應(yīng)著三種不同范圍的定義,權(quán)限和范圍都是是由大到小,可根據(jù)服務(wù)器的功能靈活配置。
去掉mapping中_all域
Index中默認(rèn)會(huì)有_all的域,這個(gè)會(huì)給查詢帶來方便,但是會(huì)增加索引時(shí)間和索引數(shù)據(jù)大小
PUT my_index
{
"mappings": {
"type_2": {
"_all": {
"enabled": false
},
"properties": {...}
}
}
}
Cache比例
Indices Cache
索引緩存,用于插數(shù)據(jù)時(shí)
indices.memory.index_buffer_size: 10%
Node Query Cache
節(jié)點(diǎn)查詢緩存查詢,負(fù)責(zé)緩存查詢結(jié)果。每個(gè)Node上的所有shards都共享一個(gè)查詢緩存(只針對(duì)filter緩存)。緩存實(shí)現(xiàn)了LRU驅(qū)逐策略;
常用的三種緩存驅(qū)逐策略:
1.LRU:最近最少使用的,緩存的元素有一個(gè)時(shí)間戳,當(dāng)緩存容量滿了,而又需要騰出地方來緩存新的元素的時(shí)候,那么現(xiàn)有緩存元素中時(shí)間戳離當(dāng)前時(shí)間最遠(yuǎn)的元素將被清除緩存。
2.LFU:最少被使用,緩存的元素有一個(gè)hit屬性,hit值最小的將會(huì)被清除緩存。
3.FIFO:先進(jìn)先出。
es采用了LRU驅(qū)逐策略
設(shè)置Node查詢緩存的值,可以在每個(gè)Node上單獨(dú)設(shè)置
indices.queries.cache.size:5%
Fielddata Cache
Fielddata Cache主要應(yīng)用在text類型的字段上,是一個(gè)永久存在于堆中的緩存,fielddata 會(huì)加載索引中(針對(duì)該特定字段的) 所有的文檔,它會(huì)消耗大量的堆內(nèi)存,可以在elasticsearch.yml里設(shè)置
indices.fielddata.cache.size:60%
由于Fielddata 耗費(fèi)內(nèi)存嚴(yán)重但是效率高,所以針對(duì)特殊業(yè)務(wù)場(chǎng)景,可以配置使用。
Fielddata :https://www.elastic.co/guide/en/elasticsearch/reference/6.4/fielddata.html
批量和并發(fā)操作
批量操作
批量操作優(yōu)于單個(gè)請(qǐng)求的效率,所以盡可能多的使用批量操作。
但是這里需要大致找到批量請(qǐng)求的最佳大小,一個(gè)通用的方法是在具有單個(gè)分片的單個(gè)節(jié)點(diǎn)上運(yùn)行基準(zhǔn)測(cè)試。 首先嘗試索引100個(gè)文件,然后是200,然后是400,等等。 當(dāng)索引速度開始穩(wěn)定時(shí),我們便知道達(dá)到了數(shù)據(jù)批量請(qǐng)求的最佳大小。
java批量API:https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-docs-bulk.html
并發(fā)操作
單個(gè)線程發(fā)送批量請(qǐng)求不太可能將Elasticsearch集群的性能最大化利用,為了發(fā)揮Elasticsearch集群的最大性能,應(yīng)該從多個(gè)線程或進(jìn)程發(fā)送我們的業(yè)務(wù)請(qǐng)求。 除了更好地利用集群的資源,這應(yīng)該有助于降低每個(gè)fsync的成本。
注意:
TOO_MANY_REQUESTS(429)響應(yīng)代碼(Java客戶端的EsRejectedExecutionException),這是Elasticsearch告訴我們承受不住這么高頻率的請(qǐng)求了。
與批量調(diào)整大小請(qǐng)求類似,只有測(cè)試才能確定最佳的并發(fā)數(shù)量。 這可以通過逐漸增加工作者數(shù)量來測(cè)試,直到集群上的I / O或CPU飽和。
調(diào)整index.refresh_interval
Elasticsearch 在寫入數(shù)據(jù)時(shí)候,采用延遲寫入的策略,即數(shù)據(jù)先寫到內(nèi)存中,當(dāng)超過默認(rèn) 1 秒 (index.refresh_interval)會(huì)進(jìn)行一次寫入操作,就是將內(nèi)存中 segment 數(shù)據(jù)刷新到操作系統(tǒng)中,此時(shí)我們才能將數(shù)據(jù)搜索出來,所以這就是為什么 Elasticsearch 提供的是近實(shí)時(shí)搜索功能,而不是實(shí)時(shí)搜索功能。
index.refresh_interval默認(rèn)是1s,
經(jīng)常執(zhí)行刷新合并操作,這使得對(duì)搜索可見的索引進(jìn)行最近的更改。但是也頻繁使用了服務(wù)器性能,可以把改參數(shù)設(shè)置為不刷新或者合適的時(shí)間間隔
禁用刷新
index.refresh_interval:-1
擴(kuò)大刷新時(shí)間
index.refresh_interval:60s
優(yōu)化es的線程池
最新版本的es線程池有三種類型:
cache:這是無限制的線程池,為每個(gè)傳入的請(qǐng)求創(chuàng)建一個(gè)線程。
fixed:這是一個(gè)有著固定大小的線程池,大小由size屬性指定,允許你指定一個(gè)隊(duì)列(使用queue_size屬性指定)用來保存請(qǐng)求,直到有一個(gè)空閑的線程來執(zhí)行請(qǐng)求。如果Elasticsearch無法把請(qǐng)求放到隊(duì)列中(隊(duì)列滿了),該請(qǐng)求將被拒絕。
scaling:縮放線程池?fù)碛袆?dòng)態(tài)線程數(shù)。這個(gè)數(shù)字與工作量成正比,并且在核心值和最大值之間變化。
可指定線程池類型的操作
index:此線程池用于索引和刪除操作。默認(rèn)type為fixed,size為可用處理器的數(shù)量,size為300。
search:此線程池用于搜索和計(jì)數(shù)請(qǐng)求。默認(rèn)type為fixed,size為可用處理器的數(shù)量乘以3,size為1000。
get:此線程池用于實(shí)時(shí)的GET請(qǐng)求。默認(rèn)為fixed,size為可用處理器的數(shù)量,size默認(rèn)為1000。
bulk:此線程池用于批量操作。默認(rèn)為fixed,size為可用處理器的數(shù)量,size為50。
......
......
elasticsearch.yml中可以設(shè)置 :
threadpool.index.type: fixed
threadpool.index.size: 100
threadpool.index.queue_size: 500
thread_pool.get.queue_size
thread_pool.bulk.queue_size
thread_pool.index.queue_size
thread_pool.listener.queue_size
thread_pool.search.queue_size
thread_pool.force_merge.queue_size
G1垃圾回收機(jī)制代替默認(rèn)CMS
cms和g1的區(qū)別可以參考http://www.itdecent.cn/p/466068ce238d
替換方式為把elasticsearch.in.sh 文件內(nèi)將
if [ "x$ES_USE_IPV4" != "x" ]; then
JAVA_OPTS="$JAVA_OPTS -Djava.net.preferIPv4Stack=true"
fi
JAVA_OPTS="$JAVA_OPTS -XX:CMSInitiatingOccupancyFraction=75"
JAVA_OPTS="$JAVA_OPTS -XX:+UseCMSInitiatingOccupancyOnly"
替換為
JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC"
JAVA_OPTS="$JAVA_OPTS -XX:MaxGCPauseMillis=200"
以上就是ElasticSearch性能優(yōu)化的一些關(guān)鍵點(diǎn),后續(xù)發(fā)現(xiàn)歡迎補(bǔ)充