Elasticsearch核心技術與實戰學習筆記 40 | 分片及其生命週期

一 序

    本文屬於極客時間Elasticsearch核心技術與實戰學習筆記系列。

二 分片的內部原理

什麼是 ES 的分片

  • ES 中最小的工作單元 / 是一個 Lucence 的 Index

一些問題:

  • 爲什麼 ES 的搜索時近實時的(1 秒後被搜到)
  • ES 如何保證在斷電時數據也不會丟失
  • 爲甚刪除文檔,並不會立刻釋放空間

2.1 倒排索引的不可變性

 倒排索引採用 Immutable Design, 一旦生成,不可更改
不可變性,帶來了的好處如下:

  • 不許考慮併發寫文件的問題,避免了鎖機制帶來的性能問題
  • 一旦讀入內核的文件系統緩存,便留在那裏,只要文件系統存有足夠的空間,大部分請求就會直接請求內存,不會命中磁盤,提高了很大的性能
  • 緩存容易生成和維護 / 數據可以被壓縮

不可變更性,帶來了的挑戰:如果需要讓一個新的文檔可以被搜索,需要重建整個索引

2.2 Lucence Index

     分片是Elasticsearch中的最小工作單元,本質上是一個Lucene Index。在Lucene中,單個倒排索引文件被稱爲Segment,Segment是自包含且不可變更的,多個Segment彙總在一起稱爲Lucene Index

     當有新文檔生成時,會生成新的Segment,查詢時會同時查詢所有Segment,並且對結果彙總,Lucene中有一個文件用來記錄所有Segments信息,叫做Commit Point,刪除的文檔信息,保存在.del文件中。搜索的時候,會對刪除的文檔做過濾。
     

 2.3 Refresh

  •  將 Index buffer 寫入 Segment 的過程叫做 Refresh。Refresh 不執行 fsync 操作
  • Refresh 頻率:默認 1 秒發生一次,可通過 index.refresj_interval 配置。Refresh 後,數據就可以被搜索到了。這也就是爲什麼 ES 被稱爲近實時搜索
  • 如果系統有大量的數據寫入,那就會產生很多的 Segment
  • Index Buffer 被佔滿時,會觸發 Refresh, 默認值是 JVM 的 10%

2.4 什麼是Transaction Log

  • Segment 寫入磁盤的過程相對耗時,藉助文件系統緩存,Refresh 時,先將 Segment 寫入緩存以開放查詢
  • 爲了保證數據不會丟失。所有在 Index 文檔時,同時寫 Transaction Log,高版本開始,ra 默認落盤。每個分片都有一個 Transaction Log
  • 當 ES Refresh 時,Index Buffer 被清空,Transaction Log 不會清空

當ES產生斷電的時候,因爲Transaction Log都做了落盤的處理,所以系統重啓的時候,會先從Transaction Log 進行recover。不會丟失。

2.5 什麼是Flush

 ES Flush & Lucene Commit
調用 Refresh ,Index Buffer 清空並且 Refresh
調用 fsync, 將緩存中的 Segments 寫入磁盤
清空(刪除)Transaction Log
默認 30 分鐘調用一次
Transaction Log 滿(默認 512M)

2.6 Merge

  • Segment 很多,需要定期被合併
    • 減少 Segment/ 刪除已經刪除的文檔(真正的刪除)
  • ES 和 Lucene 會自動進行 Merge 操作(強制merge)
    • POST my_index/_forcemerge

***********************

有優秀的小夥伴Geek_817ea4查了文檔,做了總結,這裏引用下

1)客戶端發起數據寫入請求,對你寫的這條數據根據_routing規則選擇發給哪個Shard。
確認Index Request中是否設置了使用哪個Filed的值作爲路由參數,
如果沒有設置,則使用Mapping中的配置,
如果mapping中也沒有配置,則使用_id作爲路由參數,然後通過_routing的Hash值選擇出Shard,最後從集羣的Meta中找出出該Shard的Primary節點。
2)寫入請求到達Shard後,先把數據寫入到內存(buffer)中,同時會寫入一條日誌到translog日誌文件中去。
當寫入請求到shard後,首先是寫Lucene,其實就是創建索引。
索引創建好後並不是馬上生成segment,這個時候索引數據還在緩存中,這裏的緩存是lucene的緩存,並非Elasticsearch緩存,lucene緩存中的數據是不可被查詢的。
3)執行refresh操作:從內存buffer中將數據寫入os cache(操作系統的內存),產生一個segment file文件,buffer清空。
寫入os cache的同時,建立倒排索引,這時數據就可以供客戶端進行訪問了。
默認是每隔1秒refresh一次的,所以es是準實時的,因爲寫入的數據1秒之後才能被看到。
buffer內存佔滿的時候也會執行refresh操作,buffer默認值是JVM內存的10%。
通過es的restful api或者java api,手動執行一次refresh操作,就是手動將buffer中的數據刷入os cache中,讓數據立馬就可以被搜索到。
若要優化索引速度, 而不注重實時性, 可以降低刷新頻率。
4)translog會每隔5秒或者在一個變更請求完成之後,將translog從緩存刷入磁盤。
translog是存儲在os cache中,每個分片有一個,如果節點宕機會有5秒數據丟失,但是性能比較好,最多丟5秒的數據。。
可以將translog設置成每次寫操作必須是直接fsync到磁盤,但是性能會差很多。
可以通過配置增加transLog刷磁盤的頻率來增加數據可靠性,最小可配置100ms,但不建議這麼做,因爲這會對性能有非常大的影響。
5)每30分鐘或者當tanslog的大小達到512M時候,就會執行commit操作(flush操作),將os cache中所有的數據全以segment file的形式,持久到磁盤上去。
第一步,就是將buffer中現有數據refresh到os cache中去。
清空buffer 然後強行將os cache中所有的數據全都一個一個的通過segmentfile的形式,持久到磁盤上去。
將commit point這個文件更新到磁盤中,每個Shard都有一個提交點(commit point), 其中保存了當前Shard成功寫入磁盤的所有segment。
把translog文件刪掉清空,再開一個空的translog文件。
flush參數設置:
index.translog.flush_threshold_period:
index.translog.flush_threshold_size:
#控制每收到多少條數據後flush一次
index.translog.flush_threshold_ops:
6)Segment的merge操作:
隨着時間,磁盤上的segment越來越多,需要定期進行合併。
Es和Lucene 會自動進行merge操作,合併segment和刪除已經刪除的文檔。
我們可以手動進行merge:POST index/_forcemerge。一般不需要,這是一個比較消耗資源的操作。

 merge一般不需要人爲參與,es自動會做。索引從hot遷移到warm,可以人爲對索引做一次force merge

這一屆真的知識點很多。

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