分布式 ES 操作流程解析


概念解析

CURD 操作

CURD 操作都是針對具體的某個或某些文檔的操作,每個文檔的 routing 都是確認的,所以其所在分片也是可以事先確定的。該過程對應 ES 的 Document API。

  • 新建(C): 指對某個文檔進行索引操作的過程。
  • 檢索(R): 指從 ES 中獲取某個或多個特定文檔的過程。
  • 刪除(D): 指從 ES 中刪除某個文檔讓其不再可被搜索。
  • 更新(U): 指在 ES 中更新某個文檔的過程,其實質是刪除+新建的過程。

搜索

搜索操作是指通過查詢條件從 ES 中獲取匹配的文檔的過程,搜索前不知道哪個文檔會匹配查詢。該過程對應 ES 的 Search API。

 

路由和分片

分片

  • 文檔在索引的時候,需要確定文檔存放到哪個分片上去。(通過把 _id 作為 routing 來計算 shard)
  • 文檔在檢索的時候,需要確定文檔處在具體哪個分片上。(通過把 _id 作為 routing 來計算 shard)

路由

分片的確定,都是由路由來完成的,具體計算公式如下:

shard = hash(routing) % number_of_primary_shards
  • routing 值是一個任意字符串,它默認是 _id 但也可以自定義。
  • routing 字符串通過哈希函數生成一個數字,然后除以主切片的數量得到一個余數(remainder),余數的范圍永遠是 0 到 number_of_primary_shards - 1 ,這個數字就是特定文檔所
    在的分片。
  • 這也解釋了為什么主分片的數量只能在創建索引時定義且不能修改:如果主分片的數量在未來改變了,所有先前的路由值就失效了,文檔也就永遠找不到了。

 

文檔的新建、索引和刪除

流程

新建、索引和刪除請求都是寫(write)操作,它們必須在主分片上成功完成才能復制到相關的復制分片上。並且要等所有復制分片完成后才向請求節點返回。

image

在主分片和復制分片上成功新建、索引或刪除一個文檔必要的順序步驟:

  • 1. 客戶端給 Node 1 發送新建、索引或刪除請求,Node 1 作為協調節點。
  • 2. 協調節點使用文檔的 _id 確定文檔屬於分片 0 (通過把 _id 作為 routing 來計算 shard)。它轉發請求到 Node 3 (主分片位於這個節點上)。
  • 3. Node 3 在主分片上執行請求,如果成功,它轉發請求到相應的位於 Node 1 和 Node 2 的復制節點上。當所有的復制節點報告成功, Node 3 報告成功給協調節點。
  • 4. 協調節點返回結果給客戶端。

客戶端接收到成功響應的時候,文檔的修改已經被應用於主分片和所有的復制分片。

由於要主分片和復制分片都成功后才返回成功,所以寫操作是比較耗時的。

優化

replication:

replication 默認為 sync。也就是要等所有復制分片都操作完后才返回。

設置為 async 運行在主分片操作完成后即返回。

 

文檔的檢索

流程

檢索文檔為讀(read)操作,請求只需分片的任意一個副本返回操作結果即完成。

image

在主分片或復制分片上檢索一個文檔必要的順序步驟:

  • 1. 客戶端給 Node1(主節點) 發送 get 請求,Node 1 作為協調節點。
  • 2. 協調節點使用文檔的 _id 確定文檔屬於分片 0(通過把 _id 作為 routing 來計算 shard) 。分片 0 對應的復制分片在三個節點上都有。此時,它轉發請求到 Node 2 。
  • 3. Node 2 返回執行結果給協調節點。
  • 4. 協調節點返回結果給客戶端。

對於讀請求,為了平衡負載,協調節點會為每個分片的請求選擇不同的副本——它會循環所有分片副本。

 

文檔的更新

流程

更新過程整體流程就是 “讀” + “寫” 操作。

image

執行更新必要的順序步驟:

  • 1. 客戶端給 Node 1 發送更新請求,Node 1 作為協調節點。
  • 2. 協調節點轉發請求到主分片所在節點 Node 3(主分片) 。
  • 3. Node 3 從主分片檢索出文檔,修改 _source 字段的JSON,然后在主分片上重新索引。如果有其他進程修改了文檔,它以 retry_on_conflict 設置的次數重復步驟3,都未成功則放棄。
  • 4. 如果 Node 3 成功更新文檔,它同時轉發文檔的新版本到 Node 1 和 Node 2 上的復制分片以重新索引。當所有節點報告成功, Node 3 返回成功給協調節點。
  • 5. 協調節點返回結果給客戶端。

 

批量文檔操作

