前沿拓展:
寫入緩存策略
打開,可以有助于電腦性能提高
但是這樣最好不要強行斷電重啟,可能會損傷硬盤
1、ES 的寫入過程1.1 ES支持四種對文檔的數(shù)據(jù)寫**作create:如果在PUT數(shù)據(jù)的時候當前數(shù)據(jù)已經(jīng)存在,則數(shù)據(jù)會被覆蓋,如果在PUT的時候加上**作類型create,此時如果數(shù)據(jù)已存在則會返回失敗,因為已經(jīng)強制指定了**作類型為create,ES就不會再去執(zhí)行update**作。比如:PUT /pruduct/_create/1/ ( 老版本的語法為 PUT /pruduct/_doc/1/_create )指的就是在索引product中強制創(chuàng)建id為1的數(shù)據(jù),如果id為1的數(shù)據(jù)已存在,則返回失敗。delete:刪除文檔,ES對文檔的刪除是懶刪除機制,即標記刪除。index:在ES中,寫入**作被稱為Index,這里Index為動詞,即索引數(shù)據(jù)為將數(shù)據(jù)創(chuàng)建在ES中的索引,后面章節(jié)中均稱之為“索引數(shù)據(jù)”。update:執(zhí)行partial update(全量替換,部分替換)1.2 寫流程
ES中的數(shù)據(jù)寫入均發(fā)生在Primary Shard,當數(shù)據(jù)在Primary寫入完成之后會同步到相應的Replica Shard。下圖演示了單條數(shù)據(jù)寫入ES的流程:
以下為數(shù)據(jù)寫入的步驟:
客戶端發(fā)起寫入請求至node 4node 4通過文檔 id 在路由表中的映射信息確定當前數(shù)據(jù)的位置為分片0,分片0的主分片位于node 5,并將數(shù)據(jù)轉(zhuǎn)發(fā)至node 5。數(shù)據(jù)在node 5寫入,寫入成功之后將數(shù)據(jù)的同步請求轉(zhuǎn)發(fā)至其副本所在的node 4和node 6上面,等待所有副本(具體等待多少副本取決于wait_for_active_shards的配置值)數(shù)據(jù)寫入成功之后node 5 將結(jié)果報告node 4,并由 node 4 將結(jié)果返回給客戶端,報告數(shù)據(jù)寫入成功。
在這個過程中,接收用戶請求的節(jié)點是不固定的,上述例子中,node 4 發(fā)揮了協(xié)調(diào)節(jié)點和客戶端節(jié)點的作用,將數(shù)據(jù)轉(zhuǎn)發(fā)至對應節(jié)點和接收以及返回用戶請求。
數(shù)據(jù)在由 node4 轉(zhuǎn)發(fā)至 node5的時候,是通過以下公式來計算,指定的文檔具體在那個分片的
shard_num=hash(_routing)%num_primary_shards
其中,_routing 的默認值是文檔的 id。
1.3 寫一致性策略
ES 5.x 之后,一致性策略由 wait_for_active_shards 參數(shù)控制:
即確定客戶端返回數(shù)據(jù)之前必須處于active 的分片分片數(shù)(包括主分片和副本),默認為 wait_for_active_shards = 1,即只需要主分片寫入成功,設(shè)置為 all或任何正整數(shù),最大值為索引中的分片總數(shù) ( number_of_replicas + 1 )。如果當前 active 狀態(tài)的副本沒有達到設(shè)定閾值,寫**作必須等待并且重試,默認等待時間30秒,直到 active 狀態(tài)的副本數(shù)量超過設(shè)定的閾值或者超時返回失敗為止。
執(zhí)行索引**作時,分配給執(zhí)行索引**作的主分片可能不可用。造成這種情況的原因可能是主分片當前正在從**恢復或正在進行重**。默認情況下,索引**作將在主分片上等待最多 1 分鐘,第二才會失敗并返回錯誤。
2、ES 的寫入原理2.1 圖解文檔的寫入原理
2.2 Translog
對索引的修改**作在會 Lucene 執(zhí)行 commit 之后真正持久化到磁盤,這個過程是非常消耗資源的,因此不可能在每次索引**作或刪除**作后執(zhí)行。Lucene 提交的成本太高,無法對每個單獨的更改執(zhí)行,因此每個分片副本還將**作寫入其 事務日志,也就是 translog 。所有索引和刪除**作在被內(nèi)部 Lucene 索引處理之后但在它們被確認之前寫入到 translog。如果發(fā)生崩潰,當分片恢復時,已確認但尚未包含在最后一次 Lucene 提交中的最近**作將從 translog 中恢復。
Elasticsearch Flush 是Lucene 執(zhí)行 commit 并開始寫入新的 translog 的過程。刷新是在后臺自動執(zhí)行的,以確保 translog 不會變得太大,這將導致在恢復期間重放其**作需要相當長的時間。手動執(zhí)行刷新的能力也通過 API 公開,但是一般并不需要。
translog 中的數(shù)據(jù)僅在 translog 被執(zhí)行 fsync 和 commit 時才會持久化到磁盤。如果發(fā)生硬件故障或**作系統(tǒng)崩潰或 JVM 崩潰或分片故障,自上次 translog 提交以來寫入的任何數(shù)據(jù)都將丟失。
默認情況下,index.translog.durability設(shè)置為意味著 Elasticsearch 僅在 translog在主分片和每個副本上 request 成功編輯并提交后,才會向客戶端報告索引、刪除、更新或批量請求的成功。fsync 如果 index.translog.durability 設(shè)置為 async then Elasticsearch fsync并僅提交 translog index.translog.sync_interval,這意味著當節(jié)點恢復時,在崩潰之前執(zhí)行的任何**作都可能丟失。
以下可動態(tài)更新的每個索引設(shè)置控制 translog 的行為:
index.translog.sync_interval無論寫入**作如何,translog 默認每隔 5s 被 fsync 寫入磁盤并 commit 一次,不允許設(shè)置小于 100ms 的提交間隔。index.translog.durability是否 fsync在每次索引、刪除、更新或批量請求后提交事務日志。此設(shè)置接受以下參數(shù):request(默認):fsync并在每次請求后提交。如果發(fā)生硬件故障,所有確認的寫入都已經(jīng)提交到磁盤。async:fsync 并在后臺提交每個 sync_interval`. 如果發(fā)生故障,自上次自動提交以來所有確認的寫入都將被丟棄。index.translog.flush_threshold_sizetranslog 存儲所有尚未安全保存在 Lucene 中的**作(即,不是 Lucene 提交點的一部分)。盡管這些**作可用于讀取,但如果分片停止并必須恢復,則需要重播它們。此設(shè)置控制這些**作的最大總大小,以防止恢復時間過長。一旦達到最大大小,就會發(fā)生刷新,生成一個新的 Lucene 提交點。默認為 512mb.2.3 Refresh2.3.1 概念和原理
內(nèi)存索引緩沖區(qū)(圖 1)中的文檔被寫入新段(圖 2)。新段第一寫入文件系統(tǒng)緩存(這個過程性能消耗很低),第二才刷新到磁盤(這個過程則代價很低)。但是,在文件進入緩存后,它可以像任何其他文件一樣打開和讀取。
Lucene 允許寫入和打開新的段,使它們包含的文檔對搜索可見,而無需執(zhí)行完整的提交。這是一個比提交到磁盤更輕松的過程,并且可以經(jīng)常執(zhí)行而不會降低性能。
在 Elasticsearch 中,這個寫入和打開新段的過程稱為 刷新 。刷新使自上次刷新以來對索引執(zhí)行的所有**作都可用于搜索。
2.3.2 設(shè)置刷新間隔
index.refresh_interval:多久執(zhí)行一次刷新**作,這使得對索引的最近更改對搜索可見。默認為 1s. 可以設(shè)置 -1 為禁用刷新。
并不是所有的情況都需要每秒刷新。比如 Elasticsearch 索引大量的日志文件,此時并不需要太高的寫入實時性, 可以通過設(shè)置 refresh_interval ,增大刷新間隔來降低每個索引的刷新頻率,從而降低因為實時性而帶來的性能開銷。進而提升檢索效率。
POST <index_name>
{
"settings": {
"refresh_interval": "30s"
}
}
1234562.3.3 強制對索引刷新POST <target>/_refresh
GET <target>/_refresh
POST /_refresh
GET /_refresh
12345672.4 Flush
刷新數(shù)據(jù)流或索引是確保當前僅存儲在 Traslog 中的任何數(shù)據(jù)也**存儲在 Lucene 索引中的過程。重新啟動時,Elasticsearch 會將所有未刷新的**作從事務日志重播到 Lucene 索引,以使其恢復到重新啟動前的狀態(tài)。Elasticsearch 會根據(jù)需要自動觸發(fā)刷新,使用啟發(fā)式算法來權(quán)衡未刷新事務日志的大小與執(zhí)行每次刷新的成本。
一旦每個**作被刷新,它就會**存儲在 Lucene 索引中。這可能意味著不需要在事務日志中維護它的額外副本。事務日志由多個文件組成,稱為 generation ,一旦不再需要,Elasticsearch 將刪除任何生成文件,從而釋放磁盤空間。
也可以使用刷新 API 觸發(fā)一個或多個索引的刷新,盡管用戶很少需要直接調(diào)用此 API。如果您在索引某些文檔后調(diào)用刷新 API,則成功響應表明 Elasticsearch 已刷新在調(diào)用刷新 API 之前索引的所有文檔。
2.5 Merge
由于自動刷新流程每秒會創(chuàng)建一個新的段 ,這樣會導致短時間內(nèi)的段數(shù)量暴增。而段數(shù)目太多會帶來較大的麻煩。 每一個段都會消耗文件句柄、內(nèi)存和cpu運行周期。更重要的是,每個搜索請求都必須輪流檢查每個段;所以段越多,搜索也就越慢。
Elasticsearch通過在后臺進行段合并來解決這個問題。小的段被合并到大的段,第二這些大的段再被合并到更大的段。
Elasticsearch 中的一個 shard 是一個 Lucene 索引,一個 Lucene 索引被分解成段。段是存儲索引數(shù)據(jù)的索引中的內(nèi)部存儲元素,并且是不可變的。較小的段會定期合并到較大的段中,并刪除較小的段
合并大的段需要消耗大量的I/O和CPU資源,如果任其發(fā)展會影響搜索性能。Elasticsearch在默認情況下會對合并流程進行資源限制,所以搜索仍然 有足夠的資源很好地執(zhí)行。
3、寫入性能調(diào)優(yōu)3.1 基本原則
寫性能調(diào)優(yōu)是建立在對 Elasticsearch 的寫入原理之上。ES 數(shù)據(jù)寫入具有一定的延時性,這是為了減少頻繁的索引文件產(chǎn)生。默認情況下 ES 每秒生成一個 segment 文件,當達到一定閾值的時候 會執(zhí)行merge,merge 過程發(fā)生在 JVM中,頻繁的生成 Segmen 文件可能會導致頻繁的觸發(fā) FGC,導致 OOM。為了避免避免這種情況,通常采取的手段是降低 segment 文件的生成頻率,手段有兩個,一個是 增加時間閾值,另一個是增大 Buffer的空間閾值,因為緩沖區(qū)寫滿也會生成 Segment 文件。
生產(chǎn)經(jīng)常面臨的寫入可以分為兩種情況:
:一般情況為定期重建索引或批量更新文檔數(shù)據(jù)。
在搜索引擎的業(yè)務場景下,用戶一般并不需要那么高的寫入實時性。比如你在網(wǎng)站發(fā)布一條征婚信息,或者二手交易平臺發(fā)布一個商品信息。其他人并不是馬上能搜索到的,這其實也是正常的處理邏輯。這個延時的過程需要處理很多事情,業(yè)務層面比如:你的信息需要后臺審核。你發(fā)布的內(nèi)容在搜索服務中需要建立索引,而且你的數(shù)據(jù)可能并不會馬上被寫入索引,而是等待要寫入的數(shù)據(jù)達到一定數(shù)量之后,批量寫入。這種**作優(yōu)點類似于我們快遞物流的場景,只有當快遞數(shù)量達到一定量級的時候,比如能裝滿整個車的時候,快遞車才會發(fā)車。因為反正是要跑一趟,裝的越多,平均成本越低。這和我們數(shù)據(jù)寫入到磁盤的過程是非常相似的,我們可以把一條文檔數(shù)據(jù)看做是一個快遞,而快遞車每次發(fā)車就是向磁盤寫入數(shù)據(jù)的一個過程。這個過程不宜太多,太多只會降低性能,就是體現(xiàn)在運輸成本上面。而對于我們數(shù)據(jù)寫入而言就是體現(xiàn)在我們硬件性能損耗上面。
3.2 優(yōu)化手段
以下為常見 數(shù)據(jù)寫入的調(diào)優(yōu)手段,寫入調(diào)優(yōu)均以提升寫入吞吐量和并發(fā)能力為目標,而非提升寫入實時性。
3.2.1 增加 flush 時間間隔
目的是減小數(shù)據(jù)寫入磁盤的頻率,減小磁盤IO頻率。
3.2.2 增加refresh_interval的參數(shù)值
目的是減少segment文件的創(chuàng)建,減少segment的merge次數(shù),merge是發(fā)生在jvm中的,有可能導致full GC,增加refresh會降低搜索的實時性。
ES的 refresh 行為非常昂貴,并且在正在進行的索引活動時經(jīng)常調(diào)用,會降低索引速度,這一點在索引寫入原理中介紹過,了解索引的寫入原理,可以關(guān)注我的博客Elastic開源社區(qū)。
默認情況下,Elasticsearch 每秒定期刷新索引,但僅在最近 30 秒內(nèi)收到一個或多個搜索請求的索引上。
如果沒有搜索流量或搜索流量很少(例如每 5 分鐘不到一個搜索請求)并且想要優(yōu)化索引速度,這是最佳配置。此行為旨在在不執(zhí)行搜索的默認情況下自動優(yōu)化批量索引。建議顯式配置此配置項,如 30秒。
3.2.3 增加Buffer大小
本質(zhì)也是減小refresh的時間間隔,因為導致segment文件創(chuàng)建的原因不僅有時間閾值,還有buffer空間大小,寫滿了也會創(chuàng)建。 默認最小值 48MB< 默認值 JVM 空間的10% < 默認最大無限制
3.2.4 關(guān)閉副本
當需要單次寫入大量數(shù)據(jù)的時候,建議關(guān)閉副本,暫停搜索服務,或選擇在檢索請求量谷值區(qū)間時間段來完成。
第一,是減小讀寫之間的資源搶占,讀寫分離第二,當檢索請求數(shù)量很少的時候,可以減少甚至完全刪除副本分片,關(guān)閉segment的自動創(chuàng)建以達到高效利用內(nèi)存的目的,因為副本的存在會導致主從之間頻繁的進行數(shù)據(jù)同步,大大增加服務器的資源占用。具體可通過則設(shè)置index.number_of_replicas 為0以加快索引速度。沒有副本意味著丟失單個節(jié)點可能會導致數(shù)據(jù)丟失,因此數(shù)據(jù)保存在其他地方很重要,以便在出現(xiàn)問題時可以重試初始加載。初始加載完成后,可以設(shè)置index.number_of_replicas改回其原始值。
3.2.5 禁用swap
大多數(shù)**作系統(tǒng)嘗試將盡可能多的內(nèi)存用于文件系統(tǒng)緩存,并急切地換掉未使用的應用程序內(nèi)存。這可能導致部分 JVM 堆甚至其可執(zhí)行頁面被換出到磁盤。
交換對性能和節(jié)點穩(wěn)定性非常不利,應該不惜一切代價避免。它可能導致垃圾收集持續(xù)幾分鐘而不是幾毫秒,并且可能導致節(jié)點響應緩慢甚至與集群斷開連接。在Elastic分布式系統(tǒng)中,讓**作系統(tǒng)殺**節(jié)點更有效。
3.2.6 使用多個工作線程
發(fā)送批量請求的單個線程不太可能最大化 Elasticsearch 集群的索引容量。為了使用集群的所有資源,應該從多個線程或進程發(fā)送數(shù)據(jù)。除了更好地利用集群的資源外,還有助于降低每個 fsync 的成本。
確保注意 TOO_MANY_REQUESTS (429)響應代碼(EsRejectedExecutionException使用 Java 客戶端),這是 Elasticsearch 告訴我們它無法跟上當前索引速度的方式。發(fā)生這種情況時,應該在重試之前暫停索引,最好使用隨機指數(shù)退避。
與調(diào)整批量請求的大小類似,只有測試才能確定最佳工作線程數(shù)量是多少。這可以通過逐漸增加線程數(shù)量來測試,直到集群上的 I/O 或 CPU 飽和。
3.2.7 避免使用稀疏數(shù)據(jù)3.2.8 max_result_window參數(shù)
max_result_window是分頁返回的最大數(shù)值,默認值為10000。max_result_window本身是對JVM的一種保護機制,通過設(shè)定一個合理的閾值,避免初學者分頁查詢時由于單頁數(shù)據(jù)過大而導致OOM。
在很多業(yè)務場景中經(jīng)常需要查詢10000條以后的數(shù)據(jù),當遇到不能查詢10000條以后的數(shù)據(jù)的問題之后,網(wǎng)上的很多**會告訴你可以通過放開這個參數(shù)的限制,將其配置為100萬,甚至1000萬就行。但是如果僅僅放開這個參數(shù)就行,那么這個參數(shù)限制的意義有何在呢?如果你不知道這個參數(shù)的意義,很可能導致的后果就是頻繁的發(fā)生OOM而且很難找到原因,設(shè)置一個合理的大小是需要通過你的各項指標參數(shù)來衡量確定的,比如你用戶量、數(shù)據(jù)量、物理內(nèi)存的大小、分片的數(shù)量等等。通過**數(shù)據(jù)和分析各項指標從而確定一個最佳值,并非越大越好
4、查詢調(diào)優(yōu)4.1 讀寫性能不可兼得
第一要明確一點:魚和熊掌不可兼得。讀寫性能調(diào)優(yōu)在很多場景下是只能二選一的。犧牲 A 換 B 的行為非常常見。索引本質(zhì)上也是通過空間換取時間。寫生寫入實時性就是為了提高檢索的性能。
當你在二手平臺或者某垂直信息網(wǎng)站發(fā)布信息之后,是允許有信息寫入的延時性的。但是檢索不行,甚至 1 秒的等待時間對用戶來說都是無法接受的。滿足用戶的要求甚至必須做到10 ms以內(nèi)。
4.2 優(yōu)化手段4.2.1 避免單次召回大量數(shù)據(jù)
搜索引擎最擅長的事情是從海量數(shù)據(jù)中查詢少量相關(guān)文檔,而非單次檢索大量文檔。非常不建議動輒查詢上萬數(shù)據(jù)。如果有這樣的需求,建議使用滾動查詢
4.2.2 避免單個文檔過大
鑒于默認http.max_content_length設(shè)置為 100MB,Elasticsearch 將拒絕索引任何大于該值的文檔。您可能決定增加該特定設(shè)置,但 Lucene 仍然有大約 2GB 的限制。
即使不考慮硬性限制,大型文檔通常也不實用。大型文檔對網(wǎng)絡、內(nèi)存使用和磁盤造成了更大的壓力,即使對于不請求的搜索請求也是如此,_source因為 Elasticsearch_id在所有情況下都需要獲取文檔的文件系統(tǒng)緩存有效。對該文檔進行索引可能會占用文檔原始大小的倍數(shù)的內(nèi)存量。Proximity Search(例如短語查詢)和高亮查詢也變得更加昂貴,因為它們的成本直接取決于原始文檔的大小。
有時重新考慮信息單元應該是什么是有用的。例如,您想讓書籍可搜索的事實并不一定意味著文檔應該包含整本書。使用章節(jié)甚至段落作為文檔可能是一個更好的主意,第二在這些文檔中擁有一個屬性來標識它們屬于哪本書。這不僅避免了大文檔的問題,還使搜索體驗更好。例如,如果用戶搜索兩個單詞fooand bar,則不同章節(jié)之間的匹配可能很差,而同一段落中的匹配可能很好。
4.2.3 單次查詢10條文檔 好于 10次查詢每次一條
批量請求將產(chǎn)生比單文檔索引請求更好的性能。但是每次查詢多少文檔最佳,不同的集群最佳值可能不同,為了獲得批量請求的最佳閾值,建議在具有單個分片的單個節(jié)點上運行基準測試。第一嘗試一次索引 100 個文檔,第二是 200 個,第二是 400 個等。在每次基準測試運行中,批量請求中的文檔數(shù)量翻倍。當索引速度開始趨于平穩(wěn)時,就可以獲得已達到數(shù)據(jù)批量請求的最佳大小。在相同性能的情況下,當大量請求同時發(fā)送時,太大的批量請求可能會使集群承受內(nèi)存壓力,因此建議避免每個請求超過幾十兆字節(jié)。
4.2.4 數(shù)據(jù)建模
很多人會忽略對 Elasticsearch 數(shù)據(jù)建模的重要性。
nested屬于object類型的一種,是Elasticsearch中用于復雜類型對象數(shù)組的索引**作。Elasticsearch沒有內(nèi)部對象的概念,因此,ES在存儲復雜類型的時候會把對象的復雜層次結(jié)果扁平化為一個鍵值對列表。
特別是,應避免連接。Nested 可以使查詢慢幾倍,Join 會使查詢慢數(shù)百倍。兩種類型的使用場景應該是:Nested針對字段值為非基本數(shù)據(jù)類型的時候,而Join則用于 當子文檔數(shù)量級非常大的時候。
關(guān)于數(shù)據(jù)建模,在我的博客中有詳細的講解,此處不再贅述
4.2.5 給系統(tǒng)留足夠的內(nèi)存
Lucene的數(shù)據(jù)的fsync是發(fā)生在OS cache的,要給OS cache預留足夠的內(nèi)從大小,詳見JVM調(diào)優(yōu)。
4.2.6 預索引
利用查詢中的模式來優(yōu)化數(shù)據(jù)的索引方式。例如,如果所有文檔都有一個price字段,并且大多數(shù)查詢 range 在固定的范圍列表上運行聚合,可以通過將范圍預先索引到索引中并使用聚合來加快聚合速度。
4.2.7 使用 filter 代替 query
query和filter的主要區(qū)別在: filter是結(jié)果導向的而query是過程導向。query傾向于“當前文檔和查詢的語句的相關(guān)度”而filter傾向于“當前文檔和查詢的條件是不是相符”。即在查詢過程中,query是要對查詢的每個結(jié)果計算相關(guān)性得分的,而filter不會。另外filter有相應的緩存機制,可以提高查詢效率。
4.2.8 避免深度分頁
避免單頁數(shù)據(jù)過大,可以參考百度或者淘寶的做法。es提供兩種解決方案 scroll search 和 search after。關(guān)于深度分頁的詳細原理,推薦閱讀:詳解Elasticsearch深度分頁問題
4.2.9 使用 Keyword 類型
并非所有數(shù)值數(shù)據(jù)都應映射為數(shù)值字段數(shù)據(jù)類型。Elasticsearch為 查詢優(yōu)化數(shù)字字段,例如integeror long。如果不需要范圍查找,對于 term查詢而言,keyword 比 integer 性能更好。
4.2.10 避免使用腳本
Scripting是Elasticsearch支持的一種專門用于復雜場景下支持自定義編程的強大的腳本功能。相對于 DSL 而言,腳本的性能更差,DSL能解決 80% 以上的查詢需求,如非必須,盡量避免使用 Script
拓展知識:
寫入緩存策略
題中的,打開策略后沒有“啟用磁盤上的寫入緩存”這項。分析可能性,如果不是有問題的盜版**作系統(tǒng),則可能這塊硬盤本身沒有那塊“SRAM存儲芯片”,硬盤屬性窗中也就不會出現(xiàn)該選項了。當然這塊芯片有問題,系統(tǒng)也是會這樣處理的。
根本不用這么麻煩,下載個HD Tunepre 工具軟件查看一下硬盤是否有該“緩存”,就有思路了。老硬盤沒有緩存也正常。
寫入緩存策略
你的不支持 只能是這樣拉
原創(chuàng)文章,作者:九賢生活小編,如若轉(zhuǎn)載,請注明出處:http:///40971.html