elasticsearch集群優(yōu)化原則

1.選擇堆大泄坦摺(Choosing a Heap Size)

在設(shè)置 Elasticsearch 堆大小時需要通過 $ES_HEAP_SIZE(在bin/elasticsearch 頭部設(shè)置export ES_HEAP_SIZE=31g)環(huán)境變量應(yīng)用兩個規(guī)則:

不要超過可用 RAM 的 50%
Lucene 能很好利用文件系統(tǒng)的緩存往史,它是通過系統(tǒng)內(nèi)核管理的。如果沒有足夠的文件系統(tǒng)緩存空間择诈,性能會受到影響。 此外,專用于堆的內(nèi)存越多意味著其他所有使用 doc values 的字段內(nèi)存越少庐完。
不要超過 32 GB
如果堆大小小于 32 GB,JVM 可以利用指針壓縮徘熔,這可以大大降低內(nèi)存的使用:每個指針 4 字節(jié)而不是 8 字節(jié)门躯。

堆內(nèi)存:大小和交換編輯

Elasticsearch 默認(rèn)安裝后設(shè)置的堆內(nèi)存是 1 GB。 對于任何一個業(yè)務(wù)部署來說酷师, 這個設(shè)置都太小了讶凉。如果你正在使用這些默認(rèn)堆內(nèi)存配置,您的集群可能會出現(xiàn)問題窒升。

這里有兩種方式修改 Elasticsearch 的堆內(nèi)存缀遍。最簡單的一個方法就是指定 ES_HEAP_SIZE 環(huán)境變量。服務(wù)進(jìn)程在啟動時候會讀取這個變量饱须,并相應(yīng)的設(shè)置堆的大小域醇。 比如,你可以用下面的命令設(shè)置它:

export ES_HEAP_SIZE=10g

此外蓉媳,你也可以通過命令行參數(shù)的形式譬挚,在程序啟動的時候把內(nèi)存大小傳遞給它,如果你覺得這樣更簡單的話:

./bin/elasticsearch -Xmx10g -Xms10g

確保堆內(nèi)存最小值( Xms )與最大值( Xmx )的大小是相同的酪呻,防止程序在運行時改變堆內(nèi)存大小减宣, 這是一個很耗系統(tǒng)資源的過程。

通常來說玩荠,設(shè)置 ES_HEAP_SIZE 環(huán)境變量漆腌,比直接寫 -Xmx -Xms 更好一點贼邓。

把你的內(nèi)存的(少于)一半給 Lucene編輯

一個常見的問題是給 Elasticsearch 分配的內(nèi)存 太 大了。 假設(shè)你有一個 64 GB 內(nèi)存的機器闷尿, 天啊塑径,我要把 64 GB 內(nèi)存全都給 Elasticsearch。因為越多越好疤罹摺统舀!

當(dāng)然,內(nèi)存對于 Elasticsearch 來說絕對是重要的劳景,它可以被許多內(nèi)存數(shù)據(jù)結(jié)構(gòu)使用來提供更快的操作誉简。但是說到這里, 還有另外一個內(nèi)存消耗大戶 非堆內(nèi)存 (off-heap):Lucene盟广。

Lucene 被設(shè)計為可以利用操作系統(tǒng)底層機制來緩存內(nèi)存數(shù)據(jù)結(jié)構(gòu)闷串。 Lucene 的段是分別存儲到單個文件中的。因為段是不可變的衡蚂,這些文件也都不會變化窿克,這是對緩存友好的,同時操作系統(tǒng)也會把這些段文件緩存起來毛甲,以便更快的訪問年叮。

Lucene 的性能取決于和操作系統(tǒng)的相互作用。如果你把所有的內(nèi)存都分配給 Elasticsearch 的堆內(nèi)存玻募,那將不會有剩余的內(nèi)存交給 Lucene只损。 這將嚴(yán)重地影響全文檢索的性能。