批量檢索(mget)和批量新建、索引、更新、刪除(bulk)操作和單個文檔的操作過程類似。

區別在於協調節點知道所有文檔所在的分片,並將請求的文檔根據所在的分片來分組。然后同時請求需要的節點。

一旦收到所有節點的響應,協調節點再將這多個節點的響應組合成一個響應結果返回給客戶端。

流程

mget 操作

image

mget 操作過程基本步驟:

  • 1. 客戶端發送請求到 Node 1,Node 1 作為協調節點。
  • 2. 協調節點確認每一個操作請求的目標分片,並根據需要請求的目標分片重新分組。
  • 2. 協調節點同時轉發每組請求到目標主分片或復制分片(檢索操作任意分片都可以)
  • 3. 一旦所有請求的分片都返回,協調節點整理結果,並返回給客戶端。

bulk操作

 bulk 操作過程基本步驟:

  • 1. 客戶端發送請求到 Node 1,Node 1 作為協調節點。
  • 2. 協調節點確認每一個操作請求的目標主分片,並根據目標主分片重新分組。
  • 2. 協調節點同時請求包含這些主分片的節點(步驟2)。
  • 3. 每一個主分片一個接一個的處理每一個文檔請求——某個文檔在主分片上請求成功了,主分片將請求發送給它所有的復制分片,然后就接着處理下一個文檔請求。
  • 4. 當所有的復制分片請求成功后,主分片所在節點就向協調節點報告成功。
  • 5. 協調節點整理所有文檔的結果,並返回給客戶端。

 

搜索

文檔的 CRUD 操作一次只處理一個單獨的文檔(批量操作也是單個執行)。CRUD 操作中,文檔的唯一性由 _index , _type 和 routing (通常默認是該文檔的 _id )的組合來確定。這意味着我們可以准確知道集群中的哪個分片有這個文檔。

搜索過程,由於不知道哪個文檔會匹配查詢(文檔可能存放在集群中的任意分片上),所以搜索需要一個更復雜的模型。搜索通過查詢每一個我們感興趣的索引的分片副本,來看是否含有任何匹配的文檔。

搜索的執行過程分兩個階段,稱為查詢然后取回(query then fetch)。

查詢階段

GET /_search
{    "from": 90,
     "size": 10
}

image

1. 客戶端發送一個 search(搜索) 請求給 Node 3 , Node 3 創建了一個長度為 from+size 的空優先級隊列。

2. Node 3 轉發這個搜索請求到索引中每個分片的原本或副本。搜索請求可以被每個分片的原本或任意副本處理。

(並非所有副本都處理同樣的請求,而是輪詢處理不同的請求,所以多副本能夠提高吞吐)

3. 每個分片在本地執行這個查詢並且結果將結果到一個大小為 from+size 的有序本地優先隊列里去。

4. 每個分片返回document的ID和它優先隊列里的所有document的排序值給協調節點 Node 3 。 Node 3 把這些值合並到自己的優先隊列里產生全局排序結果。

5. 對於多(multiple)或全部(all)索引的搜索的工作機制和這完全一致——僅僅是多了一些分片而已。

取回階段

查詢階段辨別出那些滿足搜索請求的document,但我們仍然需要取回那些document本身。這就是取回階段的工作。

image

1. 協調節點(請求節點)辨別出哪個document需要取回(比如只取前100項),並且向相關分片發出 GET 請求。

2. 每個分片加載document並且根據需要豐富(enrich)它們,然后再將document返回協調節點。

3. 一旦所有的document都被取回,協調節點會將結果返回給客戶端。

搜索選項

1. preference:

preference 參數允許你控制使用哪個分片或節點來處理搜索請求。她接受如下一些參數 _primary , _primary_first ,_local , _only_node:xyz , _prefer_node:xyz 和 _shards:2,3

2. timeout:

通常,協調節點會等待接收所有分片的回答。如果有一個節點遇到問題,它會拖慢整個搜索請求。timeout 參數告訴協調節點最多等待多久,就可以放棄等待而將已有結果返回。

3. routing:

指定一個或多個 routing 值來限制只搜索那些分片而不是搜索index里的全部分片。

4. search_type:

  • count(計數):當不需要搜索結果只需要知道滿足查詢的document的數量時,可以使用這個查詢類型。
  • query_and_fetch:搜索類型將查詢和取回階段合並成一個步驟
  • dfs_query_then_fetch 和 dfs_query_and_fetch
  • scan:scan(掃描) 搜索類型是和 scroll(滾屏) API連在一起使用的,可以高效地取回巨大數量的結果。它是通過禁用排序來實現的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM