MongoDB/分片

分片機(jī)制:
分片的機(jī)制:一開(kāi)始插入數(shù)據(jù)時(shí),數(shù)據(jù)是只插入到其中一塊分片上的,插入完畢后,mongodb內(nèi)部開(kāi)始在各片之間進(jìn)行數(shù)據(jù)的移動(dòng),這個(gè)過(guò)程可能不是立即的,mongodb足夠智能會(huì)根據(jù)當(dāng)前負(fù)載決定是立即進(jìn)行移動(dòng)還是稍后移動(dòng)。這種分片機(jī)制,節(jié)省了人工維護(hù)成本,但是由于其是優(yōu)先往某個(gè)片上插入,等到chunk失衡時(shí),再移動(dòng)chunk,并且隨著數(shù)據(jù)的增多,shard的實(shí)例之間,有chunk來(lái)回移動(dòng)的現(xiàn)象,這將會(huì)為服務(wù)器帶來(lái)很大的IO開(kāi)銷(xiāo)。

分片:
啟動(dòng)Shard Server:

mkdir  usr/local/data/shard/s0 usr/local/data/shard/s1  #創(chuàng)建數(shù)據(jù)目錄
mkdir  usr/local/data/shard/log # 創(chuàng)建日志目錄
./bin/mongod --port 27017 --dbpath /usr/local/mongodb/data/shard/s0 --fork --logpath /usr/local/mongodb/data/shard/log/s0.log # 啟動(dòng)Shard Server實(shí)例1
./bin/mongod --port 27018 --dbpath /usr/local/mongodb/data/shard/s1 --fork --logpath /usr/local/mongodb/data/shard/log/s1.log # 啟動(dòng)Shard Server實(shí)例2

啟動(dòng)Config Server

mkdir -p ./data/shard/config #創(chuàng)建數(shù)據(jù)目錄
./bin/mongod --port 27027 --dbpath /usr/local/mongodb/data/shard/config --fork --logpath /usr/local/mongodb/

啟動(dòng)Route Process
mongos啟動(dòng)參數(shù)中,chunkSize這一項(xiàng)是用來(lái)指定chunk的大小的,單位是MB,默認(rèn)大小為200MB,為了方便測(cè)試Sharding效果,我們把chunkSize指定為 1MB。意思是當(dāng)這個(gè)分片中插入的數(shù)據(jù)大于1M時(shí)開(kāi)始進(jìn)行數(shù)據(jù)轉(zhuǎn)移

./bin/mongos --port 4000 --configdb localhost:27027 --fork --logpath /usr/local/mongodb/data/shard/log/route.log --chunkSize=1 

修改chunk大小
mongos> db.settings.save( { _id:"chunksize", value: 1 } )

配置Sharding:
登錄到mongos,添加Shard節(jié)點(diǎn)
在為collection分片前,必須讓該集合所屬的數(shù)據(jù)庫(kù)具有分片的功能,一旦你開(kāi)啟了某個(gè)數(shù)據(jù)庫(kù)的分片,MongoDB會(huì)分配一個(gè)主片。

./bin/mongo --port 40000 
> use admin #此操作需要連接admin庫(kù)
> db.runCommand({ addshard:"localhost:27017" }) #添加 Shard Server 或者用 sh.addshard()命令來(lái)添加,下同;
{ "shardAdded" : "shard0000", "ok" : 1 }
> db.runCommand({ addshard:"localhost:27018" })
{ "shardAdded" : "shard0001", "ok" : 1 }

> db.runCommand({ enablesharding:"test" }) #設(shè)置分片存儲(chǔ)的數(shù)據(jù)庫(kù)
{ "ok" : 1 }

> db.runCommand({ shardcollection: "test.users", key: { id:1 }}) 
# 設(shè)置分片的集合名稱(chēng)。且必須指定Shard Key,系統(tǒng)會(huì)自動(dòng)創(chuàng)建索引,然后根據(jù)這個(gè)shard Key來(lái)計(jì)算。
# 實(shí)際中尤其不要輕易選擇自增_id作為片鍵,片鍵也可以是多個(gè)字段的組合。
{ "collectionsharded" : "test.users", "ok" : 1 }

 > sh.status(); #查看片的狀態(tài)
 > printShardingStatus(db.getSisterDB("config"),1); # 查看片狀態(tài)(完整版);
 > db.stats(); # 查看所有的分片服務(wù)器狀態(tài)
 #查看分片后的情況
 > use config
 switched to db config
 > db.databases.find()
 { "_id" : "test", "primary" : "shard0000", "partitioned" : true }
 > db.chunks.find()
 { "_id" : "test.user-_id_MinKey", "ns" : "test.user", "min" : { "_id" : { "$minKey" : 1 } }, "max" : { "_id" : { "$maxKey" : 1 } }, "shard" : "shard0000", "lastmod" : Timestamp(1, 0), "lastmodEpoch" : ObjectId("5677cc4015fdf4f1ffbb15bd") }