標(biāo)準(zhǔn)的建議是把 50% 的可用內(nèi)存作為 Elasticsearch 的堆內(nèi)存七咧,保留剩下的 50%跃惫。當(dāng)然它也不會被浪費,Lucene 會很樂意利用起余下的內(nèi)存艾栋。

如果你不需要對分詞字符串做聚合計算(例如爆存,不需要 fielddata )可以考慮降低堆內(nèi)存。堆內(nèi)存越小蝗砾,Elasticsearch(更快的 GC)和 Lucene(更多的內(nèi)存用于緩存)的性能越好先较。

不要超過 32 GB!

這里有另外一個原因不分配大內(nèi)存給 Elasticsearch悼粮。事實上 闲勺, JVM 在內(nèi)存小于 32 GB 的時候會采用一個內(nèi)存對象指針壓縮技術(shù)。

在 Java 中扣猫,所有的對象都分配在堆上菜循,并通過一個指針進(jìn)行引用。 普通對象指針(OOP)指向這些對象申尤,通常為 CPU 字長 的大邪┠弧:32 位或 64 位衙耕,取決于你的處理器。指針引用的就是這個 OOP 值的字節(jié)位置勺远。

對于 32 位的系統(tǒng)臭杰,意味著堆內(nèi)存大小最大為 4 GB。對于 64 位的系統(tǒng)谚中, 可以使用更大的內(nèi)存,但是 64 位的指針意味著更大的浪費寥枝,因為你的指針本身大了宪塔。更糟糕的是, 更大的指針在主內(nèi)存和各級緩存(例如 LLC囊拜,L1 等)之間移動數(shù)據(jù)的時候某筐,會占用更多的帶寬。

Java 使用一個叫作 內(nèi)存指針壓縮(compressed oops)的技術(shù)來解決這個問題冠跷。 它的指針不再表示對象在內(nèi)存中的精確位置南誊,而是表示 偏移量 。這意味著 32 位的指針可以引用 40 億個 對象 蜜托, 而不是 40 億個字節(jié)抄囚。最終, 也就是說堆內(nèi)存增長到 32 GB 的物理內(nèi)存橄务,也可以用 32 位的指針表示幔托。

一旦你越過那個神奇的 ~32 GB 的邊界,指針就會切回普通對象的指針蜂挪。 每個對象的指針都變長了重挑,就會使用更多的 CPU 內(nèi)存帶寬,也就是說你實際上失去了更多的內(nèi)存棠涮。事實上谬哀,當(dāng)內(nèi)存到達(dá) 40–50 GB 的時候,有效內(nèi)存才相當(dāng)于使用內(nèi)存對象指針壓縮技術(shù)時候的 32 GB 內(nèi)存严肪。

這段描述的意思就是說:即便你有足夠的內(nèi)存史煎,也盡量不要 超過 32 GB。因為它浪費了內(nèi)存诬垂,降低了 CPU 的性能劲室,還要讓 GC 應(yīng)對大內(nèi)存。

到底需要低于 32 GB多少结窘,來設(shè)置我的 JVM很洋?

遺憾的是,這需要看情況隧枫。確切的劃分要根據(jù) JVMs 和操作系統(tǒng)而定喉磁。 如果你想保證其安全可靠谓苟,設(shè)置堆內(nèi)存為 31 GB 是一個安全的選擇。 另外协怒,你可以在你的 JVM 設(shè)置里添加 -XX:+PrintFlagsFinal 用來驗證 JVM 的臨界值涝焙, 并且檢查 UseCompressedOops 的值是否為 true。對于你自己使用的 JVM 和操作系統(tǒng)孕暇,這將找到最合適的堆內(nèi)存臨界值仑撞。

例如,我們在一臺安裝 Java 1.7 的 MacOSX 上測試妖滔,可以看到指針壓縮在被禁用之前隧哮,最大堆內(nèi)存大約是在 32600 mb(~31.83 gb):

$ JAVA_HOME=`/usr/libexec/java_home -v 1.7` java -Xmx32600m -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops
     bool UseCompressedOops   := true

$ JAVA_HOME=`/usr/libexec/java_home -v 1.7` java -Xmx32766m -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops
     bool UseCompressedOops   = false

