在上一章,咱們看到了將數據放入索引而後檢索它們的全部方法。不過咱們有意略過了許多關於數據是如何在集羣中分佈和獲取的相關技術細節。這種使用和細節分離是刻意爲之的——你不須要知道數據在Elasticsearch如何分佈它就會很好的工做。html
這一章咱們深刻這些內部細節來幫助你更好的理解數據是如何在分佈式系統中存儲的。node
當你索引一個文檔,它被存儲在單獨一個主分片上。Elasticsearch是如何知道文檔屬於哪一個分片的呢?當你建立一個新文檔,它是如何知道是應該存儲在分片1仍是分片2上的呢?算法
進程不能是隨機的,由於咱們未來要檢索文檔。事實上,它根據一個簡單的算法決定:安全
shard = hash(routing) % number_of_primary_shards
複製代碼
routing
值是一個任意字符串,它默認是_id
但也能夠自定義。這個routing
字符串經過哈希函數生成一個數字,而後除以主切片的數量獲得一個餘數(remainder),餘數的範圍永遠是0到number_of_primary_shards
- 1,這個數字就是特定文檔所在的分片。網絡
這也解釋了爲何主分片的數量只能在建立索引時定義且不能修改:若是主分片的數量在將來改變了,全部先前的路由值就失效了,文檔也就永遠找不到了。異步
全部的文檔API(get、index、delete、bulk、update、mget
)都接收一個routing
參數,它用來自定義文檔到分片的映射。自定義路由值能夠確保全部相關文檔——例如屬於同一我的的文檔——被保存在同一分片上。async
爲了闡述意圖,咱們假設有三個節點的集羣。它包含一個叫作bblogs的索引並擁有兩個主分片。每一個主分片有兩個複製分片。相同的分片不會放在同一個節點上,因此咱們的集羣是這樣的:elasticsearch
咱們可以發送請求給集羣中任意一個節點。每一個節點都有能力處理任意請求。每一個節點都知道任意文檔所在的節點,因此也能夠將請求轉發到須要的節點。下面的例子中,咱們將發送全部請求給Node 1,這個節點咱們將會稱之爲請求節點(requesting node)分佈式
當咱們發送請求,最好的作法是循環經過全部節點請求,這樣能夠平衡負載。
複製代碼
新建、索引和刪除請求都是寫(write)操做,它們必須在主分片上成功完成才能複製到相關的複製分片上。函數
下面咱們羅列在主分片和複製分片上成功新建、索引或刪除一個文檔必要的順序步驟:
1.客戶端給Node 1發送新建、索引或刪除請求。
2.節點使用文檔的_id肯定文檔屬於分片0。它轉發請求到Node 3,分片0位於這個節點上。
3.Node 3在主分片上執行請求,若是成功,它轉發請求到相應的位於Node1和Node2的複製節點上。當全部的複製節點報告成功,Node3報告成功到請求的節點,請求的節點再報告給客戶端。
客戶端接收到成功響應的時候,文檔的修改已經被應用於主分片和全部的複製分片。你的修改生效了。
有不少可選的請求參數容許你更改這一過程。你可能想犧牲一些安全來提升性能。這一選項不多使用由於Elasticsearch已經足夠快,不過爲了內容的完整咱們將作一些闡述。
replication
複製默認的值是sync
。這將致使主分片獲得複製分片的成功響應後才返回。
若是你設置replication
爲async
,請求在主分片上被執行後就會返回給客戶端。它依舊會轉發請求給複製節點,但你將不知道複製節點成功與否。
上面的這個選項不建議使用。默認的sync
複製容許Elasticsearch強制反饋傳輸。async
複製可能會由於在不等待其它分片就緒的狀況下發送過多的請求而使Elasticsearch過載。
consistency
默認主分片在嘗試寫入時須要規定數量(quorum)或過半的分片(能夠是主節點或複製節點)可用。這是防止數據被寫入到錯的網絡分區。規定的數量計算公式以下:
int( (primary + number_of_replicas) / 2 ) + 1
複製代碼
consistency
容許的值爲one
(只有一個主分片),all
(全部主分片和複製分片)或者默認的quorum
或過半分片。
注意number_of_replicas
是在索引中的的設置,用來定義複製分片的數量,而不是如今活動的複製節點的數量。若是你定義了索引有3個複製節點,那規定數量是:
int( (primary + 3 replicas) / 2 ) + 1 = 3
複製代碼
但若是你只有2個節點,那你的活動分片不夠規定數量,也就不能索引或刪除任何文檔。
timeout
當分片副本不足時會怎樣?Elasticsearch會等待更多的分片出現。默認等待一分鐘。若是須要,你能夠設置timeout參數讓它終止的更早:100表示100毫秒,30s表示30秒。
注意:
新索引默認有1個複製分片,這意味着爲了知足quorum的要求須要兩個活動的分片。固然,這個默認設置將阻止咱們在單一節點集羣中進行操做。爲了避開這個問題,規定數量只有在`number_of_replicas`大於一時才生效。
複製代碼
文檔可以從主分片或任意一個複製分片被檢索。
下面咱們羅列在主分片或複製分片上檢索一個文檔必要的順序步驟:
1.客戶端給Node 1發送get請求。
2.節點使用文檔的_id肯定文檔屬於分片0。分片0對應的複製分片在三個節點上都有。此時,它轉發請求到Node 2。
3.Node 2返回文檔(document)給Node 1而後返回給客戶端。
對於讀請求,爲了平衡負載,請求節點會爲每一個請求選擇不一樣的分片——它會循環全部分片副本。
可能的狀況是,一個被索引的文檔已經存在於主分片上卻還沒來得及同步到複製分片上。這時複製分片會報告文檔未找到,主分片會成功返回文檔。一旦索引請求成功返回給用戶,文檔則在主分片和複製分片都是可用的。
update API 結合了以前提到的讀和寫的模式。
下面咱們羅列執行局部更新必要的順序步驟:
1.客戶端給Node 1發送更新請求。
2.它轉發請求到主分片所在節點Node 3。
3.Node 3從主分片檢索出文檔,修改_source字段的JSON,而後在主分片上重建索引。若是有其餘進程修改了文檔,它以retry_on_conflict設置的次數重複步驟3,都未成功則放棄。
4.若是Node 3成功更新文檔,它同時轉發文檔的新版本到Node1和Node2上的複製節點以重建索引。當全部複製節點報告成功,Node3返回成功給請求節點,而後返回給客戶端。
update API
還接受《新建、索引和刪除》章節提到的routing
、replication
、consistency
和timout
參數。
基於文檔的複製
當主分片轉發更改給複製分片時,並非轉發更新請求,而是轉發整個文檔的新版本。記住這些修改轉發到複製節點是異步的,它們並不能保證到達的順序與發送相同。若是Elasticsearch轉發的僅僅是修改請求,修改的順序多是錯誤的,那獲得的就是個損壞的文檔。
複製代碼
mget
和bulk API
與單獨的文檔相似。差異是請求節點知道每一個文檔所在的分片。它把多文檔請求拆成每一個分片的對文檔請求,而後轉發每一個參與的節點。
一旦接收到每一個節點的應答,而後整理這些響應組合爲一個單獨的響應,最後返回給客戶端。
下面咱們將羅列經過一個mget
請求檢索多個文檔的順序步驟:
1.客戶端向Node 1發送mget請求。
2.Node 1爲每一個分片構建一個多條數據檢索請求,而後轉發到這些請求所需的主分片或複製分片上。當全部回覆被接收,Node 1構建響應並返回給客戶端。
routing
參數能夠被docs中的每一個文檔設置。
下面咱們將羅列使用一個bulk
執行多個create、index、delete和update
請求的順序步驟:
1.客戶端向Node 1發送bulk請求。
2.Node 1爲每一個分片構建批量請求,而後轉發到這些請求所需的主分片上。
3.主分片一個接一個的按序執行操做。當一個操做執行完,主分片轉發新文檔(或者刪除部分)給對應的複製節點,而後執行下一個操做。一旦全部複製節點報告全部操做已成功完成,節點就報告success給請求節點,後者(請求節點)整理響應並返回給客戶端。
bulk API
還能夠在最上層使用replication
和consistency
參數,routing
參數則在每一個請求的元數據中使用。