1. Lucene分段
當Elasticsearch接收到應用發送的文檔時,他會將其索引到內存中稱為分段(segments)的倒排索引,這些分段不能被改變,只能被刪除,這是為了系統更好的緩存分段,較小的分段會定期合並為較大的分段,合並后的分段會被標記刪除。然后這些分段會不時的寫入磁盤。
Elasticsearch對分段的處理有以下幾種方式:
- 刷新(refresh)和沖刷(flush)的頻率:
刷新
會讓 Elasticsearch重新打開索引,讓新建的文檔可用於搜索。沖刷
是將索引的數據從內存寫入磁盤。從性能的角度來看,刷新和沖刷操作都是非常消耗資源的。 - 合並的策略:Lucene(Elasticsearch也是如此)將數據存儲在不可變的一組文件中,也就是分段中。隨着索引的數據越來越多,系統會創建更多的分段。由於在過多的分段中搜索是很慢的,因此在后台小分段會被合並為較大的分段,保持分段的數量可控。不過,合並也是十分消耗性能的,對於IO子系統尤其如此。你可以調節合並的策略,來確定合並多久發生一次,而且分段應該合並到多大。
- 存儲和存儲限流:Elasticsearch調節每秒寫入的字節數,來限制合並對於IO系統的影響。
1.1 刷新和沖刷
Elasticsearch被稱為近實時(或准實時)索引系統,是因為默認每秒執行一次刷新操作,將未被索引的數據(新建的索引或文檔)刷新到內存中。其不足是每次刷新都會影響性能:某些緩存將失效,拖慢請求,重新打開索引的過程也需要一些處理能力,拖慢了索引的建立。因此可根據項目具體情況設置刷新頻率。
刷新
的過程和內存分段
寫入磁盤的過程是相互獨立的。實際上,數據首先索引到內存中,經過一次刷新后,Elasticsearch就會搜索相應的內存分段。將內存中的分段提交到磁盤上的 Lucene索引的過程,被稱為沖刷
(fush)
,無論分段是否能被搜到,沖刷都會發生。
為了確保某個節點宕機或分片移動位置的時候,內存數據不會丟失,Elasticsearch將使用事物日志來跟蹤尚未沖刷的索引操作。除了將內存分段提交到磁盤,沖刷還會清理事物日志。
觸發沖刷的條件如下:
- 內存緩沖區已滿
- 自上一次沖刷后超過了一定的時間
- 事務日志達到了一定的閾值
當沖刷發生的時候,它會在磁盤上創建一個或多個分段。執行一個查詢的時候,Elasticsearch
(通過 Lucene)查看所有的分段,然后將結果合並到一個整體的分片中。搜索的時候每個分片上的結果將被聚集為一個完整的結果集合,然后返回給應用程序。
關於分段,這里需要記住的關鍵點是你需要搜索的分段越多,搜索的速度就越慢。為了防止分段的數量失去控制,Elasticsearch(也是通過 Lucene)在后台將多組較小的分段合並為較大的分段。
1.2 段的合並及合並策略
由於分段是不變的,它們很容易被緩存,使得搜索更快。此外,修改數據集時,如添加一篇文檔,無須重建現有分段中的數據索引。這使得新文檔的索引也是很快的。
但是更新文檔不能修改實際的文檔,只是索引一篇新的文檔。如此處理還需要刪除原有的文檔。而且刪除也不能從分段中移除文檔(這需要重建倒排索引),只是在單獨的.del文件
中將其標記為“已被刪除”。文檔只會在分段合並的時候真正地被移除。
因此合並分段的兩個目的:第一個是將分段的總數量保持在受控的范圍內(這用來保障查詢的性能)。第二個是真正地刪除文檔。
按照已定義的合並策略,分段是在后台進行的。默認的合並策略是分層配置,合並發生在索引、更新或者刪除文檔的時候,如圖10-4所示,該策略將分段划分為多個層次,如果你的分段多於某一層中所設置的最大分段數,該層的合並就會被觸發。
優化索引:有了刷新和沖刷,你可以手動觸發一次合並。一次強制性的合並也被稱為優化(optimize),之所以起這樣的名字是因為通常是在一個今后不會更改的索引上運行這個操作,將其優化到一定
(較低)數量的分段,使得更快的搜索成為可能。