億級規模的Elasticsearch優化實戰

本次分享主要包含兩個方面的實戰經驗:索引性能和查詢性能。php

 

一. 索引性能(Index Performance)html

 

 

首先要考慮的是,索引性能是否有必要作優化?前端

 

索引速度提升與否?主要是看瓶頸在什麼地方,如果 Read DB(產生DOC)的速度比較慢,那瓶頸不在 ElasticSearch 時,優化就沒那麼大的動力。實際上 Elasticsearch 的索引速度仍是很是快的。java

 

咱們有一次遇到 Elasticsearch 升級後索引速度很慢,查下來是新版 IK 分詞的問題,修改分詞插件後獲得解決。node

 

若是須要優化,應該如何優化?mysql

 

SSD 是經濟壓力能承受狀況下的不二選擇。減小碎片也能夠提升索引速度,天天進行優化仍是頗有必要的。在初次索引的時候,把 replica 設置爲 0,也能提升索引速度。web

 

bulk 是否是必定須要呢?redis

 

如果 Elasticsearch 普通索引已經致使高企的 LA,IO 壓力已經見頂,這時候 bulk 也沒法提供幫助,SSD 應該是很好的選擇。sql

 

在 create doc 速度能跟上的時候,bulk 是能夠提升速度的。docker

 

記得 threadpool.index.queue_size ++,否則會出現索引時隊列不夠用的狀況。

 

indices.memory.index_buffer_size:10% 這個參數能夠進行適當調整。

 

調整以下參數也能夠提升索引速度:index.translog.flush_threshold_ops:50000 和 refresh_interval。

 

二. 查詢性能(Query Perofrmance)

 

 

王道是什麼?routing,routing,仍是 routing。

 

咱們爲了提升查詢速度,減小慢查詢,結合本身的業務實踐,使用多個集羣,每一個集羣使用不一樣的 routing。好比,用戶是一個routing維度。

 

在實踐中,這個routing 很是重要。

 

咱們碰到一種狀況,想把此維度的查詢(即用戶查詢)引到非用戶routing 的集羣,結果集羣徹底頂不住!

 

在大型的本地分類網站中,城市、類目也是一個不錯的維度。咱們使用這種維度進行各類搭配。而後在前端分析查詢,把各個不一樣查詢分別引入合適的集羣。這樣作之後,每一個集羣只須要不多的機器,並且保持很小的 CPU Usage 和 LA。從而查詢速度夠快,慢查詢幾乎消滅。

 

分合?

 

分別(索引和routing)查詢和合並(索引和routing)查詢,即此分合的意思。

 

索引愈來愈大,單個 shard 也很巨大,查詢速度也愈來愈慢。這時候,是選擇分索引仍是更多的shards?

 

在實踐過程當中,更多的 shards 會帶來額外的索引壓力,即 IO 壓力。

 

咱們選擇了分索引。好比按照每一個大分類一個索引,或者主要的大城市一個索引。而後將他們進行合併查詢。如:http://cluster1:9200/shanghai,beijing/_search?routing=fang,自動將查詢中城市屬性且值爲上海或北京的查詢,且是房類目的,引入集羣 cluster1,而且routing等於fang。

 

http://cluster1:9200/other/_search?routing=jinan,linyi。小城市的索引,咱們使用城市作 routing,如本例中同時查詢濟南和臨沂城市。

 

http://cluster1:9200/_all/_search,所有城市查詢。

 

再如: http://cluster2:9200/fang,che/_search?routing=shanghai_qiche,shanghai_zufang,beijing_qiche,beijing_zufang。查詢上海和北京在小分類汽車、整租的信息,那咱們進行如上合併查詢。並將其引入集羣 cluster2。

 

使用更多的 shards?

 

除了有 IO 壓力,並且不能進行所有城市或所有類目查詢,由於徹底頂不住。

 

Elastic 官方文檔建議:一個 Node 最好不要多於三個 shards。

 

如果 "more shards」,除了增長更多的機器,是沒辦法作到這一點的。

分索引,雖然一個 Node 總的shards 仍是挺多的,可是一個索引能夠保持3個之內的shards。

 

咱們使用分索引時,全量查詢是能夠頂住的,雖然壓力有點兒高。

 

索引愈來愈大,資源使用也愈來愈多。如果要進行更細的集羣分配,大索引使用的資源成倍增長。

 

有什麼辦法能減少索引?顯然,建立 doc 時,把不須要的 field 去掉是一個辦法;可是,這須要對業務很是熟悉。

 

