整體流程:
- 數據寫入buffer緩沖和translog日志文件中。
當你寫一條數據document的時候,一方面寫入到mem buffer緩沖中,一方面同時寫入到translog日志文件中。 - buffer滿了或者每隔1秒(可配),refresh將mem buffer中的數據生成index segment文件並寫入os cache,此時index segment可被打開以供search查詢讀取,這樣文檔就可以被搜索到了(注意,此時文檔還沒有寫到磁盤上);然后清空mem buffer供后續使用。可見,refresh實現的是文檔從內存移到文件系統緩存的過程。
- 重復上兩個步驟,新的segment不斷添加到os cache,mem buffer不斷被清空,而translog的數據不斷增加,隨着時間的推移,translog文件會越來越大。
- 當translog長度達到一定程度的時候,會觸發flush操作,否則默認每隔30分鍾也會定時flush,其主要過程:
4.1. 執行refresh操作將mem buffer中的數據寫入到新的segment並寫入os cache,然后打開本segment以供search使用,最后再次清空mem buffer。
4.2. 一個commit point被寫入磁盤,這個commit point中標明所有的index segment。
4.3. filesystem cache(os cache)中緩存的所有的index segment文件被fsync強制刷到磁盤os disk,當index segment被fsync強制刷到磁盤上以后,就會被打開,供查詢使用。
4.4. translog被清空和刪除,創建一個新的translog。
refresh
最原始的ES版本里,必須等待fsync將segment刷入磁盤,才能將segment打開供search使用,這樣的話,從一個document寫入到它可以被搜索,可能會超過一分鍾,主要瓶頸是在fsync實際發生磁盤IO寫數據進磁盤,是很耗時的,這就不是近實時的搜索了。為此,引入refresh操作的目的是提高ES的實時性,使添加文檔盡可能快的被搜索到,同時又避免頻繁fsync帶來性能開銷,依靠的原理就是文件系統緩存OS cache里緩存的文件可以被打開(open/reopen)和讀取,而這個os cache實際是一塊內存區域,而非磁盤,所以操作是很快的。
寫入流程改進:
1)數據寫入到內存buffer隊列中
2)每隔一定時間,buffer中的數據被寫入segment文件,然后先寫入os cache
3)只要segment數據寫入os cache,那就直接打開segment供search使用,而不必調用fsync將segment刷新到磁盤
將緩存數據生成segment后刷入os cache,並被打開供搜索的過程就叫做refresh,默認每隔1秒。也就是說,每隔1秒就會將buffer中的數據寫入一個新的index segment file,先寫入os cache中。所以,es是近實時的,輸入寫入到os cache中可以被搜索,默認是1秒,所以從數據插入到被搜索到,最長是1秒(可配)。
flush操作與translog
但是,需要注意, index segment刷入到os cache后就可以打開供查詢,這個操作是有潛在風險的,因為os cache中的數據有可能在意外的故障中丟失,而此時數據必備並未刷入到os disk,此時數據丟失將是不可逆的,這個時候就需要一種機制,可以將對es的操作記錄下來,來確保當出現故障的時候,已經落地到磁盤的數據不會丟失,並在重啟的時候可以從操作記錄中將數據恢復過來。elasticsearch提供了translog來記錄這些操作,結合os cached segments數據定時落盤來實現數據可靠性保證(flush)。
當向elasticsearch發送創建document文檔添加請求的時候,document數據會先進入到buffer,與此同時會將操作記錄在translog之中,當發生refresh時(數據從index buffer中進入filesystem cache的過程)translog中的操作記錄並不會被清除,而當數據從os cache中被寫入磁盤之后才會將translog中清空。這個將os cache的索引文件(segment file)持久化到磁盤的過程就是flush,flush之后,這段translog的使命就完成了,因為segment已經寫入磁盤,就算故障也可以從磁盤的segment文件中恢復。flush的時機可能是1.定時flush;2.translog大小達到閾值;3.一些重要操作;4.指令觸發。
translog記錄的是已經在內存生成(segments)並存儲到os cache但是還沒寫到磁盤的那些索引操作(注意,有一種解釋說,添加到buffer中但是沒有被存入segment中的數據沒有被記錄到translog中,這依賴於寫translog的時機,不同版本可能有變化,不影響理解),此時這些新寫入的數據可以被搜索到,但是當節點掛掉后這些未來得及落入磁盤的數據就會丟失,可以通過trangslog恢復。
當然translog本身也是磁盤文件,頻繁的寫入磁盤會帶來巨大的IO開銷,因此對translog的追加寫入操作的同樣操作的是os cache,因此也需要定時落盤(fsync)。translog落盤的時間間隔直接決定了ES的可靠性,因為宕機可能導致這個時間間隔內所有的ES操作既沒有生成segment磁盤文件,又沒有記錄到Translog磁盤文件中,導致這期間的所有操作都丟失且無法恢復。
translog的fsync是ES在后台自動執行的,默認是每5秒鍾主動進行一次translog fsync,或者當translog文件大小大於512MB主動進行一次fsync,對應的配置是index.translog.flush_threshold_period 和 index.translog.flush_threshold_size。還需指出的是, 從ES2.0開始,每次index、bulk、delete、update完成的時候也會觸發translog flush,當flush到磁盤成功后才給請求端返回 200 OK。這個改變提高了數據安全性,但是會對寫入的性能造成不小的影響,因此在可靠性要求不十分嚴格且寫入效率優先的情況下,可以在 index template 里設置如下參數:"index.translog.durability":"async",這相當於關閉了index、bulk等操作的同步flush translog操作,僅使用默認的定時刷新、文件大小閾值刷新的機制,同時可以調高 "index.translog.sync_interval":30s (默認是5s)和index.translog.flush_threshold_size配置選項。
總結一下translog的功能:
- 保證在filesystem cache中的數據不會因為elasticsearch重啟或是發生意外故障的時候丟失。
- 當系統重啟時會從translog中恢復之前記錄的操作。
- 當對elasticsearch進行CRUD操作的時候,會先到translog之中進行查找,因為tranlog之中保存的是最新的數據。
- translog的清除時間時進行flush操作之后(將數據從filesystem cache刷入disk之中)。
總結一下flush操作的時間點:
- es的各個shard會每個30分鍾進行一次flush操作。
- 當translog的數據達到某個上限的時候會進行一次flush操作。
有關於translog和flush的一些配置項:
- index.translog.flush_threshold_ops:當發生多少次操作時進行一次flush。默認是 unlimited。
- index.translog.flush_threshold_size:當translog的大小達到此值時會進行一次flush操作。默認是512mb。
- index.translog.flush_threshold_period:在指定的時間間隔內如果沒有進行flush操作,會進行一次強制flush操作。默認是30m。
- index.translog.interval:多少時間間隔內會檢查一次translog,來進行一次flush操作。es會隨機的在這個值到這個值的2倍大小之間進行一次操作,默認是5s。