在MongoDB存在另一種集羣就是MongoDB的分片技術。通過使用分片可以滿足MongoDB數據量大量增長的需求。當MongoDB存儲海量的數據時,一台MongoDB服務器可能不能滿足存儲數據的要求,也可能不足以提供可接受的讀寫吞吐量。MongoDB為了解決這一系列的問題提出了將數據分割存儲在多台服務器上,使得數據庫系統能存儲和處理更多的數據,以實現數據的分佈式存儲。這就是MongoDB的分片。
提示:單個MongoDB複製集中的節點不能超過12個節點。
因此複製集從本質上並不能解決數據海量存儲的問題。
一、 MongoDB分片的架構
MongoDB分片的架構需要依賴MongoDB的複製集為基礎來實現,下圖展示了分片的體系架構。
從圖中可以看出,MongoDB的分片主要包含以下幾個組成的部分:
- 前端路由服務器:Router,客户端應用程序從Router接入MongoDB分片集羣。Router可以讓分片集羣看上去像一個單一的數據庫。Router通過mongos的命令來啓動。
- 配置服務器:Config Server,負責存儲MongoDB分片的元信息以及後端的分片服務器信息。從MongoDB 3.4的版本開始,Config Server必須配置成一個複製集的形式。
- 分片服務器:Shard Server,負責存儲實際的數據塊。在實際生產環境中一個Shard Server可以由幾台服務器組成一個複製集,從而防止主機單點故障造成數據的丟失。分片服務器也必須是一個複製集的形式。
視頻講解如下:
https://www.bilibili.com/video/BV17BHtz2EqZ/?aid=115302222273...
二、 【實戰】部署MongoDB分片
在瞭解到了MongoDB分片的架構與組成以後,下表列舉了MongoDB分片中的各個節點信息。
提示:表中列舉的的信息是MongoDB分片架構的最簡信息。
例如這裏的前端路由服務器只使用了一個節點來實現,
在實際的生產環境中可以搭建多個節點前端路由服務器。
下面通過具體的步驟來演示如何部署一個MongoDB的分片。
(1)創建各個節點數據的存儲路徑。
mkdir -p /data/27017
mkdir -p /data/37017
mkdir -p /data/37018
mkdir -p /data/47017
mkdir -p /data/47018
(2)創建前端路由服務器的配置信息文件/data/27017/mongos.conf
port=27017
fork=true
logpath=/data/27017/mongos.log
configdb=myshardingconfig/127.0.0.1:37017,127.0.0.1:37018
其中:configdb用於指定配置服務器的地址。
(3)創建第一個配置服務器的配置信息文件/data/37017/mongo_configsvr_37017.conf
dbpath=/data/37017
port=37017
fork=true
logpath=/data/37017/configsvr37017.log
replSet=myshardingconfig
configsvr=true
其中:configsvr=true,表示這是一台配置服務器。
(4)創建第一個配置服務器的配置信息文件/data/37018/mongo_configsvr_37018.conf
dbpath=/data/37018
port=37018
fork=true
logpath=/data/37018/configsvr37018.log
replSet=myshardingconfig
configsvr=true
(5)創建第一個分片服務器的配置信息文件/data/47017/mongo_shardsvr_47017.conf
dbpath=/data/47017
port=47017
fork=true
logpath=/data/47017/shardsvr47017.log
shardsvr=true
replSet=myshardone
其中:shardsvr=true,表示這是一台分片服務器。
(6)創建第二個分片服務器的配置信息文件/data/47018/mongo_shardsvr_47018.conf
dbpath=/data/47018
port=47018
fork=true
logpath=/data/47018/shardsvr47018.log
shardsvr=true
replSet=myshardtwo
(7)啓動所有的MongoDB實例。
mongod --config /data/37017/mongo_configsvr_37017.conf
mongod --config /data/37018/mongo_configsvr_37018.conf
mongod --config /data/47017/mongo_shardsvr_47017.conf
mongod --config /data/47018/mongo_shardsvr_47018.conf
(8)啓動前端路由服務器
mongos --config /data/27017/mongos.conf
(9)使用mongoshell連接37017端口上的MongoDB實例完成配置服務器複製集的初始化。
mongo --port 37017
(10)將37017和37018端口上的MongoDB實例加入複製集中。
> cfg = {"_id":"myshardingconfig",
"members":[{"_id":0,"host":"127.0.0.1:37017"},
{"_id":1,"host":"127.0.0.1:37018"}]}
> rs.initiate(cfg)
(11)查看複製集myshardingconfig的狀態信息。
> rs.status()
# 輸出的信息如下:
......
"members" : [
{
"_id" : 0,
"name" : "127.0.0.1:37017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
......
},
{
"_id" : 1,
"name" : "127.0.0.1:37018",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
......
}
],
......
(12)使用mongoshell連接前端路由服務器。
mongo
(13)查看MongoDB分片服務器的信息。
> sh.status()
# 輸出的信息如下:
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("624d60d6675d42fb9b900362")
}
shards: --> 此處還沒有添加任何的分片服務器地址信息。
active mongoses:
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: no
Failed balancer rounds in last 5 attempts: 0
Migration results for the last 24 hours:
No recent migrations
databases:
{ "_id" : "config", "primary" : "config","partitioned" :true}
(14)初始化47017上的複製集。
> cfg = {"_id":"myshardone",
"members":[{"_id":0,"host":"127.0.0.1:47017"}]}
> rs.initiate(cfg)
(15)初始化47018上的複製集。
> cfg = {"_id":"myshardtwo",
"members":[{"_id":0,"host":"127.0.0.1:47018"}]}
> rs.initiate(cfg)
(16)添加分片服務器
> sh.addShard("myshardone/127.0.0.1:47017")
> sh.addShard("myshardtwo/127.0.0.1:47018")
(17)重新查看MongoDB分片的信息。
> sh.status()
# 輸出的信息如下:
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("624d60d6675d42fb9b900362")
}
shards: --> 分片中的服務器地址。
{"_id":"myshardone","host":"myshardone/127.0.0.1:47017",
"state":1,"topologyTime":Timestamp(1649238845,3)}
{"_id":"myshardtwo","host":"myshardtwo/127.0.0.1:47018",
"state":1,"topologyTime":Timestamp(1649238865,3)}
active mongoses:
"5.0.6" : 1
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: no
Failed balancer rounds in last 5 attempts: 0
Migration results for the last 24 hours:
No recent migrations
databases:
{"_id":"config","primary":"config","partitioned" : true }
(18)添加一個分片數據庫。
> sh.enableSharding("myshardDB")
(19)查看分片數據庫的信息。
> sh.status()
# 輸出的信息如下:
......
databases:
{ "_id" : "config", "primary" : "config", "partitioned" : true }
config.system.sessions
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
myshardone 992
myshardtwo 32
too many chunks to print, use verbose if you want to force print
{ "_id" : "myshardDB", "primary" : "myshardtwo",
"partitioned" : true,
"version":{"uuid": UUID("4c640f1f-77fe-45a6-92b4-b7c90692b845"),
"timestamp" : Timestamp(1649239126, 36),
"lastMod" : 1 } }
(20)修改數據分片的大小。
> use config
> db.settings.save( { _id:"chunksize", value:1})
注意:默認情況下,分片大小(chunk size)是64M。只有達到了分片的大小,才會進行分片。
(21)開啓集合上數據的分片。
> sh.shardCollection("myshardDB.table1",{"_id":1})
提示:這裏使用了插入文檔的_id作為片鍵來實現文檔的分佈式存儲。
(22)在數據庫myshardDB中創建集合,並插入10萬條文檔
> use myshardDB
> for(var i = 1; i <= 100000; i++)
{db.table1.insert({"_id":i,"action":"write","iteration no:":i});}
(23)再次查看分片數據庫的信息。
> sh.status()
# 輸出的信息如下:
......
myshardDB.table1
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
myshardone 6
myshardtwo 1
{"_id":{"$minKey":1}}-->>{"_id":2} on:myshardone Timestamp(2,0)
{"_id": 2}-->>{"_id":20241} on:myshardtwo Timestamp(3,1)
{"_id":20241}-->>{"_id":37933} on:myshardone Timestamp(3,2)
{"_id":37933}-->>{"_id":55627} on:myshardone Timestamp(3,4)
{"_id":55627}-->>{"_id":74150} on:myshardone Timestamp(3,6)
{"_id":74150}-->>{"_id":91829} on:myshardone Timestamp(3,8)
{"_id":91829}-->>{"_id":{"$maxKey":1}}on:myshardoneTimestamp(3,9)
......
從輸出的信息可以看出,id值在{2,20241}的數據存儲在了myshardtwo 的複製集上;而其他id值對應的數據存儲在了myshardone的複製集上。因此可以得出結論,數據實現了分佈式存儲但效果不是很好。為了實現更好的數據分佈式存儲應當合理地選擇片鍵。