《一起學(xué)mongodb》之第三卷分片集群
前言
上一篇介紹了 mongo 的三種部署方式,「單點(diǎn)、主從、副本集」三種部署方式,今天就跟大家聊聊最后一種「分片集群」的方式,分片集群也是 mongo 能夠作為萬(wàn)億級(jí)別數(shù)據(jù)庫(kù)的核心魅力所在,也有一句話說(shuō)到:
「連分片集群都不知道,你還好意思說(shuō)自己用過 mongo ?」
分片集群架構(gòu)
其他的不多說(shuō),我們先甩一張分片集群的架構(gòu)圖
在分片集群當(dāng)中,一共有以下三種角色
- mongos:路由層,主要用來(lái)處理客戶端的請(qǐng)求,連接客戶端與 shard
- config server:主要用來(lái)存儲(chǔ)分片集群的元數(shù)據(jù)和配置信息
- shard:每個(gè) Shard 就相當(dāng)于一個(gè) mongod 數(shù)據(jù)庫(kù)實(shí)例,用于存儲(chǔ)數(shù)據(jù),整個(gè)數(shù)據(jù)庫(kù)會(huì)「分散在不同的 shard 當(dāng)中」,每一個(gè)分片都滿足高可用,一般都是一主二從(建議部署位副本集架構(gòu)),分片的個(gè)數(shù)最大可以到1024個(gè)
一個(gè)集群包含了多個(gè)分片組成,而一個(gè)分片又存儲(chǔ)了多個(gè)塊(每個(gè)塊包含一定范圍片鍵的數(shù)據(jù),互不相交且并集為全部數(shù)據(jù)),一個(gè)塊當(dāng)中包含了多個(gè)文檔。
那么問題來(lái)了-
mongoDB 是怎么做數(shù)據(jù)分片的?
mongo 提供了「三種方式來(lái)做數(shù)據(jù)分片」
哈希分片
這是很多技術(shù)最常用的一種方式,就是將數(shù)據(jù)通過 hash 散列化,打在不同的機(jī)器上,實(shí)現(xiàn)「均勻分布」,但是它很大的問題就是「數(shù)據(jù)不連續(xù)」,比如業(yè)務(wù)需要查詢工資在 10000~20000 之間的人員,你可能就需要遍歷每一個(gè)分片了
范圍分片
這種策略直接根據(jù)片鍵的范圍確定分片。
比如現(xiàn)在我們將數(shù)據(jù)在邏輯上分為四個(gè)塊。
在數(shù)據(jù)上數(shù)據(jù) 工資 0~5000一個(gè)塊,5000~10000 一個(gè)塊,10000~15000 一個(gè)塊,15000~20000 一個(gè)塊,20000~25000 一個(gè)塊,25000 以上一個(gè)塊,由于公司人員薪資分布大概率都在 5000~15000,這個(gè)區(qū)域內(nèi),就會(huì)造成數(shù)據(jù)過分集中在 5000~10000 、10000~15000 這兩個(gè)塊兒中,造成「數(shù)據(jù)分布不均勻」,但是再做「范圍查詢的時(shí)候效率就會(huì)很高」
zone 分片
簡(jiǎn)單來(lái)說(shuō) Zone 實(shí)際上像是范圍分片的另一個(gè)版本,你為一定范圍內(nèi)的片鍵制定一個(gè) Zone,然后再將一些分片加入到這個(gè)Zone中,于是這一范圍內(nèi)的數(shù)據(jù)最終就將存儲(chǔ)在這個(gè) Zone 中的分片上。
Chunk(塊) 分裂
隨著數(shù)據(jù)慢慢的寫入,數(shù)據(jù)量越來(lái)越大,當(dāng) Chunk 增長(zhǎng)到指定大小(默認(rèn)為 64MB)時(shí),MongoDB 會(huì) 對(duì) Chunk 進(jìn)行分裂。
Chunk 分裂的?式
- ?動(dòng)觸發(fā)
- ?動(dòng)觸發(fā):當(dāng)發(fā)生插?和更新操作才會(huì)觸發(fā)?動(dòng)塊分裂。
JumboChunk 是一個(gè)最小的 Chunk 可以「只包含一個(gè)唯一的 ShardKey」,這樣的 Chunk 不可以再進(jìn)行分裂。
那么如果數(shù)據(jù)分片不均 mongoDB 是怎么做的?
這個(gè)時(shí)候就要說(shuō)到我們的 「balancer(平衡器)」 了,用來(lái)「保證集合的 Chunk 在各個(gè) Shard 上是均衡的」。
當(dāng)某些分片數(shù)據(jù)不均勻的情況下,balancer 會(huì)發(fā)出一個(gè)命令讓切割器去需要移動(dòng)的分片上去做數(shù)據(jù)切割,再把數(shù)據(jù)移動(dòng)到數(shù)據(jù)少的分片上。具體的步驟如下:
- 平衡器向源分片發(fā)送 moveChunk 的命令
- 源分片收到命令后,會(huì)啟動(dòng)自己內(nèi)部的一個(gè) moveChunk 命令,如果在數(shù)據(jù)移動(dòng)過程中有客戶端發(fā)來(lái)讀寫請(qǐng)求的話,都會(huì)發(fā)送到源分片。
- 目標(biāo)片開始向源分片請(qǐng)求將要移動(dòng)的數(shù)據(jù)塊的文檔,準(zhǔn)備拷貝文檔數(shù)據(jù)。
- 當(dāng)目標(biāo)分片接收到據(jù)塊的最后一個(gè)文檔后,目標(biāo)分片會(huì)啟動(dòng)一個(gè)同步進(jìn)程來(lái)檢查,是否已經(jīng)拷貝完全部的文檔。
- 當(dāng)同步完成后,目標(biāo)分片會(huì)連接配置服務(wù)器,更新元數(shù)據(jù)列表中數(shù)據(jù)塊的地址。
- 當(dāng)目標(biāo)分片完成元數(shù)據(jù)更新后,源分片就會(huì)刪除原來(lái)的數(shù)據(jù)塊.如果有新的數(shù)據(jù)塊需要移動(dòng)的話,可以繼續(xù)進(jìn)行移動(dòng)。
- 配置服務(wù)器會(huì)通知 monogs 進(jìn)程更新自己的映射表。
遷移過程對(duì)于應(yīng)用是透明的,但由于「遷移過程會(huì)占用相應(yīng)節(jié)點(diǎn)的 CPU 和帶寬資源」,因此對(duì)分片集有一定程度的性能影響,并且對(duì)運(yùn)維操作存在一些限制。
在對(duì)集合進(jìn)行分片后是否可以更改片鍵?
「不可以」
MongoDB 中沒有對(duì)集合分片后更改片鍵的自動(dòng)支持。如果在集合分片后必須更改片鍵,可以按如下方式操作:
- 將MongoDB中的所有數(shù)據(jù)轉(zhuǎn)儲(chǔ)為外部格式,比如可以先放在 mysql 中。
- 刪除原始分片集合。
- 使用新的的片鍵配置分片。
- 預(yù)分割片鍵范圍以確保初始均勻分布。
- 將轉(zhuǎn)儲(chǔ)的數(shù)據(jù)恢復(fù)到 MongoDB 中。
mongos 是如何處理連接的?
每個(gè) mongos 實(shí)例都「維護(hù)一個(gè)與分片集群成員的連接池」。客戶端「一次請(qǐng)求就會(huì)占用一個(gè)連接」,客戶端請(qǐng)求完成后,連接釋放。但是客戶端數(shù)量減少時(shí),這些池不會(huì)收縮。這可能導(dǎo)致未使用的mongos占用大量打開的連接。如果 mongos 不再使用,則可以安全地重新啟動(dòng)進(jìn)程以關(guān)閉現(xiàn)有連接。
總結(jié)
今天的內(nèi)容只講了分片集群相關(guān)的,當(dāng)你看完了以上內(nèi)容時(shí),再來(lái)看看以下幾個(gè)問題,「mongoDB 分片集群架構(gòu)是怎么樣的?有哪三種分片方式?塊分裂是什么?為什么會(huì)有塊分裂?分片之間的負(fù)載均衡是怎么做的?如何修改分片鍵?mongos 如何管理與分片之間的連接?」
你都會(huì)了嗎?