# 01. 選擇合理的硬件配置:盡可能使用 SSD
使用SSD通常比機(jī)械硬盤查詢速度快5~10倍,寫入性能提升不明顯。對(duì)于文檔檢索類查詢性能要求較高的場(chǎng)景,建議考慮 SSD 作為存儲(chǔ),同時(shí)按照 1:10 的比例配置內(nèi)存和硬盤。對(duì)于日志分析類查詢并發(fā)要求較低的場(chǎng)景,可以考慮采用機(jī)械硬盤作為存儲(chǔ),同時(shí)按照 1:50 的比例配置內(nèi)存和硬盤。單節(jié)點(diǎn)存儲(chǔ)數(shù)據(jù)建議在2TB以內(nèi),不要超過5TB,以避免系統(tǒng)不穩(wěn)定。
# 02.?給JVM配置機(jī)器一半的內(nèi)存,但是不建議超過32G
修改conf/jvm.options配置,-Xms 和 -Xmx 設(shè)置為相同的值,推薦設(shè)置為機(jī)器內(nèi)存的一半左右,剩余一半留給操作系統(tǒng)緩存使用。JVM 內(nèi)存建議不要低于 2G,JVM 建議不要超過 32G,否則 JVM 會(huì)禁用內(nèi)存對(duì)象指針壓縮技術(shù),造成內(nèi)存浪費(fèi)。機(jī)器內(nèi)存大于 64G 內(nèi)存時(shí),推薦配置 -Xms30g -Xmx30g。JVM 堆內(nèi)存較大時(shí),內(nèi)存垃圾回收暫停時(shí)間比較長,建議配置 ZGC(低延遲垃圾回收器) 或 G1(垃圾優(yōu)先收集器) 垃圾回收算法。
# 03. 規(guī)模較大的集群配置專有主節(jié)點(diǎn),避免腦裂問題
ES 主節(jié)點(diǎn)負(fù)責(zé)集群元信息管理、index 的增刪操作、節(jié)點(diǎn)的加入剔除,定期將最新的集群狀態(tài)廣播至各個(gè)節(jié)點(diǎn)。在集群規(guī)模較大時(shí),建議配置專有主節(jié)點(diǎn)只負(fù)責(zé)集群管理,不存儲(chǔ)數(shù)據(jù),不承擔(dān)數(shù)據(jù)讀寫壓力。
#?專有主節(jié)點(diǎn)配置(conf/elasticsearch.yml):
node.master:true
node.data:?false
node.ingest:false
#?數(shù)據(jù)節(jié)點(diǎn)配置(conf/elasticsearch.yml):
node.master:false
node.data:true
node.ingest:true
Elasticsearch 默認(rèn)每個(gè)節(jié)點(diǎn)既是候選主節(jié)點(diǎn),又是數(shù)據(jù)節(jié)點(diǎn)。最小主節(jié)點(diǎn)數(shù)量參數(shù)minimum_master_nodes?推薦配置為候選主節(jié)點(diǎn)數(shù)量一半以上,該配置告訴 ES 當(dāng)沒有足夠的 master 候選節(jié)點(diǎn)的時(shí)候,不進(jìn)行 master 節(jié)點(diǎn)選舉,等 master 節(jié)點(diǎn)足夠進(jìn)行選舉。
例如對(duì)于 3 節(jié)點(diǎn)集群,最小主節(jié)點(diǎn)數(shù)量從默認(rèn)值 1 改為 2。
#?最小主節(jié)點(diǎn)數(shù)量配置(conf/elasticsearch.yml):
discovery.zen.minimum_master_nodes:?2
# 04. Linux操作系統(tǒng)調(diào)優(yōu)
關(guān)閉交換分區(qū),防止內(nèi)存置換降低性能。
#?將/etc/fstab?文件中包含swap的行注釋掉
sed?-i?'/swap/s/^/#/'?/etc/fstab
swapoff?-a
#?單用戶可以打開的最大文件數(shù)量,可以設(shè)置為官方推薦的65536或更大些
echo?"*?-?nofile?655360"?>>?/etc/security/limits.conf
#?單用戶線程數(shù)調(diào)大
echo?"*?-?nproc?131072"?>>?/etc/security/limits.conf
#?單進(jìn)程可以使用的最大map內(nèi)存區(qū)域數(shù)量
echo?"vm.max_map_count?=?655360"?>>?/etc/sysctl.conf
#?參數(shù)修改立即生效
sysctl?-p
# 05.?設(shè)置合理的索引分片數(shù)和副本數(shù)
索引分片數(shù)建議設(shè)置為集群節(jié)點(diǎn)的整數(shù)倍,初始數(shù)據(jù)導(dǎo)入時(shí)副本數(shù)設(shè)置為0,生產(chǎn)環(huán)境副本數(shù)建議設(shè)置為 1(設(shè)置 1 個(gè)副本,集群任意 1 個(gè)節(jié)點(diǎn)宕機(jī)數(shù)據(jù)不會(huì)丟失;設(shè)置更多副本會(huì)占用更多存儲(chǔ)空間,操作系統(tǒng)緩存命中率會(huì)下降,檢索性能不一定提升)。單節(jié)點(diǎn)索引分片數(shù)建議不要超過3個(gè),每個(gè)索引分片推薦 10-40GB ,索引分片數(shù)設(shè)置后不可以修改,副本數(shù)設(shè)置后可以修改。
#?索引設(shè)置
curl?-XPUT?http://localhost:9200/fulltext001?pretty?-H?'Content-Type:?application/json'???
-d?'{
????"settings":?{
????????"refresh_interval":?"30s",
????????"merge.policy.max_merged_segment":?"1000mb",
????????"translog.durability":?"async",
????????"translog.flush_threshold_size":?"2gb",
????????"translog.sync_interval":?"100s",
????????"index":?{
????????????"number_of_shards":?“15", //5節(jié)點(diǎn)+3索引分片單機(jī)
????????????"number_of_replicas":?"0"
????????}
????}
}'
#?mapping?設(shè)置
curl?-XPOST?http://localhost:9200/fulltext001/doc/_mapping?pretty??-H?'Content-Type:?application/json'?
-d?'{
????"doc":?{
????????"_all":?{
????????????"enabled":?false
????????},
????????"properties":?{
????????????"content":?{
????????????????"type":?"text",
????????????????"analyzer":?"ik_max_word"
????????????},
????????????"id":?{
????????????????"type":?"keyword"
????????????}
????????}
????}
}'
#?寫入數(shù)據(jù)示例
curl?-XPUT?'http://localhost:9200/fulltext001/doc/1?pretty'?-H?'Content-Type:?application/json'?
-d?'{
????"id":?"https://www.huxiu.com/article/215169.html",
????"content":?"“娃娃機(jī),迷你KTV,VR體驗(yàn)館,堪稱商場(chǎng)三大標(biāo)配‘神器’。”一家地處商業(yè)中心在過去的這幾個(gè)月里,幾乎所有的綜合體都“標(biāo)配”了三種“設(shè)備”…"
}'
#?修改副本數(shù)示例
curl?-XPUT?"http://localhost:9200/fulltext001/_settings"?-H?'Content-Type:?application/json'?
-d?'{
????"number_of_replicas":?1
}'
# 06.?使用批量請(qǐng)求
使用批量請(qǐng)求將產(chǎn)生比單文檔索引請(qǐng)求好得多的性能。寫入數(shù)據(jù)時(shí)調(diào)用批量提交接口,推薦每批量提交5~15MB數(shù)據(jù)。如單條記錄 1KB 大小,每批次提交 10000 條左右記錄寫入性能較優(yōu)。
#?批量請(qǐng)求接口API
curl?-XPOST?"http://localhost:9200/_bulk"?-H?'Content-Type:?application/json'?
-d'
{?"index"?:?{?"_index"?:?"test",?"_type"?:?"_doc",?"_id"?:?"1"?}?}{?"field1"?:?"value1"?}
{?"delete"?:?{?"_index"?:?"test",?"_type"?:?"_doc",?"_id"?:?"2"?}?}
{?"create"?:?{?"_index"?:?"test",?"_type"?:?"_doc",?"_id"?:?"3"?}?}{?"field1"?:?"value3"?}
{?"update"?:?{"_id"?:?"1",?"_type"?:?"_doc",?"_index"?:?"test"}?}{?"doc"?:?{"field2"?:?"value2"}?}'
# 07.?通過多進(jìn)程/線程發(fā)送數(shù)據(jù)
單線程批量寫入數(shù)據(jù)往往不能充分利用服務(wù)器 CPU 資源,可以嘗試調(diào)整寫入線程數(shù)或者在多個(gè)客戶端上同時(shí)向 ES 服務(wù)器提交寫入請(qǐng)求。通過測(cè)試確定最佳的 worker 數(shù)量??梢酝ㄟ^逐漸增加工作任務(wù)數(shù)量來測(cè)試,直到集群上的 I/O 或 CPU 飽和。
# 08.?調(diào)大寫入的refresh interval
ES寫入和打開一個(gè)新段的輕量過程叫做refresh,可以通過設(shè)置 refresh_interval,降低每個(gè)索引的刷新頻率。
#?設(shè)置?refresh?interval?API
curl?-XPUT?"http://localhost:9200/index"?-H?'Content-Type:?application/json'?
-d'{
????"settings":?{
????????"refresh_interval":?"30s"
????}
}'
refresh_interval 可以在已經(jīng)存在的索引上進(jìn)行動(dòng)態(tài)更新,生產(chǎn)環(huán)境中建立一個(gè)大的新索引時(shí),可以先關(guān)閉自動(dòng)刷新,待開始使用該索引時(shí)再把它們調(diào)回來。
curl?-XPUT?"http://localhost:9200/index/_settings"?-H?'Content-Type:?application/json'?
-d'{?"refresh_interval":?-1?}'
curl?-XPUT?"http://localhost:9200/index/_settings"?-H?'Content-Type:?application/json'?
-d'{?"refresh_interval":?"30s"?}'
# 09.?配置寫入的事務(wù)日志參數(shù)
事務(wù)日志 translog 的設(shè)計(jì)目的是幫助 shard 恢復(fù)操作,否則數(shù)據(jù)可能會(huì)從內(nèi)存 flush 到磁盤時(shí)發(fā)生意外而丟失。事務(wù)日志 translog 的落盤(fsync)是 ES 在后臺(tái)自動(dòng)執(zhí)行的,默認(rèn)每5秒鐘提交到磁盤上,或者當(dāng) translog 文件大小大于 512MB 提交,或者在每個(gè)成功的索引、刪除、更新或批量請(qǐng)求時(shí)提交。 索引創(chuàng)建時(shí),可以調(diào)整默認(rèn)日志刷新間隔index.translog.sync_interval: "60s"。創(chuàng)建索引后可以動(dòng)態(tài)調(diào)整translog參數(shù),"index.translog.durability":"async"?相當(dāng)于關(guān)閉了 index、bulk 等操作的同步 flush translog 操作,僅使用默認(rèn)的定時(shí)刷新、文件大小閾值刷新機(jī)制。
#?動(dòng)態(tài)設(shè)置?translog?API
curl?-XPUT?"http://localhost:9200/index"?-H?'Content-Type:?application/json'?
-d'{
????"settings":?{
????????"index.translog.durability":?"async",
????????"translog.flush_threshold_size":?"2gb"
????}
}'
# 10.?設(shè)計(jì)mapping配置合適的字段類型
ES 寫入文檔時(shí),如果請(qǐng)求中指定的索引名不存在,會(huì)自動(dòng)創(chuàng)建新索引,并根據(jù)文檔內(nèi)容猜測(cè)可能的字段類型。但這不是最高效的,可以根據(jù)應(yīng)用場(chǎng)景來設(shè)計(jì)合理的字段類型。根據(jù)業(yè)務(wù)場(chǎng)景設(shè)計(jì)索引配置合理的分片數(shù)、副本數(shù),設(shè)置字段類型、分詞器。如果不需要合并全部字段,禁用_all字段,通過copy_to來合并字段。
curl?-XPOST?"http://localhost:9200/twitter/doc/_mapping?pretty"?-H?'Content-Type:?application/json'?
-d'{
????"doc":?{
????????"_all":?{
????????????"enabled":?false
????????},
????????"properties":?{
????????????"user":?{
????????????????"type":?"keyword"
????????????},
????????????"post_date":?{
????????????????"type":?"date"
????????????},
????????????"message":?{
????????????????"type":?"text",
????????????????"analyzer":?"cjk"
????????????}
????????}
????}
}’
document 模型設(shè)計(jì)
ES里復(fù)雜的關(guān)聯(lián)查詢盡量別用,最好是先在 Java 里就完成關(guān)聯(lián),將關(guān)聯(lián)好的數(shù)據(jù)直接寫入ES中。搜索時(shí)就不需要利用ES的搜索語法來完成 join 之類的關(guān)聯(lián)搜索。所以document 模型設(shè)計(jì)是非常重要的,復(fù)雜操作盡量在 document 模型設(shè)計(jì)和寫入的時(shí)候就完成。另外對(duì)于一些太復(fù)雜的操作,比如 join/nested/parent-child 搜索都要盡量避免,性能都很差的。
# 11. 使用過濾器緩存和分片查詢緩存
默認(rèn)情況下ES 的查詢會(huì)計(jì)算返回的每條數(shù)據(jù)與查詢語句的相關(guān)度,但對(duì)于非全文索引的使用場(chǎng)景只想精確地查找目標(biāo)數(shù)據(jù)時(shí),通過 filter 讓 ES 不計(jì)算評(píng)分,并且盡可能地緩存 filter 的結(jié)果集,供后續(xù)包含相同 filter 的查詢使用,提高查詢效率。
#?普通查詢
curl?-XGET?"http://localhost:9200/twitter/_search"?-H?'Content-Type:?application/json'?
-d'{
????"query":?{
????????"match":?{
????????????"user":?"kimchy"
????????}
????}
}'
#?過濾器(filter)查詢
curl?-XGET?"http://localhost:9200/twitter/_search"?-H?'Content-Type:?application/json'?
-d'{
????"query":?{
????????"bool":?{
????????????"filter":?{
????????????????"match":?{
????????????????????"user":?"kimchy"
????????????????}
????????????}
????????}
????}
}'
分片查詢緩存的目的是緩存聚合、提示詞結(jié)果和命中數(shù)(它不會(huì)緩存返回的文檔,因此,它只在 search_type=count 時(shí)起作用)。分片緩存的大小默認(rèn)情況下是 JVM 堆的 1% 大小,也可手動(dòng)設(shè)置在config/elasticsearch.yml文件里。
indices.requests.cache.size:?1%
查看緩存占用內(nèi)存情況(name 表示節(jié)點(diǎn)名, query_cache 表示過濾器緩存,request_cache 表示分片緩存,fielddata 表示字段數(shù)據(jù)緩存,segments 表示索引段)。
curl?-XGET?"http://localhost:9200/_cat/nodes?h=name,query_cache.memory_size,request_cache.memory_size,fielddata.memory_size,segments.memory&v"?
# 12.?使用路由 routing
ES寫入文檔時(shí),文檔會(huì)通過一個(gè)公式路由到一個(gè)索引中的一個(gè)分片上。默認(rèn)的公式如下:
shard_num?=?hash(_routing)?%?num_primary_shards
_routing 字段的取值,默認(rèn)是 _id 字段,可以根據(jù)業(yè)務(wù)場(chǎng)景設(shè)置經(jīng)常查詢的字段作為路由字段。例如可以考慮將用戶 id、地區(qū)作為路由字段,查詢時(shí)可以過濾不必要的分片,加快查詢速度。
#?寫入時(shí)指定路由
curl?-XPUT?"http://localhost:9200/my_index/my_type/1?routing=user1"?-H?'Content-Type:?application/json'?
-d'{
????"title":?"This?is?a?document",
????"author":?"user1"
}'
#?查詢時(shí)不指定路由,需要查詢所有分片,查詢時(shí)指定路由,只需要查詢1個(gè)分片
curl?-XGET?"http://localhost:9200/my_index/_search?routing=user1"?-H?'Content-Type:?application/json'?
-d'{
????"query":?{
????????"match":?{
????????????"title":?"document"
????????}
????}
}'
#?返回結(jié)果
{
????"took":?1,
????"timed_out":?false,
????"_shards":?{
????????"total":?1,
????????"successful":?1,
????????"skipped":?0,
????????"failed":?0
????}
????...?...
}
# 13. 強(qiáng)制合并只讀索引,關(guān)閉歷史數(shù)據(jù)索引
只讀索引可以從合并成一個(gè)單獨(dú)的大segment中收益,減少索引碎片,減少 JVM 堆常駐內(nèi)存。強(qiáng)制合并索引操作會(huì)耗費(fèi)大量磁盤 IO,盡量配置在業(yè)務(wù)低峰期執(zhí)行。歷史數(shù)據(jù)索引如果業(yè)務(wù)上不再支持查詢請(qǐng)求,可以考慮關(guān)閉索引,減少 JVM 內(nèi)存占用。
#?索引forcemerge?API
curl?-XPOST?"http://localhost:9200/abc20180923/_forcemerge?max_num_segments=1"
#?索引關(guān)閉API
curl?-XPOST?"http://localhost:9200/abc2017*/_close"
# 14. 配置合適的分詞器
ES 內(nèi)置了很多分詞器,也可以安裝自研/開源分詞器。根據(jù)業(yè)務(wù)場(chǎng)景選擇合適的分詞器,避免全部采用默認(rèn) standard 分詞器。
常用分詞器:
cjk:根據(jù)二元索引對(duì)中日韓文分詞,可以保證查全率。
IK:比較熱門的中文分詞,能按照中文語義切分,可以自定義詞典。
pinyin:可以讓用戶輸入拼音,就能查找到相關(guān)的關(guān)鍵詞。
aliws:阿里巴巴自研分詞,支持多種模型和分詞算法,詞庫豐富,分詞結(jié)果準(zhǔn)確,適用于對(duì)查準(zhǔn)要求高的場(chǎng)景。
#?分詞效果測(cè)試API
curl?-XPOST?"http://localhost:9200/_analyze"?-H?'Content-Type:?application/json'?
-d'{
????"analyzer":?"ik_max_word",
????"text":?"南京市長江大橋"
}'
# 15. 配置查詢聚合節(jié)點(diǎn)
查詢聚合節(jié)點(diǎn)可以發(fā)送粒子查詢請(qǐng)求到其他節(jié)點(diǎn),收集和合并結(jié)果,以及響應(yīng)發(fā)出查詢的客戶端。通過給查詢聚合節(jié)點(diǎn)配置更高規(guī)格的 CPU 和內(nèi)存,可以加快查詢運(yùn)算速度、提升緩存命中率。
#?查詢聚合節(jié)點(diǎn)配置(conf/elasticsearch.yml):
node.master:false
node.data:false
node.ingest:false
# 16. 設(shè)置查詢讀取記錄條數(shù)和字段
默認(rèn)的查詢請(qǐng)求通常返回排序后的前 10 條記錄,最多一次讀取 10000 條記錄,通過 from 和 size 參數(shù)控制讀取記錄范圍,避免一次讀取過多的記錄。通過 _source 參數(shù)可以控制返回字段信息,盡量避免讀取大字段。
#?查詢請(qǐng)求示例
curl?-XGET?http://localhost:9200/fulltext001/_search?pretty??-H?'Content-Type:?application/json'?
-d?'{
????"from":?0,
????"size":?10,
????"_source":?"id",
????"query":?{
????????"bool":?{
????????????"must":?[
????????????????{
????????????????????"match":?{
????????????????????????"content":?"虎嗅"
????????????????????}
????????????????}
????????????]
????????}
????},
????"sort":?[
????????{
????????????"id":?{
????????????????"order":?"asc"
????????????}
????????}
????]
}'
# 17. 設(shè)置 teminate_after 查詢快速返回
配teminate_after指定每個(gè) shard 最多匹配 N 條記錄后返回,設(shè)置查詢超時(shí)時(shí)間 timeout。在查詢結(jié)果中可以通過 “terminated_early” 字段標(biāo)識(shí)是否提前結(jié)束查詢請(qǐng)求。
#?teminate_after?查詢語法示例
curl?-XGET?"http://localhost:9200/twitter/_search"?-H?'Content-Type:?application/json'?
-d'{
????"from":?0,
????"size":?10,
????"timeout":?"10s",
????"terminate_after":?1000,
????"query":?{
????????"bool":?{
????????????"filter":?{
????????????????"term":?{
????????????????????"user":?"elastic"
????????????????}
????????????}
????????}
????}
}'
# 18. 避免查詢深度翻頁
ES 默認(rèn)只允許查看排序前 10000 條的結(jié)果,當(dāng)翻頁查看排序靠后的記錄時(shí),響應(yīng)耗時(shí)一般較長。ES的分頁陷阱-假如每頁是10條數(shù)據(jù),現(xiàn)在要查詢第 100 頁,實(shí)際上是會(huì)把每個(gè) shard 上存儲(chǔ)的前 1000 條數(shù)據(jù)都查到一個(gè)協(xié)調(diào)節(jié)點(diǎn)上,如果你有個(gè)5個(gè)shard,那么就有5000條數(shù)據(jù),接著協(xié)調(diào)節(jié)點(diǎn)對(duì)這5000 條數(shù)據(jù)進(jìn)行一些合并處理,再獲取到最終第 100 頁的 10 條數(shù)據(jù)。 分布式集群中,必須得從每個(gè) shard 都查 1000 條數(shù)據(jù)過來,然后根據(jù)需求進(jìn)行排序、篩選等操作,最后再次分頁,拿到里面第 100 頁的數(shù)據(jù)。所以翻頁越深,每個(gè) shard 返回的數(shù)據(jù)就越多,而且協(xié)調(diào)節(jié)點(diǎn)處理的時(shí)間越長,非常坑爹。所以用不允許深度分頁。
如果是APP下拉可以用 scroll api,scroll 會(huì)一次性生成所有數(shù)據(jù)的一個(gè)快照,然后每次滑動(dòng)向后翻頁就是通過游標(biāo) scroll_id移動(dòng),獲取下一頁,性能會(huì)比分頁要高很多,基本上都是毫秒級(jí)的。但是這個(gè)適合于下拉翻頁的不能隨意亂跳頁的場(chǎng)景。所以現(xiàn)在很多產(chǎn)品都不允許隨意翻頁的。初始化時(shí)必須指定scroll參數(shù),告訴ES要保存此次搜索的上下文多長時(shí)間。你需要確保用戶不會(huì)持續(xù)不斷翻頁翻幾個(gè)小時(shí),否則可能因?yàn)槌瑫r(shí)而失敗。
除了用 scroll api,也可用 search_after 來做,search_after 的思想是使用前一頁的結(jié)果來幫助檢索下一頁的數(shù)據(jù),顯然,這種方式也不允許你隨意翻頁,你只能一頁頁往后翻。初始化時(shí),需要使用一個(gè)唯一值的字段作為 sort 字段。使用search_after方式查詢會(huì)更輕量級(jí),如果每次只需要返回 10 條結(jié)果,則每個(gè) shard 只需要返回 search_after 之后的 10 個(gè)結(jié)果即可,返回的總數(shù)據(jù)量只是和 shard 個(gè)數(shù)以及本次需要的個(gè)數(shù)有關(guān),和歷史已讀取的個(gè)數(shù)無關(guān)。
# search_after查詢語法示例
curl?-XGET?"http://localhost:9200/twitter/_search"?-H?'Content-Type:?application/json'?
-d'{
????"size":?10,
????"query":?{
????????"match":?{
????????????"message":?"Elasticsearch"
????????}
????},
????"sort":?[
????????{
????????????"_score":?{
????????????????"order":?"desc"
????????????}
????????},
????????{
????????????"_id":?{
????????????????"order":?"asc"
????????????}
????????}
????],
????"search_after":?[
????????0.84290016,?????//上一次response中某個(gè)doc的score
????????"1024"??????????//上一次response中某個(gè)doc的id
????]
}’
# 19. 避免前綴模糊匹配
Elasticsearch 默認(rèn)支持通過 *? 正則表達(dá)式來做模糊匹配,如果在一個(gè)數(shù)據(jù)量較大規(guī)模的索引上執(zhí)行模糊匹配,尤其是前綴模糊匹配,通常耗時(shí)會(huì)比較長,甚至可能導(dǎo)致內(nèi)存溢出。盡量避免在高并發(fā)查詢請(qǐng)求的生產(chǎn)環(huán)境執(zhí)行這類操作。?
如查詢請(qǐng)求"角色:*A8848*"查詢時(shí),往往導(dǎo)致整個(gè)集群負(fù)載較高。通過對(duì)數(shù)據(jù)預(yù)處理,增加冗余字段 "角色.keyword",并事先將所有角色按照1、2、3...7分詞后存儲(chǔ)至該字段,字段存儲(chǔ)內(nèi)容示例:京,A,8,4,京A,A8,88,84,48,京A8...京A88488。通過查詢"角色.keyword:A8848"即可解決原來的性能問題。
# 20. 避免索引稀疏
Elasticsearch7.X 版本只允許 type 值為“_doc”,在一個(gè)索引下面創(chuàng)建多個(gè)字段不一樣的 type,或者將幾百個(gè)字段不一樣的索引合并到一個(gè)索引中,會(huì)導(dǎo)致索引稀疏問題。 建議每個(gè)索引下只創(chuàng)建一個(gè) type,字段不一樣的數(shù)據(jù)分別獨(dú)立創(chuàng)建index,不要合并成一個(gè)大索引。每個(gè)查詢請(qǐng)求根據(jù)需要去讀取相應(yīng)的索引,避免查詢大索引掃描全部記錄,加快查詢速度。
# 21. 擴(kuò)容集群節(jié)點(diǎn)個(gè)數(shù),升級(jí)節(jié)點(diǎn)規(guī)格
# 22. 數(shù)據(jù)預(yù)熱
?后臺(tái)監(jiān)控系統(tǒng)每隔一段時(shí)間去系統(tǒng)搜索一下熱數(shù)據(jù),刷到 filesystem cache 里去。對(duì)于訪問高頻數(shù)據(jù),最好做一個(gè)專門的緩存預(yù)熱子系統(tǒng),就是對(duì)熱數(shù)據(jù)每隔一段時(shí)間,就提前訪問一下,讓數(shù)據(jù)進(jìn)入 filesystem cache 里面去,這樣二次訪問性能提升很多。
# 23. 數(shù)據(jù)冷熱分離
? ES可以做類似于mysql的水平拆分,即將低頻冷數(shù)據(jù)和高頻熱數(shù)據(jù)分別寫不同的索引,這樣可確保熱數(shù)據(jù)在被預(yù)熱之后,盡量都留在 filesystem os cache 里,不受冷數(shù)據(jù)沖掉。比如有6臺(tái)機(jī)器,兩個(gè)索引,一個(gè)放冷數(shù)據(jù),一個(gè)放熱數(shù)據(jù),每個(gè)索引 3 個(gè)shard。3臺(tái)機(jī)器放熱數(shù)據(jù) index,另外3臺(tái)機(jī)器放冷數(shù)據(jù) index。這樣大量的時(shí)間是在訪問熱數(shù)據(jù) index,熱數(shù)據(jù)量的占比小就能保證其保留在 filesystem cache 里,確保熱數(shù)據(jù)的訪問高性能。由于冷熱索引的隔離,即使訪問冷數(shù)據(jù)都在磁盤上,此時(shí)性能差點(diǎn),但訪問低頻就能接受。
# 24. 合理選取搜索字段
比如現(xiàn)在有一行數(shù)據(jù),id,name,age .... 30 個(gè)字段。但是現(xiàn)在搜索只需要根據(jù) id,name,age 三個(gè)字段來搜索。僅僅寫入 es 中要用來檢索的少數(shù)幾個(gè)字段就可以了,比如說就寫入ES id,name,age 三個(gè)字段,然后你可以把其他的字段數(shù)據(jù)存在mysql/hbase 里,用 ES+ hbase 架構(gòu)伸縮性更好。因?yàn)镠base的特點(diǎn)是適用于海量數(shù)據(jù)的在線存儲(chǔ),就是對(duì) Hbase 可以寫入海量數(shù)據(jù),但是不要做復(fù)雜的搜索,而是做很簡單的一些根據(jù) id 或者范圍進(jìn)行查詢的操作。從 es 中根據(jù) name 和 age 去搜索,拿到的結(jié)果可能就 20 個(gè) doc id,然后根據(jù) doc id 到 Hbase 里去查詢每個(gè) doc id 對(duì)應(yīng)的完整的數(shù)據(jù),查出來返回給前端。寫入ES的數(shù)據(jù)最好小于等于或者是略微大于ES的 filesystem cache 的內(nèi)存容量。先從ES檢索,然后再根據(jù) ES返回的 id 去 hbase 里查詢。
注25:性能優(yōu)化的關(guān)鍵點(diǎn)——filesystem cache
往ES寫的數(shù)據(jù),實(shí)際上都寫到磁盤文件里去了,查詢時(shí)操作系統(tǒng)會(huì)將磁盤文件里的數(shù)據(jù)自動(dòng)緩存到 filesystem cache 里。ES搜索引擎嚴(yán)重依賴于底層的filesystem cache,如果給 filesystem cache 更多的內(nèi)存,盡量讓內(nèi)存可以容納所有的 idx segment file 索引數(shù)據(jù)文件,那么搜索時(shí)基本都是走內(nèi)存的,性能會(huì)非常高。性能差距根據(jù)之前很多的測(cè)試和壓測(cè),如果走磁盤一般肯定上秒,搜索性能絕對(duì)是秒級(jí)別的,如果是走 filesystem cache,是走純內(nèi)存的,那么一般來說性能比走磁盤要高一個(gè)數(shù)量級(jí),基本上就是毫秒級(jí)的,從幾毫秒到幾百毫秒不等。
如原先公司ES節(jié)點(diǎn)有 3 臺(tái)機(jī)器,每臺(tái)機(jī)器內(nèi)存64G,總內(nèi)存就是 64 * 3 = 192G。每臺(tái)機(jī)器給ES jvm heap 是 32G,那么留給 filesystem cache的就是每臺(tái)機(jī)器32G,總共集群里filesystem cache 的內(nèi)存就是 32 * 3 = 96G。而此時(shí)整個(gè)磁盤上索引數(shù)據(jù)文件,在 3 臺(tái)機(jī)器上共占用了1T 磁盤容量,ES數(shù)據(jù)量是 1T,那么每臺(tái)機(jī)器的數(shù)據(jù)量是 300G。filesystem cache 的內(nèi)存才 100G,十分之一的數(shù)據(jù)可以放內(nèi)存,其他的都在磁盤,然后你執(zhí)行搜索操作,大部分操作都是走磁盤,性能肯定差。要讓ES性能要好,最佳的情況下,就是你的機(jī)器的內(nèi)存,至少可以容納你的總數(shù)據(jù)量的50%。
最佳的情況是僅僅在ES中就存少量的數(shù)據(jù),就是你要用來搜索的那些索引,如果內(nèi)存留給 filesystem cache 的是 100G,那么你就將索引數(shù)據(jù)控制在 100G 以內(nèi),這樣的話,你的數(shù)據(jù)幾乎全部走內(nèi)存來搜索,性能很高1 秒以內(nèi)。