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