相比之下,同一臺機器安裝 Java 1.8座舍,可以看到指針壓縮在被禁用之前沮翔,最大堆內(nèi)存大約是在 32766 mb(~31.99 gb):

$ JAVA_HOME=`/usr/libexec/java_home -v 1.8` java -Xmx32766m -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops
     bool UseCompressedOops   := true
$ JAVA_HOME=`/usr/libexec/java_home -v 1.8` java -Xmx32767m -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops
     bool UseCompressedOops   = false

這個例子告訴我們,影響內(nèi)存指針壓縮使用的臨界值曲秉, 是會根據(jù) JVM 的不同而變化的采蚀。 所以從其他地方獲取的例子,需要謹(jǐn)慎使用承二,要確認(rèn)檢查操作系統(tǒng)配置和 JVM榆鼠。

如果使用的是 Elasticsearch v2.2.0,啟動日志其實會告訴你 JVM 是否正在使用內(nèi)存指針壓縮矢洲。 你會看到像這樣的日志消息:

[2015-12-16 13:53:33,417][INFO ][env] [Illyana Rasputin] heap size [989.8mb], compressed ordinary object pointers [true]

這表明內(nèi)存指針壓縮正在被使用璧眠。如果沒有,日志消息會顯示 [false] 读虏。

我有一個 1 TB 內(nèi)存的機器

這個 32 GB 的分割線是很重要的责静。那如果你的機器有很大的內(nèi)存怎么辦呢? 一臺有著 512–768 GB內(nèi)存的服務(wù)器愈發(fā)常見盖桥。

首先灾螃,我們建議避免使用這樣的高配機器(參考 硬件)。

但是如果你已經(jīng)有了這樣的機器揩徊,你有三個可選項:

你主要做全文檢索嗎腰鬼?考慮給 Elasticsearch 4 - 32 GB 的內(nèi)存, 讓 Lucene 通過操作系統(tǒng)文件緩存來利用余下的內(nèi)存塑荒。那些內(nèi)存都會用來緩存 segments熄赡,帶來極速的全文檢索。
你需要更多的排序和聚合齿税?而且大部分的聚合計算是在數(shù)字彼硫、日期、地理點和 非分詞 字符串上?你很幸運拧篮,你的聚合計算將在內(nèi)存友好的 doc values 上完成词渤! 給 Elasticsearch 4 到 32 GB 的內(nèi)存,其余部分為操作系統(tǒng)緩存內(nèi)存中的 doc values串绩。
你在對分詞字符串做大量的排序和聚合(例如缺虐,標(biāo)簽或者 SigTerms,等等)不幸的是礁凡,這意味著你需要 fielddata高氮,意味著你需要堆空間∏昱疲考慮在單個機器上運行兩個或多個節(jié)點纫溃,而不是擁有大量 RAM 的一個節(jié)點。仍然要堅持 50% 原則韧掩。
假設(shè)你有個機器有 128 GB 的內(nèi)存,你可以創(chuàng)建兩個節(jié)點窖铡,每個節(jié)點內(nèi)存分配不超過 32 GB疗锐。 也就是說不超過 64 GB 內(nèi)存給 ES 的堆內(nèi)存,剩下的超過 64 GB 的內(nèi)存給 Lucene费彼。

如果你選擇這一種滑臊,你需要配置

cluster.routing.allocation.same_shard.host: true 。

這會防止同一個分片(shard)的主副本存在同一個物理機上(因為如果存在一個機器上箍铲,副本的高可用性就沒有了)雇卷。

Swapping 是性能的墳?zāi)咕庉?/h3>

這是顯而易見的, 但是還是有必要說的更清楚一點:內(nèi)存交換 到磁盤對服務(wù)器性能來說是 致命 的颠猴。想想看:一個內(nèi)存操作必須能夠被快速執(zhí)行关划。

如果內(nèi)存交換到磁盤上,一個 100 微秒的操作可能變成 10 毫秒翘瓮。 再想想那么多 10 微秒的操作時延累加起來贮折。 不難看出 swapping 對于性能是多么可怕。

最好的辦法就是在你的操作系統(tǒng)中完全禁用 swap资盅。這樣可以暫時禁用:

sudo swapoff -a

如果需要永久禁用调榄,你可能需要修改 /etc/fstab 文件,這要參考你的操作系統(tǒng)相關(guān)文檔呵扛。

如果你并不打算完全禁用 swap每庆,也可以選擇降低 swappiness 的值。 這個值決定操作系統(tǒng)交換內(nèi)存的頻率今穿。 這可以預(yù)防正常情況下發(fā)生交換缤灵,但仍允許操作系統(tǒng)在緊急情況下發(fā)生交換。

對于大部分Linux操作系統(tǒng),可以在 sysctl 中這樣配置:

vm.swappiness = 1

swappiness 設(shè)置為 1 比設(shè)置為 0 要好凤价,因為在一些內(nèi)核版本 swappiness 設(shè)置為 0 會觸發(fā)系統(tǒng) OOM-killer(注:Linux 內(nèi)核的 Out of Memory(OOM)killer 機制)鸽斟。

最后,如果上面的方法都不合適利诺,你需要打開配置文件中的 mlockall 開關(guān)富蓄。 它的作用就是允許 JVM 鎖住內(nèi)存,禁止操作系統(tǒng)交換出去慢逾。在你的 elasticsearch.yml 文件中立倍,設(shè)置如下:

bootstrap.mlockall: true

2 Fielddata 的大小

indices.fielddata.cache.size 控制為 fielddata 分配的堆空間大小。 當(dāng)你發(fā)起一個查詢侣滩,分析字符串的聚合將會被加載到 fielddata口注,如果這些字符串之前沒有被加載過。如果結(jié)果中 fielddata 大小超過了指定 大小 君珠,其他的值將會被回收從而獲得空間寝志。

默認(rèn)情況下,設(shè)置都是 unbounded 策添,Elasticsearch 永遠(yuǎn)都不會從 fielddata 中回收數(shù)據(jù)材部。

這個默認(rèn)設(shè)置是刻意選擇的:fielddata 不是臨時緩存。它是駐留內(nèi)存里的數(shù)據(jù)結(jié)構(gòu)唯竹,必須可以快速執(zhí)行訪問乐导,而且構(gòu)建它的代價十分高昂。如果每個請求都重載數(shù)據(jù)浸颓,性能會十分糟糕物臂。

一個有界的大小會強制數(shù)據(jù)結(jié)構(gòu)回收數(shù)據(jù)。我們會看何時應(yīng)該設(shè)置這個值产上,但請首先閱讀以下警告:


這個設(shè)置是一個安全衛(wèi)士棵磷,而非內(nèi)存不足的解決方案。

如果沒有足夠空間可以將 fielddata 保留在內(nèi)存中晋涣,Elasticsearch 就會時刻從磁盤重載數(shù)據(jù)泽本,并回收其他數(shù)據(jù)以獲得更多空間。內(nèi)存的回收機制會導(dǎo)致重度磁盤I/O姻僧,并且在內(nèi)存中生成很多垃圾规丽,這些垃圾必須在晚些時候被回收掉。

設(shè)想我們正在對日志進(jìn)行索引撇贺,每天使用一個新的索引赌莺。通常我們只對過去一兩天的數(shù)據(jù)感興趣,盡管我們會保留老的索引松嘶,但我們很少需要查詢它們艘狭。不過如果采用默認(rèn)設(shè)置,舊索引的 fielddata 永遠(yuǎn)不會從緩存中回收! fieldata 會保持增長直到 fielddata 發(fā)生斷熔(請參閱 斷路器)巢音,這樣我們就無法載入更多的 fielddata遵倦。

這個時候,我們被困在了死胡同官撼。但我們?nèi)匀豢梢栽L問舊索引中的 fielddata梧躺,也無法加載任何新的值。相反傲绣,我們應(yīng)該回收舊的數(shù)據(jù)掠哥,并為新值獲得更多空間。

