ELK系列(十五)、Elasticsearch核心原理一篇全搞定

目錄

Lucene

介紹

核心術語

如何理解倒排索引?

檢索方式

分段存儲

段合併策略

Elasticsearch

核心概念

節點類型 

集羣狀態

3C和腦裂

1.共識性(Consensus)

2.併發(Concurrency)

3.一致性(Consistency)

腦裂

事務日誌TransLog

路由Route


答應我,看完這篇文章,別再說你不會ES了好嗎!

本文會從ES底層Lucene開始,到ES 讀寫原理分別介紹,希望對大家有幫助,謝謝。

ELK系列(一)、安裝ElasticSearch+Logstash+Kibana+Filebeat-v7.7.0

ELK系列(二)、在Kibana中使用RESTful操作ES庫

ELK系列(三)、安裝Logstash插件及打包離線安裝包

ELK系列(四)、Logstash讀取nginx日誌寫入ES中

ELK系列(五)、Logstash修改@timestamp時間爲日誌的產生時間

ELK系列(六)、修改Nginx日誌爲Json格式並使用Logstash導入至ES

ELK系列(七)、Filebeat+Logstash採集多個日誌文件並寫入不同的ES索引中

ELK系列(八)、使用Filebeat+Redis+Logstash收集日誌數據

ELK系列(九)、配置ES和Kibana的用戶密碼

ELK系列(十)、ES中文分詞器IK插件安裝和配置遠程詞庫熱加載

ELK系列(十一)、ElasticSearch7.7.0插件es-head安裝及使用

ELK系列(十二)、使用SQL查詢ElasticSearch7.7.0

ELK系列(十三)、在Hive中操作ES的索引數據,創建/查詢/更新/插入

ELK系列(十四)、在Python中操作ES,創建/查詢/插入/更新/刪除


Lucene

介紹

Lucene是一種高性能、可伸縮的信息搜索(IR)庫,在2000年開源,最初由鼎鼎大名的Doug Cutting開發,是基於Java實現的高性能的開源項目。Lucene採用了基於倒排表的設計原理,可以非常高效地實現文本查找,在底層採用了分段的存儲模式,使它在讀寫時幾乎完全避免了鎖的出現,大大提升了讀寫性能。我們所熟知的Elasticsearch,Solr都是基於Lucene工具包進行開發的全文搜索引擎,因此理解Lucene也可以幫助我們更好的理解Elasticsearch原理。

核心術語

Lucene爲什麼可以實現全文檢索主要是因爲它實現了倒排索引的查詢結構,下面是關於Lucene的核心術語:

  • 詞條(Term):索引裏面最小的存儲和查詢單元,對於英文來說是一個單詞,對於中文來說一般指分詞後的一個詞。
  • 詞典(Term Dictionary):或字典,是詞條Term的集合。搜索引擎的通常索引單位是單詞,單詞詞典是由文檔集合中出現過的所有單詞構成的字符串集合,單詞詞典內每條索引項記載單詞本身的一些信息以及指向“倒排列表”的指針。
  • 倒排表(Post list):一個文檔通常由多個詞組成,倒排表記錄的是某個詞在哪些文檔裏出現過以及出現的位置。每條記錄稱爲一個倒排項(Posting)。倒排表記錄的不單是文檔編號,還存儲了詞頻等信息。
  • 倒排文件(Inverted File):所有單詞的倒排列表往往順序地存儲在磁盤的某個文件裏,這個文件被稱之爲倒排文件,倒排文件是存儲倒排索引的物理文件。
  • 段(Segment):索引中最小的獨立存儲單元。一個索引文件由一個或者多個段組成。在Luence中的段有不變性,段一旦生成,在其上只能有讀操作,不能有寫操作。

 

如圖所示,倒排索引中主要有兩部分:詞典和倒排文件。詞典和倒排表是Lucene中很重要的兩種數據結構,是實現快速檢索的重要基石。詞典和倒排文件是分兩部分存儲的,詞典在內存中而倒排文件存儲在磁盤上。

圖中的詞典包含五個詞條(Term):rick,wang,works,on,csdn。在lucene中會記錄每個詞條出現在哪些文檔中,並且將這些文檔的編號存儲成一個有序鏈表(倒排表)1->5>8>12... 基於這種索引方式,lucene可以很方便的從海量文檔中返回匹配到的檢索詞。

如何理解倒排索引?

舉個例子,當我們在翻一本書的時候最先看到的一定是目錄頁,根據目錄裏每個標題找到對應的篇幅文章,這種就是典型的KV關係,標題就是Key,文章內容是Value。 那麼如果我們想找到文章裏包含"CSDN"關鍵字的文章在哪些標題裏呢? 如果在RDBMS中,我們只能用模糊查詢遍歷所有記錄,非常消耗性能又特別的龜速。

而Lucene以倒排表存儲索引,同樣是剛纔的文章,在錄入文章的時候,Lucene會先對文章做分詞識別出所有的詞條(Term),然後記錄這些詞條出現在的文章編號,當文章多了時候,同樣的詞條會出現在多個文章中,對於同一個詞條,它所出現過的文章編號就會組成一個有序鏈表(倒排表),這樣又是一個KV關係,Key就是我們的詞條(Term),而Value是倒排表,當我們想查詢"CSDN"這個單詞出現過的文章的時候我們會找到一個"CSDN"-->"2,3,8,11" 這樣的KV關係,即表示"CSDN"關鍵詞在編號爲2,3,8,11的文章中出現過,只要將這四個文章返回就達到了我們的目的,因此基於倒排索引的Lucene不需要去遍歷索引全部的數據就可以將我們的檢索內容返回。

檢索方式

Lucene基於倒排表存儲索引,因此在查找的過程中只需要在詞典中找到檢索的詞條,然後根據詞條找到對應的倒排列表。然後根據下面四種查詢方式對結果做交併差集等操作即可返回我們想要的結果。

1.單關鍵字查詢

根據輸入的單個詞條(Term)進行查詢,只需要在詞典中查到該詞條的倒排列表即可返回結果。

2.AND

查詢同時包含多個詞條的文檔,取交集。如:首先查詢詞條A的倒排列表[1,2,3],然後查詢詞條B的倒排列表[2,3,4],將兩個倒排列表做交集取[2,3],就是即包含詞條A又包含詞條B的文檔結果集。

3.OR

查詢包含這些詞條的文檔,取並集。如:首先查詢詞條A的倒排列表[1,2,3],然後查詢詞條B的倒排列表[2,3,4],將兩個倒排列表做並集取[1,2,3,4],就是包含詞條A或包含詞條B的文檔結果集。

4.NOT

查詢包含某個詞條且不包含另一個詞條的文檔,取差集。如:首先查詢詞條A的倒排列表[1,2,3],然後查詢詞條B的倒排列表[2,3,4],將AB兩個倒排列表做差集取[1],就是包含詞條A且不包含詞條B的文檔結果集。

分段存儲

早期的Lucene中當寫入數據時會爲整個文檔集合建立一個很大的倒排索引,並將其寫入磁盤中,如果索引有更新,就需要重新全量創建一個索引來替換原來的索引。這種方式在數據量很大時效率很低,並且由於創建一次索引的成本很高,所以對數據的更新不能過於頻繁,也就不能保證實效性。

現在,Lucene中引入了段(Segment)的概念(將一個索引文件拆分爲多個子文件,其中每個子文件稱爲段[Segment]),每個段都是一個獨立的可被搜索的數據集,並且段具有不變性,一旦索引的數據被寫入硬盤,就不可修改。

在分段的思想下,對數據寫操作的過程如下:

  • 新增:當有新的數據需要創建索引時,由於段的不變性,所以會新建一個段來存儲新增的數據。
  • 刪除:當刪除數據時,由於數據所在的段只可讀,不可寫,所以Lucene在索引文件新增一個.del的文件,用來專門存儲被刪除的數據id。當查詢時,被刪除的數據還是可以被查到的,只是在進行文檔鏈表合併時,才把已經刪除的數據過濾掉。被刪除的數據在進行段合併時纔會被真正被移除。
  • 更新:更新的操作其實就是刪除和新增操作的組合(delete & insert),先在.del文件中標記舊數據的刪除,再在新段中添加一條更新後的數據。

段不可變性的優點:

  • 不需要鎖:因爲數據不會更新,所以不用考慮多線程下的讀寫不一致情況。
  • 可以常駐內存:段在被加載到內存後,由於具有不變性,所以只要內存的空間足夠大,就可以長時間駐存,大部分查詢請求會直接訪問內存,而不需要訪問磁盤,使得查詢的性能有很大的提升。
  • 緩存友好:在段的聲明週期內始終有效,不需要在每次數據更新時被重建。
  • 增量創建:分段可以做到增量創建索引,可以輕量級地對數據進行更新,由於每次創建的成本很低,所以可以頻繁地更新數據,使系統接近實時更新。

段不可變性的缺點:

  • 刪除:當對數據進行刪除時,舊數據不會被馬上刪除,而是在.del文件中被標記爲刪除。舊數據只能等到段更新時才能真正地被移除,這樣會有大量的空間浪費。
  • 更新:更新數據由刪除和新增這兩個動作組成。若有一條數據頻繁更新,則會有大量的空間浪費。
  • 新增:由於索引具有不變性,所以每次新增數據時,都需要新增一個段來存儲數據。當段的數量太多時,對服務器的資源(如文件句柄)的消耗會非常大,查詢的性能也會受到影響。
  • 過濾:在查詢後需要對已經刪除的舊數據進行過濾,這增加了查詢的負擔。

爲了提升寫的性能,Lucene並沒有每新增一條數據就增加一個段,而是採用延遲寫的策略,每當有新增的數據時,就將其先寫入內存中,然後批量寫入磁盤中。若有一個段被寫到硬盤,就會生成一個提交點,提交點就是一個用來記錄所有提交後的段信息的文件。一個段一旦擁有了提交點,就說明這個段只有讀權限,失去了寫權限;相反,當段在內存中時,就只有寫數據的權限,而不具備讀數據的權限,所以也就不能被查詢了。因此嚴格意義上來說,Lucene或者Elasticsearch並不能被稱爲實時的搜索引擎,只能被稱爲準實時的搜索引擎。

寫索引的流程:

  1. 暫駐內存:新數據被寫入時,並沒有被直接寫到硬盤中,而是被暫時寫到內存中。(Lucene默認是一秒鐘,或者當內存中數據量達到一定階段時,再批量提交到磁盤中,默認提交時間和數據量的大小是可以通過參數控制的。通過延時寫的策略,可以減少數據往磁盤上寫的次數,從而提升整體的寫入性能,降低磁盤壓力。),此時該內存中的數據不能被檢索到。
  2. 持久化:在達到觸發條件以後,會將內存中緩存的數據一次性寫入磁盤中,並生成提交點,此時該段數據可以被檢索到。
  3. 釋放內存:釋放內存並等待新的數據寫入。

通過上面的流程中可以看到,當內存中的數據還沒有持久化到磁盤中的時候如果集羣出現故障,那麼內存中的數據就會丟失無法恢復,因此在Elasticsearch中新增了事務日誌用以保證數據安全。

段合併策略

上面我們說到,數據每次從內存持久化到磁盤中都會新增一個段(Segment),且這個持久化機制可以根據時間(默認是一秒)以及數據量進行觸發。時間久了,在索引中會存儲大量的段,非常影響服務器的穩定性以及查詢的性能。因此在Lucene中會根據段的大小將段進行分組,然後將同一組的段進行合併,且主要只對中小段進行合併,既可以避免大段合併消耗過多資源也可以很好的控制索引中段的數量。

段合併的主要參數: 

  • mergeFactor:每次合併時參與合併的最少數量,當同一組的段的數量達到該值時開始合併,默認值爲10。
  • SegmentSize:段的實際大小,單位爲字節。
  • minMergeSize:小於該值的段會被分到一組,這樣可以加速小片段的合併。
  • maxMergeSize:若有一段的文本數量大於該值,就不再參與合併,因爲大段合併會消耗更多的資源。

 

Elasticsearch

Elasticsearch是使用Java編寫的一種開源搜索引擎,它在內部使用Luence做索引與搜索,通過對Lucene的封裝,提供了一套簡單一致的RESTful API。Elasticsearch也是一種分佈式的搜索引擎架構,可以很簡單地擴展到上百個服務節點,並支持PB級別的數據查詢,使系統具備高可用和高併發性。

核心概念

  • Cluster:集羣,由一個或多個Elasticsearch節點組成,通過ZenDiscovery進行註冊發現。
  • Node:節點,組成Elasticsearch集羣的服務單元,同一個集羣內節點的名字不能重複。通常在一個節點上分配一個或者多個分片。
  • Shards:分片,當索引上的數據量太大的時候,我們通常會將一個索引上的數據進行水平拆分,拆分出來的每個數據庫叫作一個分片。在一個多分片的索引中寫入數據時,通過路由來確定具體寫入那一個分片中,所以在創建索引時需要指定分片的數量,並且分片的數量一旦確定就不能更改。分片後的索引帶來了規模上(數據水平切分)和性能上(並行執行)的提升。每個分片都是Luence中的一個索引文件,每個分片必須有一個主分片和零到多個副本分片。
  • Replicas:備份也叫作副本,是指對主分片的備份。主分片和備份分片都可以對外提供查詢服務,寫操作時先在主分片上完成,然後分發到備份上。ES爲了提高寫入的能力這個過程是併發寫的,同時爲了解決併發寫的過程中數據衝突的問題,ES通過樂觀鎖的方式控制,每個文檔都有一個 _version (版本)號,當文檔被修改時版本號遞增。一旦所有的副本分片都報告寫成功纔會向協調節點報告成功,協調節點向客戶端報告成功。當主分片不可用時,會在備份的分片中選舉出一個作爲主分片,所以備份不僅可以提升系統的高可用性能,還可以提升搜索時的併發性能。但是若副本太多的話,在寫操作時會增加數據同步的負擔。
  • Index:索引,由一個和多個分片組成,通過索引的名字在集羣內進行唯一標識。
  • Type:類別,指索引內部的邏輯分區,通過Type的名字在索引內進行唯一標識。在查詢時如果沒有該值,則表示在整個索引中查詢。(Elasticsearch7.x之後庫表合一移除了type,type默認都是"_doc"了)。
  • Document:文檔,索引中的每一條數據叫作一個文檔,類似於關係型數據庫中的一條數據通過_id在Type內進行唯一標識。
  • Settings:對集羣中索引的定義,比如一個索引默認的分片數、副本數等信息。
  • Mapping:類似於關係型數據庫中的表結構信息,用於定義索引中字段(Field)的存儲類型、分詞方式、是否存儲等信息。Elasticsearch中的mapping是可以動態識別的。如果沒有特殊需求,則不需要手動創建mapping,因爲Elasticsearch會自動根據數據格式識別它的類型,但是當需要對某些字段添加特殊屬性(比如:定義使用其他分詞器、是否分詞、是否存儲等)時,就需要手動設置mapping了。一個索引的mapping一旦創建,若已經存儲了數據,就不可修改了。
  • Analyzer:字段的分詞方式的定義。一個analyzer通常由一個tokenizer、零到多個filter組成。比如默認的標準Analyzer包含一個標準的tokenizer和三個filter:Standard Token Filter、Lower Case Token Filter、Stop Token Filter。

副本越多,集羣的可用性就越高,但由於每個分片都相當於一個Lucene的索引文件,會佔用一定的文件句柄、內存及CPU,並且分片間的數據同步也會佔用一定的網絡帶寬,因此索引的分片數和副本數也不是越多越好

節點類型 

  • 主節點(Master Node):也叫作主節點,主節點負責創建索引、刪除索引、分配分片、追蹤集羣中的節點狀態等工作。Elasticsearch中的主節點的工作量相對較輕。用戶的請求可以發往任何一個節點,並由該節點負責分發請求、收集結果等操作,而並不需要經過主節點轉發。通過在配置文件中設置node.master=true來設置該節點成爲候選主節點(但該節點不一定是主節點,主節點是集羣在候選節點中選舉出來的),在Elasticsearch集羣中只有候選節點纔有選舉權和被選舉權。其他節點是不參與選舉工作的。
  • 數據節點(Data Node):數據節點,負責數據的存儲和相關具體操作,比如索引數據的創建、修改、刪除、搜索、聚合。所以,數據節點對機器配置要求比較高,首先需要有足夠的磁盤空間來存儲數據,其次數據操作對系統CPU、Memory和I/O的性能消耗都很大。通常隨着集羣的擴大,需要增加更多的數據節點來提高可用性。通過在配置文件中設置node.data=true來設置該節點成爲數據節點。
  • 客戶端節點(Client Node):就是既不做候選主節點也不做數據節點的節點,只負責請求的分發、彙總等,也就是下面要說到的協調節點的角色。其實任何一個節點都可以完成這樣的工作,單獨增加這樣的節點更多地是爲了提高併發性。可在配置文件中設置該節點成爲客戶端節點:   node.master=false; node.data=false;
  • 協調節點(Coordinating Node):協調節點是一種角色,而不是真實的Elasticsearch的節點,我們沒有辦法通過配置項來配置哪個節點爲協調節點。集羣中的任何節點都可以充當協調節點的角色。當一個節點A收到用戶的查詢請求後,會把查詢語句分發到其他的節點,然後合併各個節點返回的查詢結果,最好返回一個完整的數據集給用戶。在這個過程中,節點A扮演的就是協調節點的角色。由此可見,協調節點會對CPU、Memory和I/O要求比較高。
  • 部落節點(Tribe Node):(Elasticsearch7.x中已移除)。部落節點可以跨越多個集羣,它可以接收每個集羣的狀態,然後合併成一個全局集羣的狀態,它可以讀寫所有集羣節點上的數據,在配置文件中通過如下設置使節點成爲部落節點:
    tribe:
        one:
          cluster.name: cluster_one
        two:
          cluster.name: cluster_two

爲了集羣的穩定性,我們應該對Elasticsearch集羣中的節點做好角色上的劃分和隔離。如將候選主節點和數據節點分離,可以減輕主節點的負擔,防止出現"腦裂"的情況。

集羣狀態

  • Green:綠色,健康。所有的主分片和副本分片都可正常工作,集羣100%健康。
  • Yellow:黃色,預警。所有的主分片都可以正常工作,但至少有一個副本分片是不能正常工作的。此時集羣可以正常工作,但是集羣的高可用性在某種程度上被弱化。
  • Red:紅色,集羣不可正常使用。集羣中至少有一個分片的主分片及它的全部副本分片都不可正常工作。這時雖然集羣的查詢操作還可以進行,但是也只能返回部分數據(其他正常分片的數據可以返回),而分配到這個分片上的寫入請求將會報錯,最終會導致數據的丟失。

3C和腦裂

1.共識性(Consensus)

共識性是分佈式系統中最基礎也最主要的一個組件,在分佈式系統中的所有節點必須對給定的數據或者節點的狀態達成共識。雖然現在有很成熟的共識算法如Raft、Paxos等,也有比較成熟的開源軟件如Zookeeper。但是Elasticsearch並沒有使用它們,而是自己實現共識系統zen discovery。zen discovery模塊以“八卦傳播”(Gossip)的形式實現了單播(Unicat):單播不同於多播(Multicast)和廣播(Broadcast)。節點間的通信方式是一對一的。

2.併發(Concurrency)

Elasticsearch是一個分佈式系統。寫請求在發送到主分片時,同時會以並行的形式發送到備份分片,但是這些請求的送達時間可能是無序的。在這種情況下,Elasticsearch用樂觀併發控制(Optimistic Concurrency Control,OCC)來保證新版本的數據不會被舊版本的數據覆蓋。
樂觀併發控制是一種樂觀鎖,另一種常用的樂觀鎖即多版本併發控制(Multi-Version Concurrency Control),它們的主要區別如下:

  • 樂觀併發控制(OCC):是一種用來解決寫-寫衝突的無鎖併發控制,認爲事務間的競爭不激烈時,就先進行修改,在提交事務前檢查數據有沒有變化,如果沒有就提交,如果有就放棄並重試。樂觀併發控制類似於自選鎖,適用於低數據競爭且寫衝突比較少的環境。
  • 多版本併發控制(MVCC):是一種用來解決讀-寫衝突的無鎖併發控制,也就是爲事務分配單向增長的時間戳,爲每一個修改保存一個版本,版本與事務時間戳關聯,讀操作只讀該事務開始前的數據庫的快照。這樣在讀操作不用阻塞操作且寫操作不用阻塞讀操作的同時,避免了髒讀和不可重複讀。

3.一致性(Consistency)

Elasticsearch集羣保證寫一致性的方式是在寫入前先檢查有多少個分片可供寫入,如果達到寫入條件,則進行寫操作,否則,Elasticsearch會等待更多的分片出現,默認爲一分鐘。
下面三種設置判斷是否允許寫操作:

  • One:只要主分片可用,就可以進行寫操作。
  • All:只有當主分片和所有副本都可用時,才允許寫操作。
  • Quorum(k-wu-wo/reng,法定人數):是Elasticsearch的默認選項。當有大部分的分片可用時才允許寫操作。
     其中,對“大部分”的計算公式爲int((primary+number_of_replicas)/2)+1。
    Elasticsearch集羣保證讀寫一致性的方式是,爲了保證搜索請求的返回結果是最新版本的文檔,備份可以被設置爲sync(默認值),寫操作在主分片和備份分片同時完成後纔會返回寫請求的結果。這樣,無論搜索請求至哪個分片都會返回最新的文檔。但是如果我們的應用對寫要求很高,就可以通過設置replication=async來提升寫的效率,如果設置replication=async,則只要主分片的寫完成,就會返回寫成功。

腦裂

在Elasticsearch集羣中主節點通過ping命令來檢查集羣中的其他節點是否處於可用狀態,同時非主節點也會通過ping來檢查主節點是否處於可用狀態。當集羣網絡不穩定時,有可能會發生一個節點ping不通Master節點,則會認爲Master節點發生了故障,然後重新選出一個Master節點,這就會導致在一個集羣內出現多個Master節點。當在一個集羣中有多個Master節點時,就有可能會導致數據丟失。我們稱這種現象爲腦裂

“腦裂”問題可能有以下幾個原因造成:

網絡問題:集羣間的網絡延遲導致一些節點訪問不到master,認爲master掛掉了從而選舉出新的master,並對master上的分片和副本標紅,分配新的主分片

節點負載:主節點的角色既爲master又爲data,訪問量較大時可能會導致ES停止響應(假死狀態)造成大面積延遲,此時其他節點得不到主節點的響應認爲主節點掛掉了,會重新選取主節點。

內存回收:主節點的角色既爲master又爲data,當data節點上的ES進程佔用的內存較大,引發JVM的大規模內存回收,造成ES進程失去響應。

 

如何避免腦裂:

爲了避免腦裂現象的發生,我們可以從原因着手通過以下幾個方面來做出優化措施:

調大響應時間,減少誤判:通過參數 discovery.zen.ping_timeout設置節點狀態的響應時間,默認爲3s,可以適當調大,如果master在該響應時間的範圍內沒有做出響應應答,判斷該節點已經掛掉了。調大參數(如6s,discovery.zen.ping_timeout:6),可適當減少誤判。

選舉觸發:我們需要在候選集羣中的節點的配置文件中設置參數 discovery.zen.munimum_master_nodes的值,這個參數表示在選舉主節點時需要參與選舉的候選主節點的節點數,默認值是1,官方建議取值 (master_eligibel_nodes/2)+1,其中 master_eligibel_nodes爲候選主節點的個數。這樣做既能防止腦裂現象的發生,也能最大限度地提升集羣的高可用性,因爲只要不少於discovery.zen.munimum_master_nodes個候選節點存活,選舉工作就能正常進行。當小於這個值的時候,無法觸發選舉行爲,集羣無法使用,不會造成分片混亂的情況。

角色分離:即是上面我們提到的候選主節點和數據節點進行角色分離,這樣可以減輕主節點的負擔,防止主節點的假死狀態發生,減少對主節點“已死”的誤判。

 

事務日誌TransLog

上面提到,Lucene爲了加快寫索引的速度,採用了延遲寫入的策略。雖然這種策略提高了寫入的效率,但其最大的弊端是,如果數據在內存中還沒有持久化到磁盤上時發生了故障,就可能丟失數據。爲了避免丟失數據,Elasticsearch添加了事務日誌(Translog),事務日誌記錄了所有還沒有被持久化磁盤的數據。

Elasticsearch寫索引的具體過程如下:

  1. 內存緩存且記錄日誌:當有數據寫入時,爲了提升寫入的速度,並沒有數據直接寫在磁盤上,而是先寫入到內存中,但是爲了防止數據的丟失,會追加一份數據到事務日誌裏。
  2. Refresh:當達到默認的時間(1秒鐘)或者內存的數據達到一定量時,會觸發一次Refresh。將JVM中的數據以段的格式緩存到文件系統緩存(操作系統內存)中。
  3. Flush:當日志數據的大小超過512MB或者時間超過30分鐘時,需要觸發一次Flush。將文件系統緩存中的段數據同步至磁盤中。

有關於Translog和Flush的一些配置項

#當發生多少次操作時進行一次flush。默認是 unlimited。
index.translog.flush_threshold_ops

#當translog的大小達到此值時會進行一次flush操作。默認是512mb。
index.translog.flush_threshold_size

#在指定的時間間隔內如果沒有進行flush操作,會進行一次強制flush操作。默認是30m。
index.translog.flush_threshold_period

#多少時間間隔內會檢查一次translog,來進行一次flush操作。es會隨機的在這個值到這個值的2倍大小之間進行一次操作,默認是5s。
index.translog.interval

Refresh會將JVM內存中的可寫不可讀的數據以段格式緩存至操作系統的內存中變成可讀不可寫的狀態,同時清空JVM中的內存準備接受新數據,因爲該段數據仍在操作系統內存中還未持久化到磁盤內,仍有停機丟數據的風險,所以事務日誌暫時不做清空處理。

Flush會將操作系統內存中緩存的段通過fsync函數刷新至磁盤內並生成提交點。因爲此時該段數據以及持久化至磁盤內,所以會將事務日誌刪除並創建一個空的日誌。

當Elasticsearch重啓時,不僅會根據提交點加載已持久化的段數據,還會從事務日誌(Translog)中把(如果有)未持久化的數據重新持久化到磁盤內。

因爲內存中的數據還會繼續寫入,所以內存中的數據並不是以段的形式存儲的,是檢索不到的。總之,Elasticsearch是一個準實時的搜索引擎,而不是一個實時的搜索引擎。

路由Route

上面提到在Elasticsearch集羣中每個索引有N個分片,每個分片會有0到多個副本分片,且分片的數量一旦定下之後就無法修改,在Elasticsearch7.x之後默認分片數量是1,在7.x之前默認分片數量爲5。單個索引最大分片數1024。

在集羣模式下ES根據路由公式將數據寫入不同節點的不同主分片內,主分片異步sync數據給副本分片。路由公式如下:

shard = hash(routing) % number_of_primary_shards

routing 是一個可變值,默認是文檔的 _id ,也可以設置成自定義的值。routing 通過 hash 函數生成一個數字,然後這個數字再除以 number_of_primary_shards (主分片的數量)後得到餘數 。這個在 0 到 主分片數-1 之間的餘數,就是我們所尋求的文檔所在分片的位置。

這也解釋了爲什麼我們要在創建索引的時候就確定好主分片的數量並且永遠不會改變這個數量:因爲如果數量變化了,那麼所有之前路由的值都會無效,文檔也再也找不到了。

由於在ES集羣中每個節點通過上面的計算公式都知道集羣中的文檔的存放位置,所以每個節點都有處理讀寫請求的能力。在一個寫請求被髮送到某個節點後,該節點即爲前面說過的協調節點,協調節點會根據路由公式計算出需要寫到哪個分片上,再將請求轉發到該分片的主分片節點上。 

 

希望本文對你有幫助,請點個贊鼓勵一下作者吧~ 謝謝!

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