問題:當(dāng)我們要在 ES 中存儲(chǔ)數(shù)據(jù)的時(shí)候,數(shù)據(jù)應(yīng)該存儲(chǔ)在主分片和復(fù)制分片中的哪一個(gè)中去;當(dāng)我們?cè)? ES 中檢索數(shù)據(jù)的時(shí)候,又是怎么判斷要查詢的數(shù)據(jù)是屬于哪一個(gè)分片。
?
- 數(shù)據(jù)存儲(chǔ)到分片的過程是一定規(guī)則的,并不是隨機(jī)發(fā)生的。
?
- 規(guī)則: shard?=?hash(routing)?%?number_of_primary_shards
?
- Routing 值可以是一個(gè)任意的字符串,默認(rèn)情況下,它的值為存數(shù)數(shù)據(jù)對(duì)應(yīng)文檔? _id? 值,也可以是用戶自定義的值。 Routing 這個(gè)字符串通過一個(gè) hash 的函數(shù)處理,并返回一個(gè)數(shù)值,然后再除以索引中主分片的數(shù)目,所得的余數(shù)作為主分片的編號(hào),取值一般在 0 到 number_of_primary_shards?-?1 的這個(gè)范圍中。通過這種方法計(jì)算出該數(shù)據(jù)是存儲(chǔ)到哪個(gè)分片中。
?
- 正是這種路由機(jī)制,導(dǎo)致了主分片的個(gè)數(shù)為什么在索引建立之后不能修改。對(duì)已有索引主分片數(shù)目的修改直接會(huì)導(dǎo)致路由規(guī)則出現(xiàn)嚴(yán)重問題,部分?jǐn)?shù)據(jù)將無法被檢索。
?
2 、主分片與復(fù)制分片如何交互
為了說明這個(gè)問題,我用一個(gè)例子來說明。
?
在上面這個(gè)例子中,有三個(gè)ES 的 node ,其中每一個(gè) index 中包含兩個(gè) primary?shard ,每個(gè) primary?shard 擁有一個(gè) replica?shard 。下面從幾種常見的數(shù)據(jù)操作來說明二者之間的交互情況。
?
- 索引與刪除一個(gè)文檔
?
?
這兩種過程均可以分為三個(gè)過程來描述:
階段 1 :客戶端發(fā)送了一個(gè)索引或者刪除的請(qǐng)求給 node?1 。
?
階段 2 : node?1 通過請(qǐng)求中文檔的? _id? 值判斷出該文檔應(yīng)該被存儲(chǔ)在 shard?0? 這個(gè)分片中,并且 node?1 知道 shard?0 的 primary?shard 位于 node?3 這個(gè)節(jié)點(diǎn)上。因此 node?1 會(huì)把這個(gè)請(qǐng)求轉(zhuǎn)發(fā)到 node?3 。
?
階段 3 : node?3 在 shard?0? 的 primary?shard 上執(zhí)行請(qǐng)求。如果請(qǐng)求執(zhí)行成功,它 node?3 將并行地將該請(qǐng)求發(fā)給 shard?0 的其余所有 replica?shard 上,也就是存在于 node?1 和 node?2 中的 replica?shard 。如果所有的 replica?shard 都成功地執(zhí)行了請(qǐng)求,那么將會(huì)向 node?3 回復(fù)一個(gè)成功確認(rèn),當(dāng) node?3 收到了所有 replica?shard 的確認(rèn)信息后,則最后向用戶返回一個(gè) Success 的消息。
?
- 更新一個(gè)文檔
?
?
該過程可以分為四個(gè)階段來描述:
階段 1 :客戶端向 node?1 發(fā)送一個(gè)文檔更新的請(qǐng)求。
?
階段 2 :同樣的 node?1 通過請(qǐng)求中文檔的? _id? 值判斷出該文檔應(yīng)該被存儲(chǔ)在 shard?0? 這個(gè)分片中,并且 node?1 知道 shard?0 的 primary?shard 位于 node?3 這個(gè)節(jié)點(diǎn)上。因此 node?1 會(huì)把這個(gè)請(qǐng)求轉(zhuǎn)發(fā)到 node?3 。
?
階段 3 : node?3 從文檔所在的 primary?shard 中獲取到它的 JSON 文件,并修改其中的 _source 中的內(nèi)容,之后再重新索引該文檔到其 primary?shard 中。
?
階段 4 :如果 node?3 成功地更新了文檔, node?3 將會(huì)把文檔新的版本并行地發(fā)給其余所有的 replica?shard 所在 node 中。這些 node 也同樣重新索引新版本的文檔,執(zhí)行后則向 node?3 確認(rèn)成功,當(dāng) node?3 接收到所有的成功確認(rèn)之后,再向客戶端發(fā)送一個(gè)更新成功的信息。
?
?
- 檢索文檔
CRUD 這些操作的過程中一般都是結(jié)合一些唯一的標(biāo)記例如: _index , _type ,以及 routing 的值,這就意味在執(zhí)行操作的時(shí)候都是確切的知道文檔在集群中的哪個(gè) node 中,哪個(gè) shard 中。
而檢索過程往往需要更多的執(zhí)行模式,因?yàn)槲覀儾⒉磺宄獧z索的文檔具體位置所在,?它們可能存在于 ES 集群中個(gè)任何位置。因此,一般情況下,檢索的執(zhí)行不得不去詢問 index 中的每一個(gè) shard 。
但是,找到所有匹配檢索的文檔僅僅只是檢索過程的一半,在向客戶端返回一個(gè)結(jié)果列表之前,必須將各個(gè) shard 發(fā)回的小片的檢索結(jié)果,拼接成一個(gè)大的已排好序的匯總結(jié)果列表。正因?yàn)檫@個(gè)原因,檢索的過程將分為查詢階段與獲取階段( Query?Phase?and?Fetch?Phase )。
?
- Query?Phase
在最初的查詢過程中,查詢請(qǐng)求會(huì)廣播到 index 中的每一個(gè) primary?shard 和 replica?shard 中,每一個(gè) shard 會(huì)在本地執(zhí)行檢索,并建立一個(gè)優(yōu)先級(jí)隊(duì)列( priority?queue )。這個(gè)優(yōu)先級(jí)隊(duì)列是一個(gè)根據(jù)文檔匹配度這個(gè)指標(biāo)所排序列表,列表的長度由分頁參數(shù) from 和 size 兩個(gè)參數(shù)所決定。例如:
?
?
下面從一個(gè)例子中說明這個(gè)過程:
?
Query?Phase 階段可以再細(xì)分成 3 個(gè)小的子階段:
子階段 1 :客戶端發(fā)送一個(gè)檢索的請(qǐng)求給 node?3 ,此時(shí) node?3 會(huì)創(chuàng)建一個(gè)空的優(yōu)先級(jí)隊(duì)列并且配置好分頁參數(shù) from 與 size 。
?
子階段 2 : node?3 將檢索請(qǐng)求發(fā)送給該 index 中個(gè)每一個(gè) shard (這里的每一個(gè)意思是無論它是 primary 還是 replica ,它們的組合可以構(gòu)成一個(gè)完整的 index 數(shù)據(jù))。每個(gè) shard 在本地執(zhí)行檢索,并將結(jié)果添加到本地優(yōu)先級(jí)隊(duì)列中。
?
子階段 3 :每個(gè) shard 返回本地優(yōu)先級(jí)序列中所記錄的 _id 與 sort 值,并發(fā)送 node?3 。 Node?3 將這些值合并到自己的本地的優(yōu)先級(jí)隊(duì)列中,并做全局的排序。
?
- Fetch?Phase
Query?Phase 主要定位了所要檢索數(shù)據(jù)的具體位置,但是我們還必須取回它們才能完成整個(gè)檢索過程。而 Fetch?Phase 階段的任務(wù)就是將這些定位好的數(shù)據(jù)內(nèi)容取回并返回給客戶端。
?
同樣也用一個(gè)例子來說明這個(gè)過程:
?
Fetch?Phase 過程可以分為三個(gè)子過程來描述:
子階段 1 : node?3 獲取了所有待檢索數(shù)據(jù)的定位之后,發(fā)送一個(gè) mget 的請(qǐng)求給與數(shù)據(jù)相關(guān)的 shard 。
?
子階段 2 :每個(gè)收到 node?3 的 get 請(qǐng)求的 shard 將讀取相關(guān)文檔 _source 中的內(nèi)容,并將它們返回給 node?3 。
?
子階段 3 :當(dāng) node?3 獲取到了所有 shard 返回的文檔后, node?3 將它們合并成一條匯總的結(jié)果,返回給客戶端。
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