為了防止發(fā)生這樣的事情秃诵,可以通過在 config/elasticsearch.yml 文件中增加配置為 fielddata 設(shè)置一個上限:

indices.fielddata.cache.size:  20%

可以設(shè)置堆大小的百分比续搀,也可以是某個值,例如: 5gb 菠净。
有了這個設(shè)置禁舷,最久未使用(LRU)的 fielddata 會被回收為新數(shù)據(jù)騰出空間。

可能發(fā)現(xiàn)在線文檔有另外一個設(shè)置: indices.fielddata.cache.expire 毅往。

這個設(shè)置 永遠(yuǎn)都不會 被使用榛了!它很有可能在不久的將來被棄用。

這個設(shè)置要求 Elasticsearch 回收那些 過期 的 fielddata煞抬,不管這些值有沒有被用到。

這對性能是件 很糟糕 的事情构哺「锎穑回收會有消耗性能,它刻意的安排回收方式曙强,而沒能獲得任何回報残拐。

沒有理由使用這個設(shè)置:我們不能從理論上假設(shè)一個有用的情形。目前碟嘴,它的存在只是為了向前兼容溪食。我們只在很有以前提到過這個設(shè)置,但不幸的是網(wǎng)上各種文章都將其作為一種性能調(diào)優(yōu)的小竅門來推薦娜扇。

它不是错沃。永遠(yuǎn)不要使用!

監(jiān)控 fielddata(Monitoring fielddata)

無論是仔細(xì)監(jiān)控 fielddata 的內(nèi)存使用情況雀瓢, 還是看有無數(shù)據(jù)被回收都十分重要枢析。高的回收數(shù)可以預(yù)示嚴(yán)重的資源問題以及性能不佳的原因。

Fielddata 的使用可以被監(jiān)控:

GET /_stats/fielddata?fields=*
GET /_nodes/stats/indices/fielddata?fields=*
  • 按索引節(jié)點
GET /_nodes/stats/indices/fielddata?level=indices&fields=*

使用設(shè)置 ?fields=* 刃麸,可以將內(nèi)存使用分配到每個字段醒叁。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子把沼,更是在濱河造成了極大的恐慌啊易,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饮睬,死亡現(xiàn)場離奇詭異租谈,居然都是意外死亡,警方通過查閱死者的電腦和手機续捂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門垦垂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人牙瓢,你說我怎么就攤上這事劫拗。” “怎么了矾克?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵页慷,是天一觀的道長。 經(jīng)常有香客問我胁附,道長酒繁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任控妻,我火速辦了婚禮州袒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘弓候。我一直安慰自己郎哭,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布菇存。 她就那樣靜靜地躺著夸研,像睡著了一般。 火紅的嫁衣襯著肌膚如雪依鸥。 梳的紋絲不亂的頭發(fā)上亥至,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機與錄音贱迟,去河邊找鬼姐扮。 笑死,一個胖子當(dāng)著我的面吹牛衣吠,可吹牛的內(nèi)容都是我干的溶握。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蒸播,長吁一口氣:“原來是場噩夢啊……” “哼睡榆!你這毒婦竟也來了萍肆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤胀屿,失蹤者是張志新(化名)和其女友劉穎塘揣,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宿崭,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡亲铡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了葡兑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奖蔓。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖讹堤,靈堂內(nèi)的尸體忽然破棺而出吆鹤,到底是詐尸還是另有隱情,我是刑警寧澤洲守,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布疑务,位于F島的核電站,受9級特大地震影響梗醇,放射性物質(zhì)發(fā)生泄漏知允。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一叙谨、第九天 我趴在偏房一處隱蔽的房頂上張望温鸽。 院中可真熱鬧,春花似錦手负、人聲如沸涤垫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至股缸,卻和暖如春衡楞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背敦姻。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工瘾境, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人镰惦。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓迷守,卻偏偏與公主長得像,于是被迫代替她去往敵國和親旺入。 傳聞我的和親對象是個殘疾皇子兑凿,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容