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