有啥立竿見影的辦法?

 

根據咱們信息的特色,內容(field:description)佔了索引的一大半,那咱們就不把 description 索引進 ES,doc 小了一倍,集羣也小了一倍,所用的資源(Memory, HD or SSD, Host, snapshot存儲,還有時間)大大節省,查詢速度天然也更快。

 

那要查 description 怎麼辦?

 

上面的實例中,咱們能夠把查詢引入不一樣集羣,天然咱們也能夠把 description 查詢引入一個非實時(也能夠實時)集羣,這主要是咱們業務特色決定的,由於description查詢所佔比例很是小,使得咱們能夠這樣作。

 

被哪些查詢搞過?第一位是 Range 查詢,這貨的性能真不敢恭維。在最熱的查詢中,如果有這貨,確定是很是痛苦的,網頁變慢,查詢速度變慢,集羣 LA 高企,嚴重的時候會致使集羣 shard 自動下線。因此,建議在最熱的查詢中避免使用 Range 查詢。

 

Facet 查詢,在後續版本這個被 aggregations 替代,咱們大多數時候讓它在後端進行運算。

 

三. 其餘

 

 

1)線程池

 

線程池咱們默認使用 fixed,使用 cached 有可能控制很差。主要是比較大的分片 relocation時,會致使分片自動下線,集羣可能處於危險狀態。在集羣高壓時,如果 cached ,分片也可能自動下線。自 1.4 版本後,咱們就一直 fixed,至於新版是否還存在這個問題,就沒再試驗了。

 

兩個緣由:一是 routing王道帶來的改善,使得集羣一直低壓運行;二是使用fixed 後,已經極少遇到自動下線shard了。

 

咱們前面說過,user 是一個很是好的維度。這個維度很重要,routing 效果很是明顯。其餘維度,須要根據業務特色,進行組合。

 

因此咱們的集羣一直是低壓運行,就不多再去關注新版本的 使用 cached 配置問題。

 

hreadpool.search.queue_size 這個配置是很重要的,通常默認是夠用了,能夠嘗試提升。

 

2)優化

 

天天優化是有好處的,能夠大大改善查詢性能。max_num_segments 建議配置爲1。雖然優化時間會變長,可是在高峯期前能完成的話,會對查詢性能有很大好處。

 

3) JVM GC的選擇:選擇 G1仍是 CMS?

 

應該大多數人仍是選擇了 CMS,咱們使用的經驗是 G1 和 CMS 比較接近;但和 CMS 相比,仍是有一點距離,至少在咱們使用經驗中是如此。

 

JVM 32G 現象?

 

128G內存的機器配置一個 JVM,而後是巨大的 heapsize (如64G)?

仍是配多個 JVM instance,較小的 heapsize(如32G)?

 

個人建議是後者。實際使用中,後者也能幫助咱們節省很多資源,並提供不錯的性能。具體請參閱 「Don’t Cross 32 GB!" (https://www.elastic.co/guide/en/elasticsearch/guide/current/heap-sizing.html#compressed_oops)

 

跨 32G 時,有一個現象,使用更多的內存,好比 40G,效果還不如31G!

 

這篇文檔值得你們仔細閱讀。

 

JVM 還有一個配置 bootstrap.mlockall: true,比較重要。這是讓 JVM 啓動的時候就 鎖定 heap 內存。

 

有沒有用過 較小的 heapsize,加上SSD?我據說有人使用過,效果還不錯,固然,咱們本身還沒試過。

 

4)插件工具

 

推薦 kopf,是一個挺不錯的工具,更新及時,功能完備,可讓你忘掉不少 API :)。

 

索引,查詢,和一些重要的配置,是今天分享的重點。

 

Q&A

 

Q1:您建議生產環境JVM採用什麼樣的參數設置?FULL GC頻率和時間如何?

 

CMS 標準配置。

ES_HEAP_NEWSIZE=?G

JAVA_OPTS="$JAVA_OPTS -XX:+UseCondCardMark"

JAVA_OPTS="$JAVA_OPTS -XX:CMSWaitDuration=250"

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"

 

Full GC 不多去care 它了。咱們使用 Elasticsearch 在JVM上花的時間不多。

 

Q2:生產環境服務器如何配置性價比較高?單機CPU核數、主頻?內存容量?磁盤容量?

 

內存大一些,CPU 多核是必要的,JVM 和 Elasticsearch 會充分使用內存和多核的。 關於內存容量的問題,不少是 JVM Tunning 的問題。 磁盤容量沒啥要求。

 

