分片是MongoDB的擴展方式,通過分片能夠增加更多的機器來用對不斷增加的負載和數(shù)據(jù),還不影響應用.
1.分片簡介
分片是指將數(shù)據(jù)拆分,將其分散存在不同機器上的過程.有時也叫分區(qū).將數(shù)據(jù)分散在不同的機器上,不需要功能
強大的大型計算機就可以存儲更多的數(shù)據(jù),處理更大的負載.
使用幾乎所有數(shù)據(jù)庫軟件都能進行手動分片,應用需要維護與若干不同數(shù)據(jù)庫服務器的連接,每個連接還是完全
獨立的.應用程序管理不同服務器上的不同數(shù)據(jù),存儲查村都需要在正確的服務器上進行.這種方法可以很好的工作,但是也
難以維護,比如向集群添加節(jié)點或從集群刪除節(jié)點都很困難,調(diào)整數(shù)據(jù)分布和負載模式也不輕松.
MongoDB支持自動分片,可以擺脫手動分片的管理.集群自動切分數(shù)據(jù),做負載均衡.
2.MongoDB的自動分片
MongoDB分片的基本思想就是將集合切分成小塊.這些塊分散到若干片里面,每個片只負責總數(shù)據(jù)的一部分.應用程序不必知道
哪片對應哪些數(shù)據(jù),甚至不需要知道數(shù)據(jù)已經(jīng)被拆分了,所以在分片之前要運行一個路由進程,進程名mongos,這個路由器知道
所有數(shù)據(jù)的存放位置,所以應用可以連接它來正常發(fā)送請求.對應用來說,它僅知道連接了一個普通的mongod.路由器知道和片的
對應關(guān)系,能夠轉(zhuǎn)發(fā)請求到正確的片上.如果請求有了回應,路由器將其收集起來回送給應用.
在沒有分片的時候,客戶端連接mongod進程,分片時客戶端會連接mongos進程.mongos對應用隱藏了分片的細節(jié).
從應用的角度看,分片和不分片沒有區(qū)別.所以需要擴展的時候,不必修改應用程序的代碼.
不分片的客戶端連接:
分片的客戶端連接:
什么時候需要分片:
a.機器的磁盤不夠用了
b.單個mongod已經(jīng)不能滿足些數(shù)據(jù)的性能需要了
c.想將大量數(shù)據(jù)放在內(nèi)存中提高性能
一般來說,先要從不分片開始,然后在需要的時候?qū)⑵滢D(zhuǎn)換成分片.
3.片鍵
設(shè)置分片時,需要從集合里面選一個鍵,用該鍵的值作為數(shù)據(jù)拆分的依據(jù).這個鍵成為片鍵.
假設(shè)有個文檔集合表示的是人員,如果選擇名字"name"做為片鍵,第一篇可能會存放名字以A-F開頭的文檔.
第二片存G-P開頭的文檔,第三篇存Q-Z的文檔.隨著增加或刪除片,MongoDB會重新平衡數(shù)據(jù),是每片的流量比較
均衡,數(shù)據(jù)量也在合理范圍內(nèi)(如流量較大的片存放的數(shù)據(jù)或許會比流量下的片數(shù)據(jù)要少些)
4.將已有的集合分片
假設(shè)有個存儲日志的集合,現(xiàn)在要分片.我們開啟分片功能,然后告訴MongoDB用"timestamp"作為片鍵,就要所有數(shù)據(jù)放到
了一個片上.可以隨意插入數(shù)據(jù),但總會是在一個片上.
然后,新增一個片.這個片建好并運行了以后,MongoDB就會把集合拆分成兩半,成為塊.每個塊中包含片鍵值在一定
范圍內(nèi)的所有文檔,假設(shè)其中一塊包含時間戳在2011.11.11前的文檔,則另一塊含有2011.11.11以后的文檔.其中
一塊會被移動到新片上.如果新文檔的時間戳在2011.11.11之前,則添加到第一塊,否則添加到第二塊.
5.遞增片鍵還是隨機片鍵
片鍵的選擇決定了插入操作在片之間的分布.
如果選擇了像"timestamp"這樣的鍵,這個值可能不斷增長,而且沒有太大的間斷,就會將所有數(shù)據(jù)發(fā)送到一個片上
(含有2011.11.11以后日期的那片).如果有添加了新片,再拆分數(shù)據(jù),還是會都導入到一臺服務器上.添加了新片,
MongoDB肯能會將2011.11.11以后的拆分成2011.11.11-2021.11.11.如果文檔的時間大于2021.11.11以后,
所有的文檔還會以最后一片插入.這就不適合寫入負載很高情況,但按照片鍵查詢會非常高效.
如果寫入負載比較高,想均勻分散負載到各個片,就得選擇分布均勻的片鍵.日志例子中時間戳的散列值,沒有模式的"logMessage"
都是復合這個條件的.
不論片鍵隨機跳躍還是穩(wěn)定增加,片鍵的變化很重要.如,如果有個"logLevel"鍵的值只有3種值"DEBUG","WARN","ERROR",
MongoDB無論如何也不能把它作為片鍵將數(shù)據(jù)分成多于3片(因為只有3個值).如果鍵的變化太少,但又想讓其作為片鍵,
可以把這個鍵與一個變化較大的鍵組合起來,創(chuàng)建一個復合片鍵,如"logLevel"和"timestamp"組合.
選擇片鍵并創(chuàng)建片鍵很像索引,以為二者原理相似.事實上,片鍵也是最常用的索引.
6.片鍵對操作的影響
最終用戶應該無法區(qū)分是否分片,但是要了解選擇不同片鍵情況下的查詢有何不同.
假設(shè)還是那個表示人員的集合,按照"name"分片,有3個片,其名字首字母的范圍是A-Z.下面以不同的方式查詢:
db.people.find({"name":"Refactor"})
mongos會將這個查詢直接發(fā)送給Q-Z片,獲得響應后,直接轉(zhuǎn)發(fā)給客戶端
db.people.find({"name":{"$lt":"L"}})
mongos會將其先發(fā)送給A-F和G-P片,然后將結(jié)果轉(zhuǎn)發(fā)給客戶端.
db.people.find().sort({"email":1})
mongos會在所有片上查詢,返回結(jié)果時還會做歸并排序,確保結(jié)果順序正確.
mongos用游標從各個服務器上獲取數(shù)據(jù),所以不必等到全部數(shù)據(jù)都拿到才向客戶端發(fā)送批量結(jié)果.
db.people.find({"email":re@msn.cn})
mongos并不追蹤"email"鍵,所以也不知道應該將查詢發(fā)給那個片.所以他就向所有片順序發(fā)送查詢.
如果是插入文檔,mongos會依據(jù)"name"鍵的值,將其發(fā)送到相應的片上.
7.建立分片
建立分片有兩步:啟動實際的服務器,然后決定怎么切分數(shù)據(jù).
分片一般會有3個組成部分:
a.片
片就是保存子集合數(shù)據(jù)的容器,片可是單個的mongod服務器(開發(fā)和測試用),也可以是副本集(生產(chǎn)用).所以一片
有多臺服務器,也只能有一個主服務器,其他的服務器保存相同的數(shù)據(jù).
b.mongos
mongos就是MongoDB配的路由器進程.它路由所有的請求,然后將結(jié)果聚合.它本身并不存儲數(shù)據(jù)或者配置信息
但會緩存配置服務器的信息.
c.配置服務器
配置服務器存儲了集群的配置信息:數(shù)據(jù)和片的對應關(guān)系.mongos不永久存房數(shù)據(jù),所以需要個地方存放分片的配置.
它會從配置服務器獲取同步數(shù)據(jù).
8.啟動服務器
首先要啟動配置服務器和mongos.配置服務器需要先啟動.因為mongos會用到其上的配置信息.
配置服務器的啟動就像普通的mongod一樣
mongod --dbpath "F:\mongo\dbs\config" --port 20000 --logpath "F:\mongo\logs\config\MongoDB.txt" --rest
配置服務器不需要很多的空間和資源(200M實際數(shù)據(jù)大約占用1kB的配置空間)
建立mongos進程,一共應用程序連接.這種路由服務器連接數(shù)據(jù)目錄都不需要,但一定要指明配置服務器的位置:
mongos --port 30000 --configdb 127.0.0.1:20000 --logpath "F:\mongo\logs\mongos\MongoDB.txt"
分片管理通常是通過mongos完成的.
添加片
片就是普通的mongod實例(或副本集)
mongod --dbpath "F:\mongo\dbs\shard" --port 10000 --logpath "F:\mongo\logs\shard\MongoDB.txt" --rest
mongod --dbpath "F:\mongo\dbs\shard1" --port 10001 --logpath "F:\mongo\logs\shard1\MongoDB.txt" --rest
連接剛才啟動的mongos,為集群添加一個片.啟動shell,連接mongos:
確定連接的是mongos而不是mongod,通過addshard命令添加片:
>mongo 127.0.0.1:30000
mongos> db.runCommand(
... {
... "addshard":"127.0.0.1:10000",
... "allowLocal":true
... }
... )
Sat Jul 21 10:46:38 uncaught exception: error { "$err" : "can't find a shard to
put new db on", "code" : 10185 }
mongos> use admin
switched to db admin
mongos> db.runCommand(
... {
... "addshard":"127.0.0.1:10000",
... "allowLocal":1
... }
... )
{ "shardAdded" : "shard0000", "ok" : 1 }
mongos> db.runCommand(
... {
... "addshard":"127.0.0.1:10001",
... "allowLocal":1
... }
... )
{ "shardAdded" : "shard0001", "ok" : 1 }
當在本機運行片的時候,得設(shè)定allowLocal鍵為1.MongoDB盡量避免由于錯誤的配置,將集群配置到本地,
所以得讓它知道這僅僅是開發(fā),而且我們很清楚自己在做什么.如果是生產(chǎn)環(huán)境中,則要將其部署在不同的機器上.
想添加片的時候,就運行addshard.MongoDB會負責將片集成到集群.
切分數(shù)據(jù)
MongoDB不會將存儲的每一條數(shù)據(jù)都直接發(fā)布,得先在數(shù)據(jù)庫和集合的級別將分片功能打開.
如果是連接配置服務器,
E:\mongo\bin>mongo 127.0.0.1:20000
MongoDB shell version: 2.0.6
connecting to: 127.0.0.1:20000/test
> use admin
switched to db admin
> db.runCommand({"enablesharding":"test"})
{
"errmsg" : "no such cmd: enablesharding",
"bad cmd" : {
"enablesharding" : "test"
},
"ok" : 0
}
應該是連接 路由服務器:
db.runCommand({"enablesharding":"test"})//將test數(shù)據(jù)庫啟用分片功能.
對數(shù)據(jù)庫分片后,其內(nèi)部的集合便會存儲到不同的片上,同時也是對這些集合分片的前置條件.
在數(shù)據(jù)庫級別啟用了分片以后,就可以使用shardcollection命令堆積和進行分片:
db.runCommand({"shardcollection":"test.refactor","key":{"name":1}})//對test數(shù)據(jù)庫的refactor集合進行分片,片鍵是name
如果現(xiàn)在對refactor集合添加數(shù)據(jù),就會依據(jù)"name"的值自動分散到各個片上.
9.生產(chǎn)配置
進入生產(chǎn)環(huán)境后,需要更健壯的分片方案,成功的構(gòu)建分片需要如下條件:
多個配置服務器
多個mongos服務器
每個片都是副本集
正確的設(shè)置w
健壯的配置
設(shè)置多個配置服務器是很簡單的.
設(shè)置多個配置服務器和設(shè)置一個配置服務器一樣
mongod --dbpath "F:\mongo\dbs\config" --port 20000 --logpath "F:\mongo\logs\config\MongoDB.txt" --rest
mongod --dbpath "F:\mongo\dbs\config1" --port 20001 --logpath "F:\mongo\logs\config1\MongoDB.txt" --rest
mongod --dbpath "F:\mongo\dbs\config2" --port 20002 --logpath "F:\mongo\logs\config2\MongoDB.txt" --rest
啟動mongos的時候應將其連接到3個配置服務器上:
mongos --port 30000 --configdb 127.0.0.1:20000,127.0.0.1:20001,127.0.0.1:20002 --logpath "F:\mongo\logs\mongos\MongoDB.txt"
配置服務器使用的是兩步提交機制,而不是普通的MongoDB的異步復制,來維護集群配置的不同副本.這樣能保證集群的狀態(tài)
的一致性.這意味著,某臺配置服務器宕機后,集群的配置信息是只讀的.客戶端還是能夠讀寫,但是只有所有配置服務器備份了
以后才能重新均衡數(shù)據(jù).
多個mongos
mongos的數(shù)量不受限制,建議針對一個應用服務器只運行一個mongos進程.這樣每個應用服務器就可以與mongos進行
本地回話,如果服務器不工作了,就不會有應用試圖與不存的mongos通話了
健壯的片
生產(chǎn)環(huán)境中,每個片都應是副本集,這樣單個服務器壞了,就不會導致整個片失效.用addshard命令就可以將副本集作為片添加,
添加時,只要指定副本集的名稱和種子就行了.
如要添加副本集refactor,其中包含一個服務器127.0.0.1:10000(還有別的服務器),就可以用下列命令將其添加到集群中:
db.runCommand({"addshard":"refactor/127.0.0.1:10000"})
如果127.0.0.1:10000服務器掛了,mongos會知道它所連接的是一個副本集,并會使用新的主節(jié)點.
10.管理分片
分片信息主要存放在config數(shù)據(jù)庫上,這樣就能被任何連接到mongos的進程訪問到了.
配置集合
在shell中連接了mongos,并使用了use config數(shù)據(jù)庫
a.片
可以在shareds集合中查到所有的片
b.數(shù)據(jù)庫
databases集合含有已經(jīng)包含在片上的數(shù)據(jù)庫列表和一些相關(guān)信息
返回的文檔解釋:
"_id"
表示數(shù)據(jù)庫名
"partitioned"
表示是否啟用了分片功能
"primary"
這個值與"_id"相對應,表名這個數(shù)據(jù)的"大本營"在哪里.不論分片與否,數(shù)據(jù)庫總會有個大本營.要是分片的話,創(chuàng)建數(shù)據(jù)庫時會
隨機選擇一個片.也就是說,大本營是開始創(chuàng)建數(shù)據(jù)庫文檔的位置.雖然分片時數(shù)據(jù)庫也會用到很多別的服務器,但會從這個片開始.
c.塊
塊信息存儲在chunks集合中.這可以看到數(shù)據(jù)到底是怎么切分到集群中的
分片命令
獲得概要
刪除片
用removeshard就能從集群中刪除片.removeshard會把給定片上的所有塊的數(shù)據(jù)都挪到其他片上
db.runCommand({"removeshard":"127.0.0.1:10001"})
在挪動過程中,removeshard會顯示進程
您可能感興趣的文章:- 如何為MongoDB添加分片副本集
- 分布式文檔存儲數(shù)據(jù)庫之MongoDB分片集群的問題
- MongoDB搭建高可用集群的完整步驟(3個分片+3個副本)
- Mongodb副本集和分片示例詳解
- MongoDB分片集群部署詳解
- MongoDB分片在部署與維護管理中常見的事項總結(jié)大全
- 詳解MongoDB4.0構(gòu)建分布式分片群集
- MongoDB分片鍵的選擇和案例實例詳解
- mongodb分片技術(shù)_動力節(jié)點Java學院整理
- mongodb3.4集群搭建實戰(zhàn)之高可用的分片+副本集
- 深入理解MongoDB分片的管理
- Mongodb 刪除添加分片與非分片表維護
- MongoDB 主分片(primary shard)相關(guān)總結(jié)