如何決定文檔被存儲在哪個分片?
shard = hash(routing) % number_of_primary_shards
routing
是一個可變值,默認是文檔的 _id
,也可以設置成一個自定義的值。 routing
通過 hash 函數生成一個數字,然後這個數字再除以 number_of_primary_shards
(主分片的數量)後得到 餘數 。這個分佈在 0
到 number_of_primary_shards-1
之間的餘數,就是我們所尋求的文檔所在分片的位置。PS:之前看其他的文檔,說id是隨機字符串,當時就懷疑~~ 自動生成的 ID 是 URL-safe、 基於 Base64 編碼且長度爲20個字符的 GUID 字符串。 這些 GUID 字符串由可修改的 FlakeID 模式生成,這種模式允許多個節點並行生成唯一 ID ,且互相之間的衝突概率幾乎爲零。
所有的文檔 API( get
、 index
、 delete
、 bulk
、 update
以及 mget
)都接受一個叫做 routing
的路由參數 ,通過這個參數我們可以自定義文檔到分片的映射。
主分片與副分片如何交互
我們可以發送請求到集羣中的任一節點。 每個節點都有能力處理任意請求。 每個節點都知道集羣中任一文檔位置,所以可以直接將請求轉發到需要的節點上。
當發送請求的時候, 爲了擴展負載,更好的做法是輪詢集羣中所有的節點。
新建、索引和刪除文檔
新建、索引和刪除 請求都是 寫 操作, 必須在主分片上面完成之後才能被複制到相關的副本分片
以下是在主副分片和任何副本分片上面 成功新建,索引和刪除文檔所需要的步驟順序:
- 客戶端向
Node 1
發送新建、索引或者刪除請求。 - 節點使用文檔的
_id
確定文檔屬於分片 0 。請求會被轉發到Node 3`,因爲分片 0 的主分片目前被分配在 `Node 3
上。 Node 3
在主分片上面執行請求。如果成功了,它將請求並行轉發到Node 1
和Node 2
的副本分片上。一旦所有的副本分片都報告成功,Node 3
將向協調節點報告成功,協調節點向客戶端報告成功。
在客戶端收到成功響應時,文檔變更已經在主分片和所有副本分片執行完成,變更是安全的。
取回一個文檔
以下是從主分片或者副本分片檢索文檔的步驟順序:
1、客戶端向 Node 1
發送獲取請求。
2、節點使用文檔的 _id
來確定文檔屬於分片 0
。分片 0
的副本分片存在於所有的三個節點上。 在這種情況下,它將請求轉發到 Node 2
。
3、Node 2
將文檔返回給 Node 1
,然後將文檔返回給客戶端。
在處理讀取請求時,協調結點在每次請求的時候都會通過輪詢所有的副本分片來達到負載均衡。
在文檔被檢索時,已經被索引的文檔可能已經存在於主分片上但是還沒有複製到副本分片。 在這種情況下,副本分片可能會報告文檔不存在,但是主分片可能成功返回文檔。 一旦索引請求成功返回給用戶,文檔在主分片和副本分片都是可用的。
局部更新文檔
- 客戶端向
Node 1
發送更新請求。 - 它將請求轉發到主分片所在的
Node 3
。 Node 3
從主分片檢索文檔,修改_source
字段中的 JSON ,並且嘗試重新索引主分片的文檔。 如果文檔已經被另一個進程修改,它會重試步驟 3 ,超過retry_on_conflict
次後放棄。- 如果
Node 3
成功地更新文檔,它將新版本的文檔並行轉發到Node 1
和Node 2
上的副本分片,重新建立索引。 一旦所有副本分片都返回成功,Node 3
向協調節點也返回成功,協調節點向客戶端返回成功。
多文檔模式
- 客戶端向
Node 1
發送mget
請求。 Node 1
爲每個分片構建多文檔獲取請求,然後並行轉發這些請求到託管在每個所需的主分片或者副本分片的節點上。一旦收到所有答覆,Node 1
構建響應並將其返回給客戶端。
使用 bulk
修改多個文檔
bulk
API 按如下步驟順序執行:
- 客戶端向
Node 1
發送bulk
請求。 Node 1
爲每個節點創建一個批量請求,並將這些請求並行轉發到每個包含主分片的節點主機。- 主分片一個接一個按順序執行每個操作。當每個操作成功時,主分片並行轉發新文檔(或刪除)到副本分片,然後執行下一個操作。 一旦所有的副本分片報告所有操作成功,該節點將向協調節點報告成功,協調節點將這些響應收集整理並返回給客戶端。
bulk
API 還可以在整個批量請求的最頂層使用 consistency
參數,以及在每個請求中的元數據中使用 routing
參數。