Elasticsearch 數據寫入原理

1、elasticsearch 如何使文檔可以被搜索

爲了支持全文檢索而採用倒排索引,倒排索引包含一個有序列表,列表包含所有文檔出現過的詞項 ,對於每一個詞項,包含了它所有曾出現過文檔的列表。
早期的倒排索引,會在文檔變化時,重建新的索引,直到完成後替換掉舊的索引,這樣新的變化就可以被搜索到。
倒排索引具有不變性,這使得索引一旦被讀入文件系統緩存,便會留在那裏,只要有足夠的空間,就可以使大部分請求直接命中緩存,很大地提升了性能,缺點是,如果有新的文檔需要被搜索,只能重建整個索引。

2、如何使用更好的方式實現倒排索引的更新

上面說了,由於索引的不變性,更新索引的方式是重建整個索引,這種方式對於數據量和更新頻率的情況是有很大限制的,所以elasticsearch通過增加新的補充索引來反映新近的修改,而不是直接重寫整個倒排索引。最終通過輪詢每一個倒排索引並對結果進行合併才創建新的索引。

  • 按段搜索
    elasticsearch 基於lucene 引入了 按段搜索的概念,每一個段,都是一個倒排索引,而一個Lucene索引,除了包含多個段之外,還包含commit point、.liv文件。
    其中,commit point記錄了每一次的創建新段,當一個段存在文檔被刪除,會維護該信息在 .liv 文件裏面。

逐段搜索會以如下流程進行工作:

  1. 新增的文檔寫入內存緩存
  2. 每隔一段時間,創建一個新段,將文檔從內存緩存中被提交到新段
  3. 新段寫入到磁盤(文件系統緩存)
  4. 新的commit point 也 寫入到磁盤(文件系統緩存)
  5. 磁盤 fsync ,從文件系統緩存中價格寫入操作同步到物理磁盤
  6. 這個新的段被開啓, 使得段內文檔對搜索可見
  7. 清空內存緩存,繼續接受新的文檔

3、如何實現近實時搜索

上面的寫入到可檢索過程,主要瓶頸在磁盤fync,大量文檔需要寫入磁盤可能造成很明顯的延遲,而且每次的索引一個文檔都要做磁盤fsync會造成性能問題。所以elasticsearch更輕量的方式來使一個文檔可被搜索——將fsync從【寫入到可檢索】的步驟中移除——在新段寫入文件系統緩存之後就可檢索。
在第1部分中描述了倒排索引在文件系統緩存中被請求,所以在新段寫入文件系統緩存之後就可以被打開和讀取了。寫入文件系統緩存和打開新段被稱爲refresh,默認情況下每秒進行一次refresh,也可以更改該項設置,或者手動執行。
有了refresh之後,索引文檔的步驟更改爲:

  1. 新增的文檔寫入內存緩存
  2. 每隔一段時間,創建一個新段,refresh,此時新段可被檢索
  3. 通過fsync刷新磁盤(flush) ,從文件系統緩存中將所有寫入操作同步到物理磁盤
  4. 清空內存緩存,繼續接受新的文檔

4、數據持久化

上面說到新段先寫入文件系統緩存,再fsync到磁盤,在這個過程中,如果斷電,則無法將未來得及同步的數據持久化到磁盤,所以elasticsearch 增加了一個 translog,也叫事務日誌,記錄了每一次的操作。

  1. 在文檔寫入內存緩存的同時,寫入到translog中
  2. 執行refresh時,會清空內存緩存,且沒有fsync到磁盤時,translog仍然保留
  3. 每隔一段時間或者translog文件太大,索引被刷新,所有在內存緩衝區的文檔都被寫入一個新的段,清空內存緩存,一個提交點被寫入硬盤,新的traslog文件被創建,舊的被刪除

而在執行refresh後,fsync之前,如果重啓elasticsearch,它會從磁盤中使用最後一個提交點去恢復已知的段,並且會重放 translog 中所有在最後一次提交後發生的變更操作。

5、段合併

由於在自動刷新流程每秒會創建一個新的段,段時間內就會積累大量的段,每一個段都會消耗文件句柄、內存和cpu運行週期,而且在檢索時需要遍歷所有段來查找文檔,這樣無疑是一個巨大的性能瓶頸。elasticsearch通過在後臺進行段合併來解決這個問題,小的段被合併到大的段,然後這些大的段再被合併到更大的段,段合併的時候會將那些舊的已刪除文檔從文件系統中清除。
段合並不會中斷檢索和索引的過程,在索引的時候,創建新段,段合併就會自動執行,合併的段將繼續執行之後的步驟。
手動進行強制段合併可使用optimize api,它會將一個分片強制合併到 max_num_segments 個段,但該操作可能會無限制的使用資源,造成集羣內短時間內無法響應。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章