如上建庫(kù)的時(shí)候要登陸mongos來(lái)建,建好一個(gè)庫(kù),mongos來(lái)自動(dòng)給你分配是建立在哪個(gè)shard上,但你也可以運(yùn)行命令來(lái)把它移動(dòng)到別的shard上。例如:在mongos上建立了一個(gè)庫(kù)叫recsys0庫(kù)。運(yùn)行db.printShardingStatus()命令我們可以看到這個(gè)recsys0是建到了哪個(gè)shard,如果建到了shard4,而你想改到shard1,那么可以運(yùn)行命令,db.runCommand( { movePrimary: “recsys0”, to: “shard1” }),這個(gè)庫(kù)就會(huì)從shard4挪到shard1上??赏ㄟ^(guò)db.printShardingStatus()再次檢查。

刪除分片:
db.runCommand({"removeshard":"192.168.245.131:27017"})

對(duì)已存在數(shù)據(jù)分片:
假設(shè)現(xiàn)在存在一個(gè)數(shù)據(jù)很大的children數(shù)據(jù)庫(kù),在192.168.245.129:27019上面,需要將這些數(shù)據(jù)進(jìn)行分片。
1)連接到mongos實(shí)例,將192.168.245.129:27019添加到分片集群中。

mongos> sh.addShard("192.168.245.129:27019")
{ "shardAdded" : "shard0004", "ok" : 1 }

注意集群分片中不能與新添加的分片中有相同的數(shù)據(jù)庫(kù),否則會(huì)報(bào)錯(cuò)。

在需要的數(shù)據(jù)庫(kù)上開(kāi)啟分片功能

mongos> sh.enableSharding("children")
{ "ok" : 1 }

對(duì)children數(shù)據(jù)庫(kù)下的集合進(jìn)行分片。注意:對(duì)已存在的數(shù)據(jù)進(jìn)行分片,一定要保證shard key字段是索引。
mongos> sh.shardCollection("children.children",{"user_id":1})

shard key:
以上分片都使用了MongoDB本身提供了Auto-Sharding的功能,Auto-Sharding的一些缺陷:

  • 如果選擇了單一的Sharding Key,會(huì)造成分片不均衡,無(wú)法充分利用每個(gè)分片集群的能力。為了彌補(bǔ)單一Sharding Key的缺點(diǎn),引入復(fù)合Sharing Key,然而復(fù)合Sharding Key會(huì)造成性能的消耗。
  • count值計(jì)算不準(zhǔn)確的問(wèn)題,數(shù)據(jù)Chunk在分片之間遷移時(shí),特定數(shù)據(jù)可能會(huì)被計(jì)算2次,造成count值計(jì)算偏大的問(wèn)題;
  • Balancer的穩(wěn)定性&智能性問(wèn)題,Sharing的遷移發(fā)生時(shí)間不確定,一旦發(fā)生數(shù)據(jù)遷移會(huì)造成整個(gè)系統(tǒng)的吞吐量急劇下降。為了應(yīng)對(duì)Sharding遷移的不確定性,我們可以強(qiáng)制指定在業(yè)務(wù)訪(fǎng)問(wèn)的低峰期做Sharding遷移。

如何選擇shard key:
參考1
參考2

手動(dòng)分片:

由程序來(lái)判斷:
關(guān)閉自動(dòng)分片:sh.stopBalancer()
只是在4個(gè)不同的shard上建立4個(gè)庫(kù)。至于讀寫(xiě)操作會(huì)對(duì)應(yīng)哪個(gè)庫(kù),由程序來(lái)判斷。

MongoDB還帶一種手動(dòng)預(yù)分片:
用split命令對(duì)空集合進(jìn)行手動(dòng)的切分

mongos> use admin
switched to db admin
mongos> db.runCommand({"enablesharding":"myapp"})
mongos> db.runCommand({"shardcollection":"myapp.users","key":{"email":1}})
for ( var x=97; x<97+26; x++ ){
for( var y=97; y<97+26; y+=6 ) {
var prefix = String.fromCharCode(x) + String.fromCharCode(y);
db.runCommand( { split : "myapp.users" , middle : { email : prefix } } );
      }
}

利用moveChunk命令手動(dòng)的移動(dòng)分割的塊:

 var shServer = [ "sh0.example.net", "sh1.example.net", "sh2.example.net", "sh3.example.net", "sh4.example.net" ];
 for ( var x=97; x<97+26; x++ ){
  for( var y=97; y<97+26; y+=6 ) {
   var prefix = String.fromCharCode(x) + String.fromCharCode(y);
   db.adminCommand({moveChunk : "myapp.users", find : {email : prefix}, to : shServer[(y-97)/6]})
  }
 }

每個(gè)分片設(shè)置成副本集:
參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容