生產級搜索引擎ES性能調優實戰

歡迎關注我的頭條號:Wooola,10年Java軟件開發及架構設計經驗,專注於Java、Golang、微服務架構,致力於每天分享原創文章、快樂編碼和開源技術。 

生產級搜索引擎ES性能調優實戰

1、所有的修改都可以在elasticsearch.yml裡面修改,也可以通過api來修改。推薦用api比較靈活

1.不同分片之間的數據同步是一個很大的花費,默認是1s同步,如果我們不要求實時性,我們可以執行如下:

$ curl -XPUT 'http://localhost:9200/twitter/' -d '{
"settings" : {
"index" : {
"refresh_interval":"60s"
}
}
}'

此處我們是修改為60s 其實可以改為-1s 這樣就是不刷新,我們需要在查詢的時候進行一次索引刷新然後再查詢,這個嘛就得看你們用戶能容忍多少時間長度了。

2、選擇正確的存儲

一般來說,如果運行的是64位操作系統,你應該選擇mmapfs。如果沒有運行64位操作系統,為UNIX系統選擇niofs,為Windows系統選擇simplefs。如果你可以容忍一個易失的存儲,但希望它非常快,可以看看memory存儲,它會給你最好的索引訪問性能,但需要足夠的內存來處理所有索引文件、索引和查詢。

3、優化es的線程池

cache:這是無限制的線程池,為每個傳入的請求創建一個線程。

fixed:這是一個有著固定大小的線程池,大小由size屬性指定,允許你指定一個隊列(使用queue_size屬性指定)用來保存請求,直到有一個空閒的線程來執行請求。如果Elasticsearch無法把請求放到隊列中(隊列滿了),該請求將被拒絕。有很多線程池(可以使用type屬性指定要配置的線程類型),然而,對於性能來說,最重要的是下面幾個。

index:此線程池用於索引和刪除操作。它的類型默認為fixed,size默認為可用處理器的數量,隊列的size默認為300。

search:此線程池用於搜索和計數請求。它的類型默認為fixed,size默認為可用處理器的數量乘以3,隊列的size默認為1000。

suggest:此線程池用於建議器請求。它的類型默認為fixed,size默認為可用處理器的數量,隊列的size默認為1000。

get:此線程池用於實時的GET請求。它的類型默認為fixed,size默認為可用處理器的數量,隊列的size默認為1000。

bulk:你可以猜到,此線程池用於批量操作。它的類型默認為fixed,size默認為可用處理器的數量,隊列的size默認為50。

percolate:此線程池用於預匹配器操作。它的類型默認為fixed,size默認為可用處理器的數量,隊列的size默認為1000。

elasticsearch.yml中可以設置 :

threadpool.index.type: fixed
threadpool.index.size: 100
threadpool.index.queue_size: 500

當然可以restAPI設置

curl -XPUT 'localhost:9200/_cluster/settings' -d '{
"transient": {
"threadpool.index.type": "fixed",
"threadpool.index.size": 100,
"threadpool.index.queue_size": 500
}
}'

4、index過於龐大導致es經常奔潰

es最近老是掛掉,無緣無故,表現症狀為 對於大小超過100g的index(5個分片 1e數據量左右)插入超級慢,由於機器資源有限 ,只能想出 將每一天的數據建立一個index+“yyyy-MM-dd” 這樣可以有效緩解我們集群的壓力,有人會說如果改成這種方案那麼之前寫的查詢豈不是廢了,其實很easy,es支持index通配符 比如你之前是logment 現在是logment2015-05-01和logment2015-05-02 現在只需要將查詢的代碼中index改為 logment* 就ok了 ,而且此法便於刪除過期的index 寫一個定時任務就ok了

我們日誌的架構是這樣的 logstash(client1) 採集日誌到 redis 然後通過 logstash(client2) 從redis轉至 elasticsearch ,logstash寫入elasticsearch的時候默認就是按照每天來建立索引的 在其配置文件無需指明 index和type 即可。

此處會產生一個問題,就是logstash 自動建立索引的時候是根據格林尼治時間來建立的 正正比我們的時間 遲了8小時,我們需要在logstash的lib裡面找到event.rb 然後找到 org.joda.time.DateTimeZone.UTC 格林尼治時間 改成 org.joda.time.DateTimeZone.getDefault() (獲取本地時間類型 我這邊運行就是中國/上海) 即可 話說logstash用的居然是大名鼎鼎的joda 果然是優秀程序 。

5、採用G1垃圾回收機制代替默認CMS

這裡我不分析cms和g1的細節區別,大內存(超過8g)下G1還是很給力的,親測有效,用了G1 一週內一次FULLGC 都沒有,哈哈

elasticsearch.in.sh內將:

# Force the JVM to use IPv4 stack
if [ "x$ES_USE_IPV4" != "x" ]; then
JAVA_OPTS="$JAVA_OPTS -Djava.net.preferIPv4Stack=true"
fi

JAVA_OPTS="$JAVA_OPTS -XX:+UseParNewGC"
JAVA_OPTS="$JAVA_OPTS -XX:+UseConcMarkSweepGC"

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"

大功告成

順便說句JVM調優,調優最主要目標:1.就是降低 GC 次數時間;2.降低FULLGC 幾率

PS:優化代碼比優化JVM實在多了

6、清理掉沒用的緩存

回憶之前的問題發現jvm調優對於老年代的回收並沒有很顯著的效果,隨著時間的推移內存還是不夠~後來才發現是es cache的問題

其實集群建立時我們是可以調整每隔節點的緩存比例、類型、者大小的

# 鎖定內存,不讓JVM寫入swapping,避免降低ES的性能
bootstrap.mlockall: true
# 緩存類型設置為Soft Reference,只有當內存不夠時才會進行回收
index.cache.field.max_size: 50000
index.cache.field.expire: 10m
index.cache.field.type: soft

但是如果你不想重新配置節點並且重啟,你可以做一個定時任務來定時清除cache

http://10.22.2.201:9200/*/_cache/clear //清除所有索引的cache,如果對查詢有實時性要求,慎用! 

到了晚上資源空閒的時候我們還能合併優化一下索引

http://10.22.2.201:9200/*/_optimize

截止現在我們es集群有38億左右數據量,比較穩定~


分享到:


相關文章: