背景最近在做搜索推薦相關的優化,在對elasticsearch進行優化時查閱了比較多的資料,現在對其中的一部分進行整理和翻譯,做一個記錄。主要分為三個部分: ·Elasticsearch 數據索引流程·Elasticsearch 數據搜索流程·集群相關 一、Elasticsearch 數據索引流程Elasticsearch 是一個非常強大且靈活的分布式數據系統,可以接受和索引數十億個文檔,使它們可以近乎實時地用于搜索、聚合和分析。這篇文章是關于它是如何完成的,重點介紹基本的新數據插入和從數據寫入請求一直到寫入磁盤的數據流向。 索引是一個相對簡單的高級過程,包括: ·數據通過 API 寫入·數據路由到正確的索引、分片和節點·映射、歸一化和分析·存儲在內存和磁盤上·使其可用于搜索 然而,實際過程要復雜得多,特別是考慮到集群及其數據的分布式特性、所涉及的高數據速率以及所有同時進行的并行特性。此外,這一切都必須盡可能可靠和可擴展。這就是 Elasticsearch 的神奇之處。 讓我們更詳細地看一下這些步驟。 數據到達及分批當數據通過索引 API 到達時,Elasticsearch 首先了解要索引的傳入數據。Logstash、Beats 甚至 cURL 等客戶端將數據發送到集群節點進行處理。他們一次可以發送一個文檔,但通常使用批量 API 批量發送數據,以減少開銷并加快處理速度。批次只是在一個 API 調用中發送的一組文檔,文檔之間不需要相關性,即它們可以包含用于多個不同索引的數據。 攝取的數據可以發送到任何節點。然而,較大的集群通常使用專用的協調節點(更多用于搜索而不是攝取數據),甚至是專用的攝取(ingest)節點,它們可以運行數據管道來預處理數據。數據到達的任何節點都將成為該批次的協調節點,并將數據路由到正確的位置,即使實際攝取工作是在保存目標索引數據的數據節點上執行的。 管道和數據流數據通常到達單個標準索引,但也可以路由到數據流或攝取管道。數據流是一個 X-Pack 功能,通常用于處理時間序列數據,例如指標和日志,并且本質上解析為此攝取過程的實際支持索引。管道是一組處理器,用于在索引之前處理文檔數據。 如果請求或批處理包含管道并且協調節點不是攝取節點(節點可以是單一角色,也可以同時有多個角色),則它似乎會首先路由到攝取節點,然后繼續路由到主節點。由于可能協調節點與攝取節點是分開的,也可能協調節點同時也承擔攝取節點的角色,所以不清楚是協調節點還是攝取節點將文檔發送到主節點,但可能是攝取節點來進行協調運行處理管道,然后將文檔返回到協調節點進行下一步。 路由一旦數據到達協調節點,必須將每個文檔路由到正確的索引、分片和節點以進行攝取。由于批量請求可能包含多個索引的數據,并且單個索引的多個文檔可能會進入單獨的分片,因此路由步驟是針對每個文檔運行的,并且對于將每個文檔都放到正確的位置非常重要。這個過程開始了“協調階段”。 每個文檔的第一步是讓協調節點使用提供的索引、別名、數據流等來確定文檔將要去的實際目標索引。如果索引不存在,則會創建它,然后該過程可以繼續。請注意,Elasticsearch 嘗試在進行任何索引之前首先創建批量請求所需的所有索引。 在協調節點知道目標索引后,它會運行一個路由過程來為文檔選擇索引的分片。路由可能會變得復雜,默認情況下由文檔 ID 驅動,默認情況下由協調節點自動生成。 默認情況下,索引數據的分片算法如下 shard_num = hash(_routing) % num_primary_shards routing字段的取值,默認是_id字段或者是_parent字段,這樣的取值在hash之后再與有多少個shard的數量取模,最終得到這條數據應該在被分配在那個一個shard上,也就是說默認是基于hash的分片,保證在每個shard上數據量都近似平均,這樣就不會出現負載不均衡的情況,然后在檢索的時候,es默認會搜索所有shard上的數據,最后在master節點上匯聚在處理后,返回最終數據。 如果您愿意,客戶端可以指定自己的 ID,還可以控制用于路由的字段,例如時間戳、用戶、源設備等,作為將相關(和可快速查詢)數據集中在一個單一位置的集群策略碎片。此外,索引可以具有強制文檔到特定分片的自定義路由。但一般來說,每個文檔將隨機分布在其目標索引的分片中。 路由過程的結果將是目標分片及其分片 ID,但我們必須記住分片可能有副本。如果有副本,協調節點也會將它們包含在路由列表中,因此結果是該文檔的所有分片的列表:主分片和副本。然后,協調節點查找這些分片的節點 ID 以了解將文檔路由到何處以進行索引。 索引階段一旦協調節點知道文檔的目標主分片和該分片的節點,文檔就會發送到該節點進行主索引,作為“初級階段”的一部分。主分片會驗證請求,然后在本地為它們編制索引,這也會先驗證mapping和字段等。下面將更詳細地描述該過程。 如果主節點索引成功,主分片節點(不是協調器節點)將文檔并行發送給所有處于同步活動狀態的副本節點,這就是“副本階段”。主分片節點等待所有副本節點完成索引,然后將結果返回給等待的協調節點。一旦批處理中的所有文檔都被索引(或失敗),協調器就會將結果返回給原始 API 調用者,即客戶端。
了解每個文檔都被它所在的每個分片單獨索引是很重要的,并且所有這些都必須在給定文檔被標記為'indexed'之前完成。因此,如果索引的副本數為 3,則意味著每個文檔都將轉到四個分片(主分片和三個副本)并由它們單獨索引,所有分片都位于不同的節點上。 Elasticsearch 中沒有真正的預處理或中央索引,集群完成的“工作”隨著給定索引的副本數量線性增加。這通常是大多數索引延遲發生的地方,因為它只能與最慢的節點和分片一樣慢地完成。 協調器節點盡可能多地并行化批處理中的文檔。它并行地將文檔發送到它們路由的主分片,但似乎每個主分片只對一個請求進行排隊(串行處理)。因此,如果批次有 10 個文檔用于單個分片的單個索引,這些將按順序處理,一次一個,但如果批次有 10 個文檔用于兩個索引,每個有 5 個分片,路由結果為一個每個分片的文檔,所有 10 個都將并行完成(相當于10個文檔對應10個分片)。這是增加主分片數量來加速索引處理的一種方式。 分片級索引一旦一個文檔到達一個給定的節點,該節點擁有一個用來寫入數據的分片,實際的文檔索引就完成了。第一步是將文檔寫入 translog 以獲得持久化副本,以防在此之后節點崩潰。 translog 是 Elasticsearch 的一項功能,可提供超出 Lucene 自身所能做到的持久性,并且是可靠系統的關鍵。如果節點在實際索引完成之前崩潰,重新啟動時 Elasticsearch 會將文檔重播到索引過程中以確保它得到處理。 實際的索引過程有幾個步驟: ·Elasticsearch 中的映射文檔字段·在 Lucene 中解析·添加到Lucene的倒排索引 首先,節點通過索引的模板映射文檔的字段,該模板指定如何處理每個字段,例如類型,但還包括分析器和其他選項。由于每個文檔可以有不同的字段和數據,這個映射步驟是必不可少的,也是經常發生錯誤的地方,因為字段類型不匹配、越界等。這項工作是在 Elasticsearch 級別完成的,因為 Lucene 有沒有模板或地圖的概念。Lucene 文檔只是一組字段,每個字段都有名稱、類型和值。 其次,該文檔被傳遞給 Lucene 進行analyze(分詞等操作)。實際上,這意味著在其上運行配置的分析器,每個分析器可以有多個步驟和組件,包括tokenizing和filtering,它們一起可以做很多強大的事情。 Tokenization 是將每個字段中的數據拆分為Token,例如用空格來分隔單詞獲取多個token;過濾包括除基本過濾之外的范圍更廣泛的內容,以將文本轉換成小寫、刪除停用詞和通過詞干進行歸一化(即更改單詞)到他們的“正常”版本,例如dogs變成dog,watched變成watch,等等) 最后,Lucene 獲取結果并為該文檔構建其存儲記錄。這通常包括文檔中的每個字段,以及可用于重新索引等的特殊字段,例如 _source 和 _all,以及非常重要的倒排索引本身。 Lucene 將所有這些寫入內存中的segment緩沖區,然后向協調節點返回成功。一旦在所有副本分片上完成此操作,從協調器節點或客戶端的角度來看,該文檔的索引基本上是完整的。 獲取磁盤上的文檔數據并可搜索剛剛索引的文檔只在內存中的臨時多文檔segment中,還沒有在磁盤上,也不能用于搜索。兩個獨立的進程在后臺運行以實現這兩件事。
第一個過程是“refresh”以使數據可用于搜索。refresh interval按索引設置,默認為 1 秒。許多用戶將此設置得更高,例如 30-60 秒,因為這是一項昂貴的操作,每秒執行一次會降低整體索引吞吐量。請注意,不經常搜索的索引在搜索之前不會自動刷新,以提高批量索引速度。 在刷新間隔,內存緩沖區的segment被合并并寫入文件系統上的單個新segment,并且數據可用于搜索。但是,雖然該segment現在存在于文件系統上,但它主要位于文件緩存中,實際上可能不在磁盤上,如果此時發生崩潰,這將是一個問題。數據是可用的,但不安全,雖然如果發生崩潰,translog 仍然存在并會被回放,并且文檔將被再次索引。 為了確保磁盤上的數據安全,有一個單獨的 Elasticsearch 刷新進程執行 Lucene 提交,合并和同步上述segment,確保它們確實在磁盤上。一旦完成,Elasticsearch 將截斷 translog,因為數據現在安全地存儲在磁盤上并且不會在崩潰中丟失。Elasticsearch 根據 translog 大小(默認最大值為 512MB)安排這些刷新,以幫助保持合理的恢復時間。 本質上,translog 為所有新文檔更改以及 Elasticsearch 刷新/Lucene 提交之間保持可靠性。注意 translog 有它自己的可靠性設置,包括每 5 秒 fsync 到磁盤的默認設置。 Elasticsearch 還單獨運行后臺線程以盡可能地繼續合并segments,使用分層合并策略盡量減少段數(因為它們是按順序搜索的),同時不會降低整體實時索引和搜索性能。這與上述所有過程是分開的。 總體結果是,在任何給定時間,任何特定可用索引都由磁盤上一組不同大小的永久段和文件緩存中的一些新段組成。加上僅在內存中的索引但尚不可用的段,等待刷新間隔。 相關參數: a) index.translog.sync_interval- translog 被 b) index.translog.durability-是否 c) index.translog_flush_threshold-默認為 512mb。 問題Elasticsearch 索引是一個很好但復雜的分布式過程,它平衡了高性能、數據可靠性和強大的功能。雖然它運作良好,但事情可能并且確實會出錯。一些問題出在文檔本身,而另一些問題出在集群方面。 集群級別的問題通常與過程中的碎片丟失或移動有關。正常的流程是從協調器節點到主節點再到副本節點,但是如果在這個過程中主節點發生了變化,或者副本丟失了怎么辦?有各種復雜的重試、超時和路由過程嘗試保存文檔,當然,它們可能會失敗,此時客戶端必須重試。 其中一些,例如副本超時或失敗,將導致該分片被聲明為不同步和無效,將索引狀態更改為黃色并安排副本重建。其他的,比如網絡分區,會導致主節點本身被聲明為無效,當它試圖與副本通信時會發現這一點。總的來說,這是一個復雜但強大的系統。 在生產中使用 Elasticsearch 時要記住的一些重要點:1.它提供了樂觀并發控制。在更新任何文檔時,可以在請求中傳遞一個版本。它在更新時不會鎖定任何分片或文檔。2.所有文檔都是不可變的,無法更改,更新會刪除現有文檔(軟刪除會在稍后的某個時間點在后臺刪除)。因此,我們必須始終確保最多使用機器中可用容量的一半。3.始終保留比可用實例(或節點)更多的分片,以便索引可以通過添加更多節點在負載增加的情況下擴展。請記住,索引的#shards 一旦創建就無法修改。每個節點的推薦 #shards 為2:1。4.Elasticsearch 在批量操作方面表現更好。如果可能,嘗試批量索引或搜索您的文檔。5.如果需要精確的字段搜索,請使用過濾器而不是查詢,因為過濾器比查詢更有效。過濾結果也可以緩存。6.3個主節點集群是首選。7.禁用索引中的_all字段并使用 copy_to 選項復制需要復制到_all字段的字段。默認情況下,每個字段的數據都存儲在_all字段中。此過程稱為黑名單方法。建議使用白名單方法,以獲得有效的索引。它節省了很多空間 參考有幾篇關于這個過程的好文章,但大多數都是多年的,并且最好地涵蓋了 Elasticsearch 的早期版本,盡管這些過程仍然大體相同: ·Elasticsearch From the Bottom Up[1]·Elasticsearch From the Top Down[2]·Anatomy of an Elasticsearch Cluster[3]·Current Replication Docs[4]·Elasticsearch Refresh & Flush Operations[5] 出處譯自:https:///swlh/elasticsearch-indexing-data-flow-d56ea14e1772 二、Elasticsearch 搜索全流程介紹Elasticsearch是一個非常強大且靈活的分布式數據系統,主要專注于搜索和分析數十億個文檔。這篇文章是關于它是如何完成的,重點是通過集群的查詢和數據流,從磁盤到所有的分片、索引、節點、分析、過濾器等等。 這個博客是關于搜索如何在相當深的層次上工作的,我們的目標是遍歷從搜索請求到結果回復的過程,包括將查詢路由到碎片、分析器、映射、聚合和協調。其中一些項目來自文檔或代碼,其他項目來自其他人的著作,還有一些是猜測,因為并非所有內容都清楚或有據可查。 基本搜索數據流基本的搜索數據流如下: ·到達Coordinator·索引列表和別名·分片路由·實際搜索·組裝文檔列表·獲取文件·排序和聚合·返回結果 然而,實際過程要復雜得多,特別是考慮到集群及其數據的分布式特性、涉及的高搜索率以及所有同時進行的并行特性。此外,這一切都必須盡可能可靠和可擴展。這就是 Elasticsearch 的神奇之處。 我們將在下面更深入地研究每一個。 到達當搜索查詢通過各種搜索 API 到達時,Elasticsearch 首先了解它。Kibana、應用程序甚至 cURL 等客戶端將搜索請求發送到集群節點進行處理。有多種 API 和選項,但幾乎所有的 API 和選項都以本質上的搜索結束,盡管或多或少具有復雜性和資源需求。 搜索請求可以發送到任何節點,但較大的集群通常使用具有足夠 CPU 和 RAM 的專用協調節點來管理高搜索量并限制協調對數據或其他節點的影響。查詢到達的任何節點都將成為此查詢的協調節點,并將數據路由到正確的位置,即使大部分實際搜索工作是在保存源索引數據的數據節點上執行的。 路由查詢到達協調節點后,必須將其路由到正確的索引、分片和節點以進行搜索。由于查詢請求可能涵蓋許多索引和分片,因此路由步驟對于將每個索引和分片都放到正確的位置非常重要。 首先,協調器根據查詢索引模式或別名構建目標索引列表。這通常是單個索引,但也可以是“logsash-*”之類的模式或指向索引或模式的別名。結果是查詢需要搜索的實際索引列表。 然后協調器構建所有目標索引的不同分片的列表。這可能會令人困惑,因為在 Elasticsearch 中,一個不同的分片(帶有分片 ID)實際上是一組單一的主副本及其可選的副本副本。 因此,具有 5 個分片和 2 個副本的索引將總共有 15 個分片,但只有 5 個不同的分片,每個分片的 ID 都以 0 開頭,因此在這種情況下為 0-4。每個都將有 3 個分片:一個主分片和兩個副本。給定的主節點和它的副本共享相同的分片 ID,只是在分片列表中將 primaryOrReplica 設置為“p”或“r”,因此您將看到分片:0/p、0/r 和第二個 0/r(其中每一個也有一個唯一的分配 ID,這是 Elasticsearch 在內部區分它們的方式)。 對于每個索引并基于索引路由選項,協調器決定查詢是轉到單個不同的分片還是所有分片。大多數查詢會轉到所有不同的分片,但特定的路由可以確保所有查詢的文檔都在單個不同的分片中;如果是這樣,查詢只會轉到那個不同的分片。 負載無論查詢是針對一個不同的分片還是所有分片,對于涉及的每個分片,協調器都會選擇要查詢每個分片的實際分片,主分片或副本之一。 因此,如果我們查詢具有 5 個分片和 2 個副本的索引,則有 5 個不同的分片,總共有 15 個分片。假設沒有配置路由,實際查詢將發送到 5 個分片,每個分片從每個不同分片的 3 個副本(1 個主分片,2 個副本)中選擇。 默認情況下,這種選擇或“平衡”算法大多是隨機的,盡管有一些優化,包括支持在最近的查詢中表現最好的分片。它也可以通過“首選項”選項在查詢的基礎上進行控制。 路由過程的結果是要查詢的實際分片列表,以及這些分片所在的節點,因為這是協調器需要發送要運行的查詢的地方。 搜索分片——查詢階段分片執行實際的搜索(和評分)工作。查詢階段搜索就是這樣,搜索與查詢匹配的文檔。 此搜索的每個分片都會發生幾件事: ·Elasticsearch 級別的映射·Lucene 中的Analysis·在 Lucene 中搜索·在 Lucene 中評分 該映射類似于索引時的映射,Elasticsearch 將查詢字段映射到底層 Lucene 數據字段和結構,以創建每個段(實際上是一個 Lucene 索引)都可以執行的 Lucene 兼容查詢。看起來映射和轉換到 Lucene 查詢是由每個分片完成的,類似于索引由每個分片完成。 分析與索引時完全相同,查詢的文本部分通過相同的分析器運行,例如標記文本、轉換為小寫和詞干等。這樣查詢文本將最好地匹配這些文件已編入索引。 段搜索分片級搜索實際上是一系列合并在一起的段級搜索(這就是為什么段越少通常性能越好)。由于段正在執行真正的搜索工作,因此大多數緩存也在段級別,這就是您在集群和節點統計信息中看到它們的方式。 段級別的實際搜索過程詳細信息取決于查詢類型和所需內容。這可以有很大的不同,從簡單的術語搜索像 name = “bob” 到復雜的多字段全文搜索在各種語言中。 任何這些搜索的結果通常是一個文檔 ID 列表,可以選擇對其進行評分和排序以獲得相關性。這個列表被稱為優先級隊列,它的大小取決于查詢,默認為 10,但如果查詢使用普通分頁,它將是 'from+size',它可以在深度分頁時使用大量 RAM。 評分本身是一個復雜的領域,比非評分查詢需要更多的資源,特別是如果使用 DTS 模式來提高全局評分結果。我們將把 Lucene 評分留給其他博客。 按任何文檔字段(即不是分數)排序是通過 doc 值完成的,因為倒排索引不太適合于此。Doc 值是 Lucene 的序列化列數據存儲,它將一個字段的所有數據打包在一起,因此可以快速讀取大量值,這非常適合聚合,也適用于排序。默認情況下,除分析字符串外的所有字段都啟用它們。 聚合更復雜,因為它們需要一種方法來訪問所有匹配的文檔,即它們不能使用短列表。它們也適用于“文檔值”,而不是倒排索引。該過程因聚合類型而異,在某些情況下,例如術語計數,分片返回為其文檔設置的整個聚合大小,協調器會將它們合并在一起。 例如,對于大小為 100 的術語計數,每個分片返回 160 個術語,協調器會將它們合并并排序為最終的 100 個給客戶端。每個分片的計數可以通過 shard_size 參數進行調整,默認為 (size * 1.5 + 10),或者 160 表示大小為 100。 對于指標聚合,例如平均值,它需要所有匹配的文檔及其字段數據。目前尚不清楚這是如何完成的,但大概每個分片都提供了自己的平均值和計數,然后協調節點可以將其合并。Min/Max 和其他可能類似的處理。 搜索進程段的注意事項有自己的緩存,用于以下幾件事: ·Filter Cache - 給定過濾器的文檔 ID 段緩存。這極大地加快了搜索速度,這也是過濾器流行的原因。·Field Cache — 字段數據值的段緩存。主要在獲取階段稍后使用。·Page Cache——當然,在 Elasticsearch 之外,用于分段數據。 分片還維護一個query cache,因此它可以在將來返回相同查詢的結果。但是,如果索引實際發生更改,則每次索引刷新(默認為 1 秒,更常見的是 30-60 秒)時,此緩存都會失效,因此雖然對繁重的索引不太有用,但它仍然可以幫助搜索大量索引。請注意,此緩存由給定節點上的所有分片共享,最多為堆大小的 1%。 雖然過濾器有緩存,但查詢(評分搜索)不是,因此對于查詢和任何未緩存的過濾器或字段,搜索必須命中倒排索引以構建文檔 ID 列表。可以緩存生成的過濾器結果和字段數據。 請注意,所有搜索都是從刷新或提交的索引段完成的,因此只有在刷新后才會搜索或找到數據。唯一的例外是當客戶端通過 ID 執行 GET 獲取文檔時,在這種情況下,可以在刷新索引之前從 translog 中提取它。有關刷新和 translog 的更多詳細信息,請參閱 Elasticsearch Indexing Dataflow 上的博客。 Coordinator歸集數據每個分片將返回其最高命中作為文檔 ID,而不是整個文檔。因此,如果我們有 5 個分片且默認大小為 10,我們將得到 50 個結果。如果涉及多個索引,它們的分片也會返回它們的結果。協調器節點合并這些列表以獲得實際的排序列表,并在收集階段繼續為它們獲取實際數據。 獲取階段——收集一旦協調器節點有了它需要的最終文檔 ID 列表,它將返回到分片以獲取實際數據,直到現在它都不需要這些數據。這是第 2 階段或“收集”過程,它使用對各種分片的多文檔 GET 請求來獲取文檔數據,通常作為 _source 字段。請注意,如果客戶端僅要求聚合(大小 = 0),則會跳過此步驟。 請注意,這是協調節點 RAM 可能失控的地方,也是首先擁有協調節點的主要原因之一。這些節點將處理、合并和排序結果所需的 CPU 和 RAM 資源保存在幾個易于監控的節點中,重要的是讓這些資源密集型進程遠離主節點、數據節點和 ML 節點,以執行其他重要工作。 例如,在深度分頁中,返回的文檔數量將是“from + size”頁面,因此來自多個索引和分片的深度頁面將收集“number_of_shards * (from + size)”文檔,這會變得非常大,吃光了所有的堆。在這種情況下,用戶通常使用滾動查詢。大文檔大小和列表同樣會導致 RAM 使用量增加。 聚合通常是根據分片返回的聚合結果構建的,聚合似乎沒有獲取階段,但如果查詢大小>0,協調器仍會為客戶端獲取底層文檔數據。 一旦協調節點擁有所有文檔及其數據和/或聚合,它就會構建最終結果,并在需要時使用元數據和其他元素對其進行增強,然后將它們返回給調用者,過程完成。 問題Elasticsearch 搜索非常快速和強大,盡管它是一個復雜的分布式過程,可以平衡高性能、準確性和功能。更大的實時性和穩定性,即不讓大查詢炸毀集群。雖然它工作得很好,但事情也確實可能會出問題。 當然,任何數據系統都可能耗盡關鍵資源,尤其是 CPU 和磁盤 IO 帶寬。Elasticsearch 非常依賴這兩者,但由于是分布式的,通常很容易根據需要添加更多。 另一個關鍵資源是 RAM,這是可能發生更多問題的地方。在最近的版本中,在保護系統方面做了很多工作,尤其是斷路器的概念,它限制了單個查詢和聚合操作可以消耗的 RAM。 查詢級別的斷路器也用于查詢的各個部分,例如字段數據,以防止查詢使系統的該部分過載(并提供關于您的查詢如何潛在地損害集群的準確報告)。 查詢驅動的內存相關問題通常來自字段組合、大聚合、大文檔、深分頁等。與此相關的是,擁有不適合頁面緩存的大索引會導致 I/O 壓力,這不會使系統崩潰,但會減慢系統速度。 其他問題包括在搜索過程中超時和分片或節點丟失。通常,Elasticsearch 會使用其他分片重試這些操作,以嘗試盡可能完整地回答客戶端的查詢。注意默認情況下,如果存在內部超時或分片故障,Elasticsearch 將返回部分結果。 概括Elasticsearch 是一個非常漂亮和強大的系統,能夠通過簡單的界面快速靈活地搜索數十億文檔。從這個博客中,您可以看到請求和數據如何在集群中移動以從磁盤到達客戶端。 參考有幾篇關于這個過程的好文章,但大多數都是多年的,并且最好地涵蓋了 Elasticsearch 的早期版本,盡管這些過程仍然大體相同: ·Elasticsearch 及其內部工作[6]·自下而上的 Elasticsearch[7]·自上而下的 Elasticsearch[8]·Elasticsearch 集群剖析[9] 出處譯自:https://steve-mushero./elasticsearch-search-data-flow-2a5f799aac6a 三、集群相關共識[10]是分布式系統的基本挑戰之一。它要求系統中的所有進程/節點就給定的數據值/狀態達成一致。有很多共識算法,如Raft[11]、Paxos[12]等,它們在數學上被證明是有效的,但是,由于Shay Banon(Elasticsearch 的創建者)在這里[13]描述的原因,Elasticsearch 已經實現了自己的共識系統(zen discovery)。zen discovery模塊有兩個部分: ·Ping: 進程節點用來發現彼此·Unicast:包含主機名列表的模塊,用于控制要 ping 的節點 Elasticsearch 是一個點對點系統,其中所有節點相互通信,并且有一個活動主節點更新和控制集群范圍內的狀態和操作。作為 ping 過程的一部分,新的 Elasticsearch 集群會進行選舉,其中從所有符合主節點的節點中選出一個節點作為主節點,其他節點加入主節點。默認ping_interval為1 sec,ping_timeout為3 sec。節點加入,他們發送加入請求到主節點,join_timeout的默認值是ping_timeout的20倍. 如果 master 失敗,集群中的節點會再次開始 ping 以開始另一次選舉。如果節點意外地認為主節點發生故障并通過其他節點發現主節點,則此 ping 過程也有幫助。 注意:默認情況下,客戶端和數據節點不參與選舉過程。這可以通過在elasticsearch.yml配置文件中將discovery.zen.master_election.filter_client和discovery.zen.master_election.filter_data屬性設置為False來更改。 對于故障檢測,主節點 ping 所有其他節點以檢查它們是否處于活動狀態,所有節點都 ping 主節點以報告它們處于活動狀態。 如果使用默認設置,Elasticsearch 會遇到腦裂[14]問題 ,在網絡分區的情況下,節點會認為 master 已死并選擇自己作為 master,從而導致集群具有多個 master。這可能會導致數據丟失,并且可能無法正確合并數據。這可以通過將以下屬性設置為符合主節點的法定人數來避免。
此屬性需要活動主節點的法定人數,以加入新當選的主節點,以便選舉過程完成,并讓新主節點接受其主節點。這是確保集群穩定性的一個極其重要的屬性,并且可以在集群大小發生變化時進行動態更新。圖a和b顯示了分別設置和不設置minimum_master_nodes屬性時,對于網絡分區會發生什么情況。注意:對于一個生產集群,建議有3個專用的主節點,這些節點不服務于任何客戶端請求,其中1個節點在任何時候都是活動的。正如我們在Elasticsearch中了解的共識,現在讓我們看看它是如何處理并發性的。 并發Elasticsearch 是一個分布式系統,支持并發請求。當創建/更新/刪除請求到達主分片時,它也會并行發送到副本分片,但是,這些請求可能會亂序到達。在這種情況下,Elasticsearch 使用樂觀并發控制[15]來確保較新版本的文檔不會被舊版本覆蓋。 每個索引的文檔都有一個版本號,該版本號隨著應用于該文檔的每次更改而遞增。這些版本號用于確保按順序應用更改。為確保我們的應用程序中的更新不會導致數據丟失,Elasticsearch 的 API 允許您指定應應用更改的文檔的當前版本號。如果請求中指定的版本比分片中存在的版本舊,則請求失敗,這意味著文檔已被另一個進程更新。可以在應用程序級別控制如何處理失敗的請求。還有其他鎖定選項可用,您可以在此處[16]閱讀有關它們的信息[17]。 當我們向 Elasticsearch 發送并發請求時,下一個問題是——我們如何使這些請求保持一致?現在,尚不清楚回答CAP[18]三角形 Elasticsearch 落在哪一邊,這是一個我們不會在這篇文章中解決的爭論。 但是,我們將回顧如何使用 Elasticsearch 實現一致的寫入和讀取。 一致性——確保一致的寫入和讀取對于寫入,Elasticsearch 支持與大多數其他數據庫不同的一致性級別,以允許進行初步檢查以查看允許寫入的可用分片數量。可用選項有quorum、one和all。默認情況下,它設置為quorum ,這意味著只有在大多數分片可用時才允許寫入操作。在大多數分片可用的情況下,仍然可能發生對副本的寫入由于某種原因失敗,在這種情況下,副本被稱為有故障,分片將在不同的節點上重建。 對于讀取,新文檔在刷新間隔之后才可用于搜索。為了確保搜索請求從最新版本的文檔返回結果,復制可以設置為同步(默認),它在主分片和副本分片上完成操作后返回寫請求。在這種情況下,來自任何分片的搜索請求將返回文檔最新版本的結果。即使您的應用程序需要replication=async以獲得更高的索引率,也可以將_preference參數設置為主要用于搜索請求。這樣,主分片會被查詢以獲取搜索請求,并確保結果將來自文檔的最新版本。 隨著我們了解 Elasticsearch 如何處理共識、并發和一致性,讓我們回顧一下分片內部的一些重要概念,這些概念導致 Elasticsearch 作為分布式搜索引擎的某些特征。 Translog自關系數據庫的發展以來,預寫日志 (WAL) 或事務日志 (translog) 的概念一直存在于數據庫世界中。Translog 確保在發生故障時的數據完整性,其基本原則是必須在將數據的實際更改提交到磁盤之前記錄并提交預期的更改。 當新文檔被索引或舊文檔被更新時,Lucene 索引會發生變化,這些變化將提交到磁盤以進行持久化。在每次寫入請求之后執行它是一項非常昂貴的操作,因此,它以一次將多個更改持久化到磁盤的方式執行。正如我們在之前的博客中[19]所描述的, 默認情況下每 30 分鐘執行一次刷新操作(Lucene 提交)或當 translog 變得太大時(默認為 512MB)。在這種情況下,有可能會丟失兩次 Lucene 提交之間的所有更改。為了避免這個問題,Elasticsearch 使用了一個 translog。所有索引/刪除/更新操作都寫入 translog,并且在每次索引/刪除/更新操作后(或默認情況下每 5 秒)對 translog 進行 fsync,以確保更改是持久的。在主分片和副本分片上對 translog 進行 fsync 后,客戶端會收到寫入確認。 如果在兩次 Lucene 提交或重新啟動之間發生硬件故障,則會重播 translog 以從最后一次 Lucene 提交之前丟失的任何更改中恢復,并將所有更改應用于索引。 注意:建議在重啟 Elasticsearch 實例之前顯式刷新 translog,因為啟動會更快,因為要重放的 translog 將為空。POST /_all/_flush命令可用于刷新集群中的所有索引。 通過 translog 刷新操作,文件系統緩存中的段被提交到磁盤以使索引中的更改持久化。現在讓我們看看什么是 Lucene 段。 Lucene 段一個 Lucene 索引由多個段組成,一個段本身就是一個功能齊全的倒排索引。段是不可變的,這允許 Lucene 以增量方式向索引添加新文檔,而無需從頭開始重建索引。對于每個搜索請求,搜索索引中的所有段,每個段消耗 CPU 周期、文件句柄和內存。這意味著段數越多,搜索性能就越低。 為了解決這個問題,Elasticsearch 將小段合并成一個更大的段(如下圖所示),將新合并的段提交到磁盤并刪除舊的小段。 這會在后臺自動發生,不會中斷索引或搜索。由于段合并可能會耗盡資源并影響搜索性能,因此 Elasticsearch 會限制合并過程以獲得足夠的資源可用于搜索。 對于搜索請求,會搜索 Elasticsearch 索引的給定分片中的所有 Lucene 段,但是,獲取所有匹配文檔或位于排名結果深處的文檔對您的 Elasticsearch 集群來說是危險的。 參考·https://www./blog/elasticsearch-distributed-consistency-principles-analysis-1---node_594358?spm=a2c41.12499374.0.0·https://www./blog/elasticsearch-distributed-consistency-principles-analysis-2---meta_594359?spm=a2c65.11461447.0.0.460e1107c5kGpY·https://www./blog/elasticsearch-distributed-consistency-principles-analysis-3---data_594360?spm=a2c65.11461447.0.0.460e1107c5kGpY 出處譯自:https://blog./anatomy-of-an-elasticsearch-cluster-part-ii-6db4e821b571 References
|
|
來自: 520jefferson > 《海量數據處理方法》