Q3: 分組統計(Facet 查詢或 aggregations )大多數時候讓它在後端進行運算,怎麼實現?應用若是須要實時進行統計並且併發量較大,如何優化?

 

由於咱們是網站系統,因此對於 Facet 請求,引導到後端慢慢計算,前端初始的時候可能沒數據,可是此後就會有了。

 

若是是精確要求的話,那就只能從 提升 facet 查詢性能去下手,好比 routing、filter、cache、更多的內存...

 

Q4:存進Elasticsearch的數據,timestamp是UTC時間,Elasticsearch集羣會在UTC 0點,也就是北京時間早上8點自動執行優化?如何改參數設置這個時間?

 

咱們沒有使用Elasticsearch的自動優化設置。本身控制優化時間。

 

Q5:個人Java程序,log4j2 Flume appender,而後機器上的Flume agent ,直接Elasticsearch 的sink avro到 es節點上,多少個agent 連在單個Elasticsearch節點比較合適 ?

 

ElasticSearch自己是一個分佈式計算集羣,因此,請求平均分配到每一個 node 便可。

 

Q6:我代碼裏直接用 Java API 生成Flume appender 格式,Flume agent 裏interceptor去拆分幾個字段,這樣是否是太累了?比較推薦的作法是否是仍是各業務點本身控制字段,調用Elasticsearch API 生成索引內容?

 

業務點本身控制生成的文檔吧?若是須要產生不一樣routing,而且分了索引,這些實際上是業務相關的。routing和不一樣索引,都是根據業務狀況哪些查詢比較集中而進行處理的。

 

Q7:您見過或管理過的生產環境的Elasticsearch數據量多大?

 

咱們使用 Elasticsearch 進行某些業務處理,數據量過億。

 

Q8:SSD性能提高多少?

 

SSD 對索引幫助很是大,效果噹噹的,提升幾十倍應該是沒問題。不過,咱們沒有試過徹底使用SSD頂查詢,而是使用內存,內存性價比仍是不錯的。

 

Q9:咱們如今有256個shard,用uid作routing,全部查詢都是走routing。每一個shard有30多G,每次擴容很慢,有什麼建議?

 

能夠考慮使用分合查詢嗎? 或者使用更多的維度? 256個 shard 確實比較難以控制。可是若是是分索引和查詢,比more shards(256) 效果應該會好很多。

 

Q10:Elasticsearch排序等聚合類的操做須要用到fielddata,查詢時很慢。新版本中doc values聚合查詢操做性能提高很大,大家有沒有用過?

 

Facet 查詢須要更大的內存,更多的 CPU 資源。能夠考慮routing、filter、cache等多種方式提升性能。

 

Aggs 未來是要替換 Facet,建議儘快替換原來的facet API。

 

Q11:Elasticsearch配置bootstrap.mlockall,咱們在使用中發現會致使啓動很慢,由於Elasticsearch要獲取到足夠的內存纔開始啓動。

 

啓動慢是能夠接受的,啓動慢的緣由也許是內存沒有有效釋放過,好比文件 cached了。 內存充足的狀況下,啓動速度仍是蠻快的,能夠接受。 JVM 和 Lucene 都須要內存,通常是JVM 50%, 剩下的50% 文件cached 爲Lucene 使用。

 

Q12:優化是一個開銷比較大的操做,天天優化的時候是否會致使查詢不可用?如何優化這塊?

 

優化是開銷很大的。不會致使查詢不可用。優化是值得的,大量的碎片會致使查詢性能大大下降。 若是很是 care 查詢,能夠考慮多個集羣。在優化時,查詢 skip 這個集羣就能夠。

 

Q13:Elasticsearch適合作到10億級數據查詢,天天千萬級的數據實時寫入或更新嗎?

 

10億是能夠作到的,若是文檔輕量,10億所佔的資源還不是不少。

ELK 使用 Elasticsearch ,進行日誌處理天天千萬是小case吧?

不過咱們除了使用 ELK 進行日誌處理,還進行業務處理,10億級快速查詢是能夠作到,不過,須要作一些工做,好比索引和shards的分分合合:)

 

Q14:Elasticsearch相比Solr有什麼優點嗎?

 

咱們當年使用 Solr 的時候,Elasticsearch 剛出來。他們都是基於 Lucene的。 Elasticsearch 相對於 solr ,省事是一個優勢。並且如今 Elasticsearch 相關的應用軟件也愈來愈多。Solr 和 Lucene 集成度很高,更新版本是和Lucene一塊兒的,這是個優勢。

 

不少年沒用 Solr了,畢竟那時候數據量還不大,因此折騰的就少了,主要仍是折騰 JVM。因此,就再也不過多的比較了。

 

Q15:分詞用的什麼組件?Elasticsearch自帶的嗎?

 

咱們使用 IK 分詞,不過其餘分詞也不錯。IK分詞更新仍是很及時的。並且它能夠遠程更新詞典。:)

 

Q16: reindex有沒有好的方法?

 

reindex 這個和 Lucene 有關,它的 update 就是 delete+ add。

 

Q17:以上面的兩個例子爲例 : 是存儲多份一樣的數據麼?

 

是兩個集羣。第一個集羣使用大城市分索引,不過,還有大部分小城市合併一個索引。大城市仍是用類目進行routing,小城市合併的索引就使用城市進行routing 。

 

第二個集羣,大類分得索引,好比fang、che,房屋和車輛和其餘類目在一個集羣上,他們使用 city+二級類目作routing。

 

Q18:集羣部署有沒有使用 Docker ? 咱們使用的時候 ,同一個服務器 節點之間的互相發現沒有問題 ,可是跨機器的時候須要強制指定network.publish_host 和discovery.zen.ping.unicast.hosts 才能解決集羣互相發現問題。

 

咱們使用puppet進行部署。暫沒使用 Docker。 強制指定network.publish_host 和discovery.zen.ping.unicast.hosts 才能解決集羣,跨IP段的時候是有這個須要。

 

Q19:您建議採用什麼樣的數據總線架構來保證業務數據按routing寫入多個Elasticsearch集羣,怎麼保證多集羣Elasticsearch中的數據與數據庫中數據的一致性?

 

咱們之前使用 PHP在web代碼中進行索引和分析 query,而後引導到不一樣集羣。 如今咱們開發了一套Go rest系統——4sea,使用 Redis + elastic 以綜合提升性能。

 

索引時,更新db的同時,提交一個文檔 ID 通知4sea 進行更新,而後根據配置更新到不一樣集羣。

 

數據提交到查詢時,就是分析 query 並引導到不一樣集羣。

 

這套 4sea 系統,有機會的能夠考慮開源,不算很複雜的。

 

Q20: 能介紹一下Elasticsearch的集羣rebanlance、段合併相關的原理和經驗嗎?

 

 

「段」合併?,咱們是根據業務特色,產生幾個不同的集羣,主要仍是 routing 不同。

 

shards 比較平均很重要的,因此選擇routing 維度是難點,選擇城市的話,大城市所在分片會很是大,此時能夠考慮 分索引,幾個大城市幾個索引,而後小城市合併一個索引。

 

若是 shards 大小分佈平均的話,就不關心如何 allocation 了。

 

Q21:關於集羣rebalance,其實就是cluster.routing.allocation配置下的那些rebalance相關的設置,好比allow_rebalance/cluster_concurrent_rebalance/node_initial_primaries_recoveries,推薦怎麼配置?

 

 

分片多的狀況下,這個纔是須要的吧。

 

分片比較少時,allow_rebalance disable,而後手動也能夠接受的。

 

分片多,通常狀況會自動平衡。咱們對主從不太關心。只是若是一臺機器多個 JVM instance (多個 Elasticsearch node)的話,咱們寫了個腳原本避免同一shard 在一臺機器上。

 

cluster_concurrent_rebalance 在恢復的時候根據狀況修改。正常狀況下,再改爲默認就行了。

 

node_initial_primaries_recoveries,在保證集羣低壓的狀況下,不怎麼care。

 

kopf 上面有好多這種配置,你能夠多試試。

 

Q22:合併查詢是異步請求仍是同步請求?作緩存嗎?

 

合併查詢是 Elasticsearch 自帶 API。

 

Q23:用httpurlconnection請求的時候,會發現返回請求很耗時,通常怎麼處理?

 

儘量減小慢查詢吧?咱們不少工做就是想辦法如何減小慢查詢,routing和分分合合,就是這個目的。

 

 

Q24:生產環境單個節點存儲多少G數據?

 

有大的,有小的。小的也幾十G了。不過根據咱們本身的業務特色,某些集羣就去掉了全文索引。惟一的全文索引,使用基本的routing(比較平衡的routing,好比user。城市的話,就作不到平衡了,由於大城市數據不少),而後作了 快照,反正是增量快照,1小時甚至更短期均可以考慮!!!去掉全文索引的其餘業務集羣,就小多了。

相關文章
相關標籤/搜索