先了解相關(guān)讀寫原理
es 寫數(shù)據(jù)過程
客戶端選擇一個(gè) node 發(fā)送請求過去,這個(gè) node 就是 coordinating node (協(xié)調(diào)節(jié)點(diǎn))。
coordinating node 對 document 進(jìn)行路由,將請求轉(zhuǎn)發(fā)給對應(yīng)的 node(有 primary shard)。
實(shí)際的 node 上的 primary shard 處理請求,然后將數(shù)據(jù)同步到 replica node 。
coordinating node 如果發(fā)現(xiàn) primary node 和所有 replica node 都搞定之后,就返回響應(yīng)結(jié)果給客戶端。
es 讀數(shù)據(jù)過程
可以通過 doc id 來查詢,會(huì)根據(jù) doc id 進(jìn)行 hash,判斷出來當(dāng)時(shí)把 doc id 分配到了哪個(gè) shard 上面去,從那個(gè) shard 去查詢。
客戶端發(fā)送請求到任意一個(gè) node,成為 coordinate node 。
coordinate node 對 doc id 進(jìn)行哈希路由,將請求轉(zhuǎn)發(fā)到對應(yīng)的 node,此時(shí)會(huì)使用 round-robin 隨機(jī)輪詢算法,在 primary shard 以及其所有 replica 中隨機(jī)選擇一個(gè),讓讀請求負(fù)載均衡。
接收請求的 node 返回 document 給 coordinate node 。
coordinate node 返回 document 給客戶端。
es 搜索數(shù)據(jù)過程
es 最強(qiáng)大的是做全文檢索,就是比如你有三條數(shù)據(jù):
java真好玩兒啊
java好難學(xué)啊
j2ee特別牛
你根據(jù) java 關(guān)鍵詞來搜索,將包含 java 的 document 給搜索出來。es 就會(huì)給你返回:java真好玩兒啊,java好難學(xué)啊。
客戶端發(fā)送請求到一個(gè) coordinate node 。
協(xié)調(diào)節(jié)點(diǎn)將搜索請求轉(zhuǎn)發(fā)到所有的 shard 對應(yīng)的 primary shard 或 replica shard ,都可以。
query phase:每個(gè) shard 將自己的搜索結(jié)果(其實(shí)就是一些 doc id )返回給協(xié)調(diào)節(jié)點(diǎn),由協(xié)調(diào)節(jié)點(diǎn)進(jìn)行數(shù)據(jù)的合并、排序、分頁等操作,產(chǎn)出最終結(jié)果。
fetch phase:接著由協(xié)調(diào)節(jié)點(diǎn)根據(jù) doc id 去各個(gè)節(jié)點(diǎn)上拉取實(shí)際的 document 數(shù)據(jù),最終返回給客戶端。
寫請求是寫入 primary shard,然后同步給所有的 replica shard;讀請求可以從 primary shard 或 replica shard 讀取,采用的是隨機(jī)輪詢算法。
寫數(shù)據(jù)底層原理
先寫入內(nèi)存 buffer,在 buffer 里的時(shí)候數(shù)據(jù)是搜索不到的;同時(shí)將數(shù)據(jù)寫入 translog 日志文件。
如果 buffer 快滿了,或者到一定時(shí)間,就會(huì)將內(nèi)存 buffer 數(shù)據(jù) refresh 到一個(gè)新的 segment file 中,但是此時(shí)數(shù)據(jù)不是直接進(jìn)入 segment file 磁盤文件,而是先進(jìn)入 os cache 。這個(gè)過程就是 refresh 。
每隔 1 秒鐘,es 將 buffer 中的數(shù)據(jù)寫入一個(gè)新的 segment file ,每秒鐘會(huì)產(chǎn)生一個(gè)新的磁盤文件 segment file ,這個(gè) segment file 中就存儲最近 1 秒內(nèi) buffer 中寫入的數(shù)據(jù)。
但是如果 buffer 里面此時(shí)沒有數(shù)據(jù),那當(dāng)然不會(huì)執(zhí)行 refresh 操作,如果 buffer 里面有數(shù)據(jù),默認(rèn) 1 秒鐘執(zhí)行一次 refresh 操作,刷入一個(gè)新的 segment file 中。
操作系統(tǒng)里面,磁盤文件其實(shí)都有一個(gè)東西,叫做 os cache ,即操作系統(tǒng)緩存,就是說數(shù)據(jù)寫入磁盤文件之前,會(huì)先進(jìn)入 os cache ,先進(jìn)入操作系統(tǒng)級別的一個(gè)內(nèi)存緩存中去。只要 buffer 中的數(shù)據(jù)被 refresh 操作刷入 os cache 中,這個(gè)數(shù)據(jù)就可以被搜索到了。
為什么叫 es 是準(zhǔn)實(shí)時(shí)的? NRT ,全稱 near real-time 。默認(rèn)是每隔 1 秒 refresh 一次的,所以 es 是準(zhǔn)實(shí)時(shí)的,因?yàn)閷懭氲臄?shù)據(jù) 1 秒之后才能被看到??梢酝ㄟ^ es 的 restful api 或者 java api ,手動(dòng)執(zhí)行一次 refresh 操作,就是手動(dòng)將 buffer 中的數(shù)據(jù)刷入 os cache 中,讓數(shù)據(jù)立馬就可以被搜索到。只要數(shù)據(jù)被輸入 os cache 中,buffer 就會(huì)被清空了,因?yàn)椴恍枰A?buffer 了,數(shù)據(jù)在 translog 里面已經(jīng)持久化到磁盤去一份了。
重復(fù)上面的步驟,新的數(shù)據(jù)不斷進(jìn)入 buffer 和 translog,不斷將 buffer 數(shù)據(jù)寫入一個(gè)又一個(gè)新的 segment file 中去,每次 refresh 完 buffer 清空,translog 保留。隨著這個(gè)過程推進(jìn),translog 會(huì)變得越來越大。當(dāng) translog 達(dá)到一定長度的時(shí)候,就會(huì)觸發(fā) commit 操作。
commit 操作發(fā)生第一步,就是將 buffer 中現(xiàn)有數(shù)據(jù) refresh 到 os cache 中去,清空 buffer。然后,將一個(gè) commit point 寫入磁盤文件,里面標(biāo)識著這個(gè) commit point 對應(yīng)的所有 segment file ,同時(shí)強(qiáng)行將 os cache 中目前所有的數(shù)據(jù)都 fsync 到磁盤文件中去。最后清空 現(xiàn)有 translog 日志文件,重啟一個(gè) translog,此時(shí) commit 操作完成。
這個(gè) commit 操作叫做 flush 。默認(rèn) 30 分鐘自動(dòng)執(zhí)行一次 flush ,但如果 translog 過大,也會(huì)觸發(fā) flush 。flush 操作就對應(yīng)著 commit 的全過程,我們可以通過 es api,手動(dòng)執(zhí)行 flush 操作,手動(dòng)將 os cache 中的數(shù)據(jù) fsync 強(qiáng)刷到磁盤上去。
translog 日志文件的作用是什么?你執(zhí)行 commit 操作之前,數(shù)據(jù)要么是停留在 buffer 中,要么是停留在 os cache 中,無論是 buffer 還是 os cache 都是內(nèi)存,一旦這臺機(jī)器死了,內(nèi)存中的數(shù)據(jù)就全丟了。所以需要將數(shù)據(jù)對應(yīng)的操作寫入一個(gè)專門的日志文件 translog 中,一旦此時(shí)機(jī)器宕機(jī),再次重啟的時(shí)候,es 會(huì)自動(dòng)讀取 translog 日志文件中的數(shù)據(jù),恢復(fù)到內(nèi)存 buffer 和 os cache 中去。
translog 其實(shí)也是先寫入 os cache 的,默認(rèn)每隔 5 秒刷一次到磁盤中去,所以默認(rèn)情況下,可能有 5 秒的數(shù)據(jù)會(huì)僅僅停留在 buffer 或者 translog 文件的 os cache 中,如果此時(shí)機(jī)器掛了,會(huì)丟失 5 秒鐘的數(shù)據(jù)。但是這樣性能比較好,最多丟 5 秒的數(shù)據(jù)。也可以將 translog 設(shè)置成每次寫操作必須是直接 fsync 到磁盤,但是性能會(huì)差很多。
es 第一是準(zhǔn)實(shí)時(shí)的,數(shù)據(jù)寫入 1 秒后可以搜索到;可能會(huì)丟失數(shù)據(jù)的。有 5 秒的數(shù)據(jù),停留在 buffer、translog os cache、segment file os cache 中,而不在磁盤上,此時(shí)如果宕機(jī),會(huì)導(dǎo)致 5 秒的數(shù)據(jù)丟失。
總結(jié)一下,數(shù)據(jù)先寫入內(nèi)存 buffer,然后每隔 1s,將數(shù)據(jù) refresh 到 os cache,到了 os cache 數(shù)據(jù)就能被搜索到(所以我們才說 es 從寫入到能被搜索到,中間有 1s 的延遲)。每隔 5s,將數(shù)據(jù)寫入 translog 文件(這樣如果機(jī)器宕機(jī),內(nèi)存數(shù)據(jù)全沒,最多會(huì)有 5s 的數(shù)據(jù)丟失),translog 大到一定程度,或者默認(rèn)每隔 30mins,會(huì)觸發(fā) commit 操作,將緩沖區(qū)的數(shù)據(jù)都 flush 到 segment file 磁盤文件中。
數(shù)據(jù)寫入 segment file 之后,同時(shí)就建立好了倒排索引。
一個(gè)segment是一個(gè)完備的lucene倒排索引,而倒排索引是通過詞典 (Term Dictionary)到文檔列表(Postings List)的映射關(guān)系,快速做查詢的。由于詞典的size會(huì)很大,全部裝載到heap里不現(xiàn)實(shí),因此Lucene為詞典做了一層前綴索引(Term Index),這個(gè)索引在Lucene4.0以后采用的數(shù)據(jù)結(jié)構(gòu)是FST (Finite State Transducer)。這種數(shù)據(jù)結(jié)構(gòu)占用空間很小,Lucene打開索引的時(shí)候?qū)⑵淙垦b載到內(nèi)存中,加快磁盤上詞典查詢速度的同時(shí)減少隨機(jī)磁盤訪問次數(shù)。
每個(gè)segment都有會(huì)一些索引數(shù)據(jù)駐留在heap里。因此segment越多,瓜分掉的heap也越多,并且這部分heap是無法被GC掉的
刪除/更新數(shù)據(jù)底層原理
如果是刪除操作,commit 的時(shí)候會(huì)生成一個(gè) .del 文件,里面將某個(gè) doc 標(biāo)識為 deleted 狀態(tài),那么搜索的時(shí)候根據(jù) .del 文件就知道這個(gè) doc 是否被刪除了。
如果是更新操作,就是將原來的 doc 標(biāo)識為 deleted 狀態(tài),然后新寫入一條數(shù)據(jù)。
buffer 每 refresh 一次,就會(huì)產(chǎn)生一 個(gè) segment file ,所以默認(rèn)情況下是 1 秒鐘一個(gè) segment file ,這樣下來 segment file 會(huì)越來越多,此時(shí)會(huì)定期執(zhí)行 merge。每次 merge 的時(shí)候,會(huì)將多個(gè) segment file 合并成一個(gè),同時(shí)這里會(huì)將標(biāo)識為 deleted 的 doc 給物理刪除掉,然后將新的 segment file 寫入磁盤,這里會(huì)寫一個(gè) commit point ,標(biāo)識所有新的 segment file ,然后打開 segment file 供搜索使用,同時(shí)刪除舊的 segment file 。
通用建議
不要返回大結(jié)果集
Elasticsearch被設(shè)計(jì)為搜索引擎,使其非常適合檢索與查詢匹配的最前面的文檔。但是,對于屬于數(shù)據(jù)庫域的工作負(fù)載(如檢索匹配特定查詢的所有文檔),效果不佳。如果需要執(zhí)行此操作,請確保使用Scroll API。
避免大文檔
假設(shè)默認(rèn)的http.max_content_length設(shè)置為100MB,Elasticsearch將拒絕索引任何大于此值的文檔。您可能決定增加該特定設(shè)置,但是Lucene仍然有大約2GB的限制。
即使不考慮硬性限制,大型文檔通常也不實(shí)用。大型文檔給網(wǎng)絡(luò),內(nèi)存使用和磁盤帶來了更大的壓力,即使對于不要求_source的搜索請求也是如此,因?yàn)镋lasticsearch在所有情況下都需要獲取文檔的_id,并且由于 文件系統(tǒng)緩存的工作方式,大型文檔獲取此字段的成本更高。索引此文檔使用的內(nèi)存量是該文檔原始大小的數(shù)倍。近似搜索(例如phrase查詢)和高亮顯示開銷也變得更加昂貴,因?yàn)樗鼈兊某杀局苯尤Q于原始文檔的大小。
重新考慮信息單位有時(shí)是有用的。例如,您想使書籍可搜索,并不一定意味著文檔應(yīng)包含整本書。最好將章節(jié)或段落用作文檔,這些文檔中具有一個(gè)屬性,以標(biāo)識它們屬于哪本書。這不僅避免了大文檔的問題,還使搜索體驗(yàn)更好。例如,如果用戶搜索foo和bar這兩個(gè)詞,則匹配的結(jié)果跨不同章節(jié)可能體驗(yàn)非常差,而匹配結(jié)果落入同一段落中就可能很不錯(cuò)。
秘密訣竅
混合精確搜索和提取詞干
在構(gòu)建搜索應(yīng)用程序時(shí),通常必須使用詞干,比如對于“skiing”的查詢需要匹配包含“ ski”或“ skis”的文檔。但是,如果用戶想專門搜索“skiing”怎么辦?執(zhí)行此操作的典型方法是使用 multi-field,以便以兩種不同的方式對相同的內(nèi)容建立索引:
curl -X PUT "localhost:9200/index?pretty" -H 'Content-Type: application/json' -d'{ "settings": { "analysis": { "analyzer": { "english_exact": { "tokenizer": "standard", "filter": [ "lowercase" ] } } } }, "mappings": { "properties": { "body": { "type": "text", "analyzer": "english", "fields": { "exact": { "type": "text", "analyzer": "english_exact" } } } } }}'curl -X PUT "localhost:9200/index/_doc/1?pretty" -H 'Content-Type: application/json' -d'{ "body": "Ski resort"}'curl -X PUT "localhost:9200/index/_doc/2?pretty" -H 'Content-Type: application/json' -d'{ "body": "A pair of skis"}'curl -X POST "localhost:9200/index/_refresh?pretty"
兩個(gè)記錄都返回的搜索:
curl -X GET "localhost:9200/index/_search?pretty" -H 'Content-Type: application/json' -d'{ "query": { "simple_query_string": { "fields": [ "body" ], "query": "ski" } }}'
返回第一個(gè)記錄的搜索:
curl -X GET "localhost:9200/index/_search?pretty" -H 'Content-Type: application/json' -d'{"query": {"simple_query_string": {"fields": [ "body.exact" ],"query": "ski" } }}'
獲得一致的評分
當(dāng)要獲得良好的評分功能時(shí),Elasticsearch使用分片和副本進(jìn)行操作會(huì)增加挑戰(zhàn)。
分?jǐn)?shù)不可復(fù)制
假設(shè)同一位用戶連續(xù)兩次執(zhí)行相同的請求,并且文檔兩次都沒有以相同的順序返回,這是非常糟糕的體驗(yàn),不是嗎?不幸的是,如果您有副本(index.number_of_replicas大于0),則可能會(huì)發(fā)生這種情況。原因是Elasticsearch以循環(huán)方式選擇查詢應(yīng)訪問的分片,因此,如果您連續(xù)運(yùn)行兩次相同的查詢,很有可能會(huì)訪問同一分片的不同副本。
現(xiàn)在為什么會(huì)出現(xiàn)問題?索引統(tǒng)計(jì)是分?jǐn)?shù)的重要組成部分。而且由于刪除的文檔,同一分片的副本之間的索引統(tǒng)計(jì)可能會(huì)有所不同。您可能知道刪除或更新文檔時(shí),不會(huì)立即將舊文檔從索引中刪除,而是將其標(biāo)記為已刪除,并且僅在下次合并該舊文檔所屬的segment時(shí)才從磁盤中刪除它。但是,出于實(shí)際原因,這些已刪除的文檔將用于索引統(tǒng)計(jì)。因此,假設(shè)主分片剛剛完成了一個(gè)大型合并,刪除了許多已刪除的文檔,那么它的索引統(tǒng)計(jì)信息可能與副本(仍然有大量已刪除文檔)完全不同,因此得分也有所不同。
解決此問題的推薦方法是,使用一個(gè)標(biāo)識所登入的用戶的字符串(例如,用戶ID或會(huì)話ID)作為首選項(xiàng)。這樣可以確保給定用戶的所有查詢始終會(huì)打到相同的分片,因此各查詢的得分更加一致。
解決此問題的另一個(gè)好處是:當(dāng)兩個(gè)文檔的分?jǐn)?shù)相同時(shí),默認(rèn)情況下將按其內(nèi)部Lucene文檔ID(與_id無關(guān))對它們進(jìn)行排序。但是,這些doc ID在同一分片的副本之間可能會(huì)有所不同。因此,通過始終訪問相同的分片,得分相同的文檔更獲得一致的排序。
相關(guān)性看起來不對
如果您發(fā)現(xiàn)具有相同內(nèi)容的兩個(gè)文檔獲得不同的分?jǐn)?shù),或者完全匹配的內(nèi)容沒有排在第一位,則該問題可能與分片有關(guān)。默認(rèn)情況下,Elasticsearch使每個(gè)分片負(fù)責(zé)產(chǎn)生自己的分?jǐn)?shù)。但是,由于索引統(tǒng)計(jì)信息是得分的重要貢獻(xiàn)者,因此只有在分片具有相似的索引統(tǒng)計(jì)信息時(shí),此方法才有效。假設(shè)是由于默認(rèn)情況下文檔均勻地路由到分片,因此索引統(tǒng)計(jì)信息應(yīng)該非常相似,并且評分將按預(yù)期進(jìn)行。但是,如果您:
在寫入索引時(shí)路由,
查詢多個(gè)索引,
或索引中的數(shù)據(jù)太少
那么很有可能所有與搜索請求有關(guān)的分片都沒有相似的索引統(tǒng)計(jì)信息,并且相關(guān)性可能很差。
如果數(shù)據(jù)集較小,則解決此問題的最簡單方法是將所有內(nèi)容編入具有單個(gè)分片(index.number_of_shards:1)的索引,這是默認(rèn)設(shè)置。然后,所有文檔的索引統(tǒng)計(jì)信息都將相同,并且得分也將保持一致。
否則,解決此問題的推薦方法是使用dfs_query_then_fetch搜索類型。這將使Elasticsearch對所有涉及的分片執(zhí)行初始往返,要求他們提供與查詢有關(guān)的索引統(tǒng)計(jì)信息,然后協(xié)調(diào)節(jié)點(diǎn)將合并這些統(tǒng)計(jì)信息,并在請求分片執(zhí)行查詢階段時(shí)將合并的統(tǒng)計(jì)信息與請求一起發(fā)送,這樣分片就可以使用這些全局統(tǒng)計(jì)信息而不是它們自己的統(tǒng)計(jì)信息來進(jìn)行評分。
在大多數(shù)情況下,這種額外的往返開銷應(yīng)該很少。但是,如果您的查詢包含大量字段/term或模糊查詢,請注意,僅收集統(tǒng)計(jì)信息可能并不便利,因?yàn)楸仨氃趖erm詞典中查找所有term才能查找到統(tǒng)計(jì)信息。
將靜態(tài)相關(guān)性信號納入評分
許多域具有已知的與相關(guān)性相關(guān)的靜態(tài)信號。例如,PageRank和URL長度是Web搜索的兩個(gè)常用功能,以便獨(dú)立于查詢來調(diào)整網(wǎng)頁的分?jǐn)?shù)。
有兩個(gè)主要查詢,可以將靜態(tài)分?jǐn)?shù)貢獻(xiàn)與文本相關(guān)性結(jié)合起來,例如。用BM25計(jì)算得出: - script_score query - rank_feature query、
例如,假設(shè)您有一個(gè)希望與BM25得分結(jié)合使用的pagerank字段,以使最終得分等于score = bm25_score + pagerank /(10 + pagerank)。
使用script_score查詢,查詢將如下所示:
curl -X GET "localhost:9200/index/_search?pretty" -H 'Content-Type: application/json' -d'{"query": {"script_score": {"query": {"match": { "body": "elasticsearch" } },"script": {"source": "_score * saturation(doc[u0027pageranku0027].value, 10)" } } }}'
盡管這兩個(gè)選項(xiàng)都將返回相似的分?jǐn)?shù),但需要權(quán)衡取舍:script_score提供了很大的靈活性,使您可以根據(jù)需要將文本相關(guān)性分?jǐn)?shù)與靜態(tài)信號結(jié)合起來。另一方面,rank_feature查詢僅提供了幾種將靜態(tài)信號混合到評分中的方法。但是,它依賴于rank_feature和rank_features字段,它們以一種特殊的方式索引值,從而使rank_feature查詢可以跳過非競爭性文檔并更快地獲得查詢的頂部匹配項(xiàng)。
寫入優(yōu)化
加大translog flush間隔,目的是降低iops、writeblock。
從ES 2.x開始,在默認(rèn)設(shè)置下,translog的持久化策略為:每個(gè)請求都“flush”。對應(yīng)配置項(xiàng)如下:index.translog.durability: request
這是影響 ES 寫入速度的最大因素。但是只有這樣,寫操作才有可能是可靠的。如果系統(tǒng)可以接受一定概率的數(shù)據(jù)丟失(例如,數(shù)據(jù)寫入主分片成功,尚未復(fù)制到副分片時(shí),主機(jī)斷電。由于數(shù)據(jù)既沒有刷到Lucene,translog也沒有刷盤,恢復(fù)時(shí)translog中沒有這個(gè)數(shù)據(jù),數(shù)據(jù)丟失),則調(diào)整translog持久化策略為周期性和一定大小的時(shí)候“flush”,例如:index.translog.durability: async
設(shè)置為async表示translog的刷盤策略按sync_interval配置指定的時(shí)間周期進(jìn)行。
index.translog.sync_interval: 120s
加大index refresh間隔,除了降低I/O,更重要的是降低了segment merge頻率。
每次索引的refresh會(huì)產(chǎn)生一個(gè)新的Lucene段,這會(huì)導(dǎo)致頻繁的segment merge行為使更改對搜索可見的操作(稱為刷新)非常昂貴,并且在正在進(jìn)行索引活動(dòng)的情況下經(jīng)常進(jìn)行調(diào)用會(huì)損害索引速度。
默認(rèn)情況下,Elasticsearch會(huì)定期每秒刷新一次索引,但僅在最近30秒內(nèi)已收到一個(gè)或多個(gè)搜索請求的索引上刷新。
如果您沒有或只有很少的搜索流量(例如,每5分鐘少于一個(gè)搜索請求)并且想要優(yōu)化索引速度,則這是最佳配置。此行為旨在在不執(zhí)行搜索時(shí)在默認(rèn)情況下自動(dòng)優(yōu)化批量索引。為了選擇退出此行為,請顯式設(shè)置刷新間隔。
另一方面,如果您的索引遇到常規(guī)搜索請求,則此默認(rèn)行為表示Elasticsearch將每1秒刷新一次索引。如果您有能力增加從索引到文檔可見之間的時(shí)間,則可以將index.refresh_interval增加到更大的值,例如30s,可能有助于提高索引速度。
調(diào)整bulk請求。
批量請求將比單文檔索引請求產(chǎn)生更好的性能。為了知道批量請求的最佳大小,您應(yīng)該在具有單個(gè)分片的單節(jié)點(diǎn)上運(yùn)行基準(zhǔn)測試。首先嘗試一次索引100個(gè)文檔,然后索引200個(gè),再索引400個(gè),依此類推。在每次基準(zhǔn)測試運(yùn)行中,批量請求中的文檔數(shù)量加倍。當(dāng)索引速度開始趨于平穩(wěn)時(shí),您便知道已達(dá)到批量請求數(shù)據(jù)的最佳大小。如果得分相同,寧可少也不要多。當(dāng)大量請求同時(shí)發(fā)送時(shí),請注意太大的批量請求可能會(huì)使集群處于內(nèi)存壓力下,因此,建議即使每個(gè)請求看起來執(zhí)行得更好,也要避免每個(gè)請求超過幾十兆字節(jié)。
如果 CPU 沒有壓滿,則應(yīng)該提高寫入端的并發(fā)數(shù)量。但是要注意 bulk線程池隊(duì)列的reject情況,出現(xiàn)reject代表ES的bulk隊(duì)列已滿,客戶端請求被拒絕,此時(shí)客戶端會(huì)收到429錯(cuò)誤(TOO_M(jìn)ANY_REQUESTS),客戶端對此的處理策略應(yīng)該是延遲重試。不可忽略這個(gè)異常,否則寫入系統(tǒng)的數(shù)據(jù)會(huì)少于預(yù)期。即使客戶端正確處理了429錯(cuò)誤,我們?nèi)匀粦?yīng)該盡量避免產(chǎn)生reject。因此,在評估極限的寫入能力時(shí),客戶端的極限寫入并發(fā)量應(yīng)該控制在不產(chǎn)生reject前提下的最大值為宜。
bulk線程池和隊(duì)列
建立索引的過程屬于計(jì)算密集型任務(wù),應(yīng)該使用固定大小的線程池配置,來不及處理的任務(wù)放入隊(duì)列。線程池最大線程數(shù)量應(yīng)配置為CPU核心數(shù)+1,這也是bulk線程池的默認(rèn)設(shè)置,可以避免過多的上下文切換。隊(duì)列大小可以適當(dāng)增加,但一定要嚴(yán)格控制大小,過大的隊(duì)列導(dǎo)致較高的GC壓力,并可能導(dǎo)致FGC頻繁發(fā)生。
升級硬件
如果索引是受I / O約束的,則應(yīng)研究為文件系統(tǒng)高速緩存提供更多內(nèi)存(請參見上文)或購買速度更快的驅(qū)動(dòng)器。特別是,已知SSD驅(qū)動(dòng)器的性能要比旋轉(zhuǎn)磁盤好。始終使用本地存儲,應(yīng)避免使用NFS或SMB等遠(yuǎn)程文件系統(tǒng)。還請注意虛擬存儲,例如Amazon的Elastic Block Storage。虛擬存儲在Elasticsearch上可以很好地工作,并且很有吸引力,因?yàn)樗惭b起來如此之快且簡單,但是與專用本地存儲相比,它在本質(zhì)上在持續(xù)運(yùn)行方面還很慢。如果在EBS上建立索引,請確保使用預(yù)配置的IOPS,否則操作可能會(huì)很快受到限制。
通過配置RAID 0陣列,跨多個(gè)SSD劃分索引。請記住,由于任何一個(gè)SSD的故障都會(huì)破壞索引,因此會(huì)增加故障的風(fēng)險(xiǎn)。但是,通常這是一個(gè)正確的權(quán)衡:優(yōu)化單個(gè)分片以實(shí)現(xiàn)最佳性能,然后在不同節(jié)點(diǎn)之間添加副本,以便為任何節(jié)點(diǎn)故障提供冗余。您還可以使用快照和還原來備份索引以提供進(jìn)一步保障。
優(yōu)化磁盤間的任務(wù)均勻情況,將shard盡量均勻分布到物理主機(jī)的各個(gè)磁盤。
如果部署方案是為path.data配置多個(gè)路徑來使用多塊磁盤,則ES在分配shard時(shí),落到各磁盤上的 shard 可能并不均勻,這種不均勻可能會(huì)導(dǎo)致某些磁盤繁忙,利用率在較長時(shí)間內(nèi)持續(xù)達(dá)到100%。這種不均勻達(dá)到一定程度會(huì)對寫入性能產(chǎn)生負(fù)面影響。ES在處理多路徑時(shí),優(yōu)先將shard分配到可用空間百分比最多的磁盤上,因此短時(shí)間內(nèi)創(chuàng)建的shard可能被集中分配到這個(gè)磁盤上,即使可用空間是99%和98%的差別。后來ES在2.x版本中開始解決這個(gè)問題:預(yù)估一下shard 會(huì)使用的空間,從磁盤可用空間中減去這部分,直到現(xiàn)在6.x版也是這種處理方式。但是實(shí)現(xiàn)也存在一些問題:
從可用空間減去預(yù)估大小這種機(jī)制只存在于一次索引創(chuàng)建的過程中,下一次的索引創(chuàng)建,磁盤可用空間并不是上次做完減法以后的結(jié)果。這也可以理解,畢竟預(yù)估是不準(zhǔn)的,一直減下去空間很快就減沒了。但是最終的效果是,這種機(jī)制并沒有從根本上解決問題,即使沒有完美的解決方案,這種機(jī)制的效果也不夠好。如果單一的機(jī)制不能解決所有的場景,那么至少應(yīng)該為不同場景準(zhǔn)備多種選擇。為此,我們?yōu)镋S增加了兩種策略?!?/p>
簡單輪詢:在系統(tǒng)初始階段,簡單輪詢的效果是最均勻的。·
基于可用空間的動(dòng)態(tài)加權(quán)輪詢:以可用空間作為權(quán)重,在磁盤之間加權(quán)輪詢。
您應(yīng)該通過禁用交換來確保操作系統(tǒng)不會(huì)交換出Java進(jìn)程。
大多數(shù)操作系統(tǒng)嘗試為文件系統(tǒng)高速緩存使用盡可能多的內(nèi)存,并急切換出未使用的應(yīng)用程序內(nèi)存。這可能會(huì)導(dǎo)致部分JVM堆甚至其可執(zhí)行頁面換出到磁盤上。
交換對性能,節(jié)點(diǎn)穩(wěn)定性非常不利,應(yīng)不惜一切代價(jià)避免交換。它可能導(dǎo)致垃圾收集持續(xù)數(shù)分鐘而不是毫秒,并且可能導(dǎo)致節(jié)點(diǎn)響應(yīng)緩慢甚至斷開與集群的連接。在彈性分布式系統(tǒng)中,讓操作系統(tǒng)殺死該節(jié)點(diǎn)更為有效。
文件系統(tǒng)緩存將用于緩沖I / O操作。您應(yīng)確保至少將運(yùn)行Elasticsearch的計(jì)算機(jī)的一半內(nèi)存分配給文件系統(tǒng)緩存。
-
性能優(yōu)化
+關(guān)注
關(guān)注
0文章
18瀏覽量
7440 -
Elasticsearch
+關(guān)注
關(guān)注
0文章
30瀏覽量
2844
發(fā)布評論請先 登錄
相關(guān)推薦
評論