圖解 Elasticsearch 寫入流程

整體上看,Client 向 ES 發送寫請求,es 接收數據,寫入磁盤文件,返回響應給 Client 寫入成功,這樣就完成了。

然後拉近看一下,看看內部都做了什麼工作。

  1. ES 整體結構

ES 集羣裏面有多個 Server 節點,一個 ES Index 有多個 shard 分片,每個 shard 有多個副本。

其中有一個 primary 主副本,負責寫入,其他副本爲 replica,不能寫,只能同步 primary 的數據,但可以處理讀請求。

ES 收到寫請求後,會將請求路由到目標 shard 的 primary 副本。

每一個 shard 就是一個 Lucene Index,包含多個 segment 文件,和一個 commit point 文件。

segment 文件存儲的就是一個個的 Document,commit point 記錄着都有哪些 segment 文件。

瞭解了 ES 的整體結構,可知 primary shard 收到寫請求,就是把 Document 數據寫入 segment。

  1. 直接寫 Segment 效率低怎麼辦?

如果每次寫操作都是直接落盤的話,I/O 效率會比較低。

所以,ES 使用了一個內存緩衝區 Buffer,先把要寫入的數據放進 buffer。

內存性能好,但不安全,會丟數據,所以 es 使用了一個日誌文件 Translog。就像 MySQL 的 Binlog,記錄着每一條操作日誌,如果 ES 出現故障,重啓之後可以從 Translog 中恢復數據。

因爲日誌文件只是單純的做內容追加,沒有其他邏輯操作,所以寫入速度很快。

並不是每條操作直接寫入磁盤,也是有一個內存緩衝,每隔 5 秒寫入磁盤。所以,極端情況下會有 5 秒數據的丟失,如果要嚴格保證數據安全,可以調整這個時間。

這樣,數據來到 primary shard 之後,先是進入 buffer,並把操作記錄寫入 Translog。

  1. Buffer 中數據怎麼寫入 Segment 文件?

ES 每隔一秒執行一次 refresh 操作,會創建一個 Segment 文件,將 buffer 中的數據寫入這個 segment,並清空 buffer。

進入 segment 的數據就進入了 Lucene,建立好了倒排索引,可以被搜索到。

  1. 如何進一步提升寫 Segment 效率?

需要注意,ES 雖然把數據寫入了 segment 文件,但實際上還沒有真正落盤,因爲操作系統的文件系統也是有緩存的,這是操作系統層面的性能優化,由操作系統決定物理落盤時間,除非程序寫文件時使用同步寫 fsync。

ES 爲了性能自然沒有使用 fsync,因爲有 Translog 記錄了所有操作步驟。

雖然可能還沒實際寫入 segment 物理文件,但只要進入了操作系統的文件系統,就可以被搜索了,這一點不用擔心。

  1. Translog 日誌文件越來越大怎麼辦?

隨着寫入數據的增加,Translog 也越來越大,需要清理。

觸發清理動作需要 2 個條件:

  1. 大小觸發設定的閾值

  2. 30 分鐘

任意條件滿足即觸發一次 commit 提交操作。

操作流程:

  1. 執行 refresh 操作。

  2. 把這次提交動作之前所有沒有落盤的 segment 強制刷盤,確保寫入物理文件。

  3. 創建一個提交點,記錄這次提交對應的所有 segment,寫入 commit point 文件。

  4. 清空 Translog,因爲 Segment 都已經踏實落地了,之前的 Translog 就不需要了。

這個提交流程,稱爲 flush

  1. Segment 太多怎麼辦?

通過上面的流程,可以發現,segment 文件太多了,一秒就產生一個,這會嚴重影響搜索性能。

es 有一個後臺程序,用於 merge 合併這些 segment 文件,把小 segment 整合到一個大的 segment 中,並修改 commit point 的 segment 記錄。

merge 過程還會清理被刪除的數據。

es 接收到刪數據請求時,不會真的到 segment 中把數據刪了,而是把要刪除的數據寫到 '.del' 文件中,在讀操作時,會根據這個文件進行過濾。

merge 合併時才真正刪除,合併後的 segment 中就沒有已經刪除的數據了。

  1. 小結

寫操作時,ES 把寫請求路由到目標 Shard 所在的 Server 節點,Doc 先被放入 Buffer,並記錄此請求的操作日誌,寫入 Translog。

每隔一秒,執行 Refresh 操作,將 Buffer 中數據寫入 Segment 文件,並清空 Buffer。

Refresh 實際寫入的 Segment 文件緩存,會在 Flush 操作中刷盤到物理文件。

當 Translog 過大,或者每隔 30 分鐘,執行一次 Flush 操作。

先執行一次 Refresh,然後將所有 Segment 文件緩存刷盤到物理文件,並創建提交點,記錄此次操作設計的 Segment,寫入 Commit Point 文件,最後清空 Translog。

ES 的 Merge 程序負責合併小 Segment,並清除被刪除的 Document。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/ZgOsGXo4ApQiOXoRJv_jfw