十年河東,十年河西,莫欺少年窮
學無止境,精益求精
本文參考至:https://zhuanlan.zhihu.com/p/84406822 感謝知乎作者的無私奉獻。
視頻講解:https://www.bilibili.com/video/av52570271/
分片理論:https://www.cnblogs.com/ddbear/p/7746076.html
mongodb相關指令:https://www.cnblogs.com/chenmh/p/8434419.html
本篇博客旨在提供更詳細的搭建說明;
1 Mongodb集群介紹
在官方文檔的介紹中,MongoDB集群有三種形式:Replica Set(副本集),Sharding(分片集群),Master-Slaver(主從)。那么該如何選擇某種集群應用
呢?其實可以從官方的文檔介紹中可以得出結論,副本集和主從的模式僅是讀寫分離與容災的體現,對於真正到達海量數據時,我們需要的是能將數據按照一定規
則分配至不同服務器進行存儲和查詢等,這就是分片集群要做的事情,聰明的你肯定已經猜到了,這種模式也囊括了副本集和主從,既然要做集群,那么我們就搭
最頂級的分片集群,本文主要介紹分片集群的搭建,以及分片集群模式下的安全認證處理配置。
2 分片集群的組件介紹
分片集群中主要有三個組件:
- Routers(前端路由器),mongos充當查詢路由器,提供客戶端應用程序和分片集群之間的接口。客戶端通過驅動選擇連接某一個mongs作為集群入口,執行
數據查詢和寫入。沒錯,它也是多個,當然官方要求至少一個,但為了防止單點故障,我們選擇3台。 - Config Servers (配置服務器),config servers配置服務器存儲群集的元數據和配置設置。從MongoDB 3.4開始,必須將配置服務器部署為副本集。它主要記錄了
shard的配置信息,元信息,如數據存儲目錄,日志目錄,端口號,chunk信息,是否開啟了journal等信息,為了保證它的高可用,官方要求必須是副本集,如果
配置器一旦整體無法使用,則集群無法使用,所以,它也是3台。 - Shard (分片服務器),每個分片包含分片數據的子集。每個分片都可以部署為副本集。實際儲存數據的載體服務,一個shard角色應該是一個ReaplicaSet組,本
此我們采用3個Shard,每個shard一個副本集,副本集中會有主節點,從節點,仲裁節點。
組件交互圖:
3 集群搭建 環境准備
mongo1(127.0.0.1) mongo2(127.0.0.1) mongo3(127.0.0.1)
config1(端口:27018) config2(端口:27028) config3(端口:27038)
mongos1(端口:27019) mongos2(端口:27029) mongos3(端口:27039)
Shard1(端口:27001) Shard1(端口:27021) Shard1(端口:27031)
Shard2(端口:27002) Shard2(端口:27022) Shard2(端口:27032)
Shard3(端口:27003) Shard3(端口:27023) Shard3(端口:27033)
實際當中,個人覺得mong1,mongo2 ,mongo3應當是在三台不同的服務器,mongos應當與config部署在不同的服務器,各shard組副本集應當部署在不同的服務器,
config可以與shard片部署在同一服務器,也就是說要達到性能最優,至少應當有6台服務器,mongos用3台,config和3組Shard用3台。本文中就以本地Windows7環境為例,
用不同的端口作為偽服務器演示搭建配置過程。MongoBD zip安裝包下載地址:
注意,集群下不要使用msi安裝。本文采用 mongodb-win32-x86_64-2012plus-v4.2-latest.zip
解壓之后重命名為mongo,內部目錄如下:
在此目錄下創建偽服務器目錄文件夾:
mongo1(服務器1),mongo2(服務器2),mongo3(服務器3)。如圖:
然后在mongo1下分別創建文件夾data(用於存儲數據),log(日志文件存放),conf(配置文件存放):
在data下再創建3個文件夾:
在conf下創建三個配置文件(config.conf、mongos.conf、shard1.conf、shard2.conf、shard3.conf):
在log下創建三個日志文件,(config.log、mongos.log、shard1.log、shard2.log、shard3.log),忽略圖片中的mongos.diagnostic.data文件夾,這是服務運行時產生的。
好,至此,mong1中的環境准備工作已經結束,將mong1下的所有文件夾拷貝到mongo2和mongo3下。
集群配置編輯:
首先編輯mong1的config的配置文件:config.conf

net: port: 27018 #config1的端口,mongo2下的為27028,mongo3下的為27038 bindIp: 0.0.0.0 #允許連接地址,這里統一設置為允許任何ip連接 systemLog: destination: file logAppend: true path: D:\tool\mongodbmy\mongo\mongo1\log\config.log #config的日志存儲地址,mongo2,mongo3下路徑調整即可 storage: dbPath: D:\tool\mongodbmy\mongo\mongo1\data\config #config的數據存儲地址,mongo2、mongo3下做相應的調整 journal: enabled: true #數據故障恢復和持久化,肯定是開啟 #processManagement: # fork: true #linux下打開此設置,Windows環境下后台啟動需要注冊服務, # pidFilePath: /mongo/config/run/mongod.pid #副本集名稱設置 replication: replSetName: configs #分片集群角色,配置服務器的固定值 sharding: clusterRole: configsvr #這里是集群安全認證配置,首次配置啟動集群不打開此配置,先留着,后面再說 #security: #keyFile: D:\tool\mongodbmy\mongo\mongodb-keyfile.file #authorization: enabled
然后編輯shard1.conf:

net: port: 27001 #mongo1下其他兩個分片shard2為27002,shard3為27003,mongo2、mongo3下對應上面的服務編排表設置端口 bindIp: 0.0.0.0 systemLog: destination: file logAppend: true path: D:\tool\mongodbmy\mongo\mongo1\log\shard1.log #mongo1下其他兩個分片shard2為shard2.log,shard3為shard3.log,mongo2、mongo3下對應做調整 storage: dbPath: D:\tool\mongodbmy\mongo\mongo1\data\shard1 #mongo1下其他兩個分片shard2為shard2,shard3為shard3,mongo2、mongo3下對應做調整 journal: enabled: true #processManagement: # fork: true # pidFilePath: /mongo/shard1/run/mongod.pid replication: replSetName: shard1 #副本集名稱,下其他兩個分片對應調整shard2為shard2,shard3為shard3 sharding: clusterRole: shardsvr #集群中角色歸屬
shard2.conf:

net: port: 27002 bindIp: 0.0.0.0 systemLog: destination: file logAppend: true path: D:\tool\mongodbmy\mongo\mongo1\log\shard2.log storage: dbPath: D:\tool\mongodbmy\mongo\mongo1\data\shard2 journal: enabled: true #processManagement: # fork: true # pidFilePath: /mongo/shard2/run/mongod.pid replication: replSetName: shard2 sharding: clusterRole: shardsvr
shard3.conf:

net: port: 27003 bindIp: 0.0.0.0 systemLog: destination: file logAppend: true path: D:\tool\mongodbmy\mongo\mongo1\log\shard3.log storage: dbPath: D:\tool\mongodbmy\mongo\mongo1\data\shard3 journal: enabled: true #processManagement: # fork: true # pidFilePath: /mongo/shard3/run/mongod.pid replication: replSetName: shard3 sharding: clusterRole: shardsvr
配置mongos.conf:

systemLog: destination: file logAppend: true path: D:\tool\mongodbmy\mongo\mongo1\log\mongos.log #mongos沒有數據存儲地址,只有日志輸出地址,mongo2、mongo3下做對應的地址調整 # network interfaces net: port: 27019 # mongos1的端口,mongos2為27029,mongos3為27039 bindIp: 0.0.0.0 setParameter: enableLocalhostAuthBypass: false #注意!此處配置的連接地址為配置服務器config Serve的副本集名稱和所在服務器地址以及端口 sharding: configDB: configs/127.0.0.1:27018,127.0.0.1:27028,127.0.0.1:27038
其次編輯mong2的config的配置文件:config.conf

net: port: 27028 #config1的端口,mongo2下的為27028,mongo3下的為27038 bindIp: 0.0.0.0 #允許連接地址,這里統一設置為允許任何ip連接 systemLog: destination: file logAppend: true path: D:\tool\mongodbmy\mongo\mongo2\log\config.log #config的日志存儲地址,mongo2,mongo3下路徑調整即可 storage: dbPath: D:\tool\mongodbmy\mongo\mongo2\data\config #config的數據存儲地址,mongo2、mongo3下做相應的調整 journal: enabled: true #數據故障恢復和持久化,肯定是開啟 #processManagement: # fork: true #linux下打開此設置,Windows環境下后台啟動需要注冊服務, # pidFilePath: /mongo/config/run/mongod.pid #副本集名稱設置 replication: replSetName: configs #分片集群角色,配置服務器的固定值 sharding: clusterRole: configsvr #這里是集群安全認證配置,首次配置啟動集群不打開此配置,先留着,后面再說 #security: # keyFile: D:\tool\mongodbmy\mongo\mongodb-keyfile.file # authorization: enabled
shard1.conf 如下:

net: port: 27021 #mongo1下其他兩個分片shard2為27002,shard3為27003,mongo2、mongo3下對應上面的服務編排表設置端口 bindIp: 0.0.0.0 systemLog: destination: file logAppend: true path: D:\tool\mongodbmy\mongo\mongo2\log\shard1.log #mongo1下其他兩個分片shard2為shard2.log,shard3為shard3.log,mongo2、mongo3下對應做調整 storage: dbPath: D:\tool\mongodbmy\mongo\mongo2\data\shard1 #mongo1下其他兩個分片shard2為shard2,shard3為shard3,mongo2、mongo3下對應做調整 journal: enabled: true #processManagement: # fork: true # pidFilePath: /mongo/shard1/run/mongod.pid replication: replSetName: shard1 #副本集名稱,下其他兩個分片對應調整shard2為shard2,shard3為shard3 sharding: clusterRole: shardsvr #集群中角色歸屬
shard2.conf 如下:

net: port: 27022 bindIp: 0.0.0.0 systemLog: destination: file logAppend: true path: D:\tool\mongodbmy\mongo\mongo2\log\shard2.log storage: dbPath: D:\tool\mongodbmy\mongo\mongo2\data\shard2 journal: enabled: true #processManagement: # fork: true # pidFilePath: /mongo/shard2/run/mongod.pid replication: replSetName: shard2 sharding: clusterRole: shardsvr
shard3.conf 如下:

net: port: 27023 bindIp: 0.0.0.0 systemLog: destination: file logAppend: true path: D:\tool\mongodbmy\mongo\mongo2\log\shard3.log storage: dbPath: D:\tool\mongodbmy\mongo\mongo2\data\shard3 journal: enabled: true #processManagement: # fork: true # pidFilePath: /mongo/shard3/run/mongod.pid replication: replSetName: shard3 sharding: clusterRole: shardsvr
配置mongos.conf:

systemLog: destination: file logAppend: true path: D:\tool\mongodbmy\mongo\mongo2\log\mongos.log #mongos沒有數據存儲地址,只有日志輸出地址,mongo2、mongo3下做對應的地址調整 # network interfaces net: port: 27029 # mongos1的端口,mongos2為27029,mongos3為27039 bindIp: 0.0.0.0 setParameter: enableLocalhostAuthBypass: false #注意!此處配置的連接地址為配置服務器config Serve的副本集名稱和所在服務器地址以及端口 sharding: configDB: configs/127.0.0.1:27018,127.0.0.1:27028,127.0.0.1:27038
最后編輯mong3 文件夾下的config.conf:

net: port: 27038 #config1的端口,mongo2下的為27028,mongo3下的為27038 bindIp: 0.0.0.0 #允許連接地址,這里統一設置為允許任何ip連接 systemLog: destination: file logAppend: true path: D:\tool\mongodbmy\mongo\mongo3\log\config.log #config的日志存儲地址,mongo2,mongo3下路徑調整即可 storage: dbPath: D:\tool\mongodbmy\mongo\mongo3\data\config #config的數據存儲地址,mongo2、mongo3下做相應的調整 journal: enabled: true #數據故障恢復和持久化,肯定是開啟 #processManagement: # fork: true #linux下打開此設置,Windows環境下后台啟動需要注冊服務, # pidFilePath: /mongo/config/run/mongod.pid #副本集名稱設置 replication: replSetName: configs #分片集群角色,配置服務器的固定值 sharding: clusterRole: configsvr #這里是集群安全認證配置,首次配置啟動集群不打開此配置,先留着,后面再說 #security: # keyFile: D:\tool\mongodbmy\mongo\mongodb-keyfile.file # authorization: enabled
shard1.conf 如下:

net: port: 27031 #mongo1下其他兩個分片shard2為27002,shard3為27003,mongo2、mongo3下對應上面的服務編排表設置端口 bindIp: 0.0.0.0 systemLog: destination: file logAppend: true path: D:\tool\mongodbmy\mongo\mongo3\log\shard1.log #mongo1下其他兩個分片shard2為shard2.log,shard3為shard3.log,mongo2、mongo3下對應做調整 storage: dbPath: D:\tool\mongodbmy\mongo\mongo3\data\shard1 #mongo1下其他兩個分片shard2為shard2,shard3為shard3,mongo2、mongo3下對應做調整 journal: enabled: true #processManagement: # fork: true # pidFilePath: /mongo/shard1/run/mongod.pid replication: replSetName: shard1 #副本集名稱,下其他兩個分片對應調整shard2為shard2,shard3為shard3 sharding: clusterRole: shardsvr #集群中角色歸屬
shard2.conf 如下:

net: port: 27032 bindIp: 0.0.0.0 systemLog: destination: file logAppend: true path: D:\tool\mongodbmy\mongo\mongo3\log\shard2.log storage: dbPath: D:\tool\mongodbmy\mongo\mongo3\data\shard2 journal: enabled: true #processManagement: # fork: true # pidFilePath: /mongo/shard2/run/mongod.pid replication: replSetName: shard2 sharding: clusterRole: shardsvr
shard3.conf 如下:

net: port: 27033 bindIp: 0.0.0.0 systemLog: destination: file logAppend: true path: D:\tool\mongodbmy\mongo\mongo3\log\shard3.log storage: dbPath: D:\tool\mongodbmy\mongo\mongo3\data\shard3 journal: enabled: true #processManagement: # fork: true # pidFilePath: /mongo/shard3/run/mongod.pid replication: replSetName: shard3 sharding: clusterRole: shardsvr
配置mongos.conf:

systemLog: destination: file logAppend: true path: D:\tool\mongodbmy\mongo\mongo3\log\mongos.log #mongos沒有數據存儲地址,只有日志輸出地址,mongo2、mongo3下做對應的地址調整 # network interfaces net: port: 27039 # mongos1的端口,mongos2為27029,mongos3為27039 bindIp: 0.0.0.0 setParameter: enableLocalhostAuthBypass: false #注意!此處配置的連接地址為配置服務器config Serve的副本集名稱和所在服務器地址以及端口 sharding: configDB: configs/127.0.0.1:27018,127.0.0.1:27028,127.0.0.1:27038
至此,mongo1下的配置結束,將上述配置文件內容拷貝到mongo2,mongo3對應的文件,根據服務編排內容做端口和路徑的調整,切記!!一定要按照服務編排好的端口
去設置,路徑一定要配置對應的文件!!!切記切記!!
配置文件下載:https://files.cnblogs.com/files/chenwolong/mongosConfig.zip
以上便是配置,下面進入啟動服務。
啟動服務,配置副本集
分片集群必須按照一定的順序啟動:config serve,Shard ,Mongos,
首先,啟動三台服務器的config:在mongo安裝目錄bin目錄下以管理員身份打開3個dos窗口分別執行下面三條dos命令,當然,如果你配置了mongo的環境變量【沒有配置,需要去設置環境變量】,任意地方
開啟三個dos窗口,執行如下doc命令【三台服務器各執行一次】。
mongod -f D:\tool\mongodbmy\mongo\mongo1\conf\config.conf mongod -f D:\tool\mongodbmy\mongo\mongo2\conf\config.conf mongod -f D:\tool\mongodbmy\mongo\mongo3\conf\config.conf
【其他兩個指令截圖類似】
【1】然后新開窗口連接到任意一台config server 【真實服務器下,不要忘記指定IP,默認為127.0.0.1】
mongo -host 127.0.0.1 --port 27018
【2】然后配置配置器的服務集:
config = { _id : "configs", members : [ {_id : 0, host : "127.0.0.1:27018" }, {_id : 1, host : "127.0.0.1:27028" }, {_id : 2, host : "127.0.0.1:27038" } ] }
【3】初始化副本集:
rs.initiate(config)
【4】查看副本集狀態:
rs.status()
上述【1】【2】【3】【4】四個指令執行完畢后, mongos1/mongos2/mongos3服務器中 data/config 和 logs/config 文件夾中將會生產相應的文件
上述【1】【2】【3】【4】四個指令在同一個窗口中執行,執行結果打印的腳本太多,無法整體截圖,貼出來供大家參考:

PS D:\tool\mongodbmy\mongo\bin> mongo --port 27018 MongoDB shell version v4.2.12-6-ga3c3db2 connecting to: mongodb://127.0.0.1:27018/?compressors=disabled&gssapiServiceName=mongodb Implicit session: session { "id" : UUID("1506619d-cbf5-42e7-9bd3-bba5813d4998") } MongoDB server version: 4.2.12-6-ga3c3db2 Server has startup warnings: 2021-02-01T16:57:53.876+0800 I CONTROL [initandlisten] 2021-02-01T16:57:53.876+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database. 2021-02-01T16:57:53.876+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted. 2021-02-01T16:57:53.876+0800 I CONTROL [initandlisten] --- Enable MongoDB's free cloud-based monitoring service, which will then receive and display metrics about your deployment (disk utilization, CPU, operation statistics, etc). The monitoring data will be available on a MongoDB website with a unique URL accessible to you and anyone you share the URL with. MongoDB may use this information to make product improvements and to suggest MongoDB products and deployment options to you. To enable free monitoring, run the following command: db.enableFreeMonitoring() To permanently disable this reminder, run the following command: db.disableFreeMonitoring() --- > config = { _id : "configs", ... members : [ ... {_id : 0, host : "127.0.0.1:27018" }, ... {_id : 1, host : "127.0.0.1:27028" }, ... {_id : 2, host : "127.0.0.1:27038" } ... ] } { "_id" : "configs", "members" : [ { "_id" : 0, "host" : "127.0.0.1:27018" }, { "_id" : 1, "host" : "127.0.0.1:27028" }, { "_id" : 2, "host" : "127.0.0.1:27038" } ] } > rs.initiate(config) { "ok" : 1, "$gleStats" : { "lastOpTime" : Timestamp(1612169978, 1), "electionId" : ObjectId("000000000000000000000000") }, "lastCommittedOpTime" : Timestamp(0, 0), "$clusterTime" : { "clusterTime" : Timestamp(1612169978, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1612169978, 1) } configs:SECONDARY> rs.status() { "set" : "configs", "date" : ISODate("2021-02-01T08:59:48.508Z"), "myState" : 2, "term" : NumberLong(0), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "configsvr" : true, "heartbeatIntervalMillis" : NumberLong(2000), "majorityVoteCount" : 2, "writeMajorityCount" : 2, "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "lastCommittedWallTime" : ISODate("1970-01-01T00:00:00Z"), "appliedOpTime" : { "ts" : Timestamp(1612169978, 1), "t" : NumberLong(-1) }, "durableOpTime" : { "ts" : Timestamp(1612169978, 1), "t" : NumberLong(-1) }, "lastAppliedWallTime" : ISODate("2021-02-01T08:59:38.372Z"), "lastDurableWallTime" : ISODate("2021-02-01T08:59:38.372Z") }, "lastStableRecoveryTimestamp" : Timestamp(0, 0), "lastStableCheckpointTimestamp" : Timestamp(0, 0), "members" : [ { "_id" : 0, "name" : "127.0.0.1:27018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 115, "optime" : { "ts" : Timestamp(1612169978, 1), "t" : NumberLong(-1) }, "optimeDate" : ISODate("2021-02-01T08:59:38Z"), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "could not find member to sync from", "configVersion" : 1, "self" : true, "lastHeartbeatMessage" : "" }, { "_id" : 1, "name" : "127.0.0.1:27028", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 10, "optime" : { "ts" : Timestamp(1612169978, 1), "t" : NumberLong(-1) }, "optimeDurable" : { "ts" : Timestamp(1612169978, 1), "t" : NumberLong(-1) }, "optimeDate" : ISODate("2021-02-01T08:59:38Z"), "optimeDurableDate" : ISODate("2021-02-01T08:59:38Z"), "lastHeartbeat" : ISODate("2021-02-01T08:59:48.396Z"), "lastHeartbeatRecv" : ISODate("2021-02-01T08:59:48.459Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "configVersion" : 1 }, { "_id" : 2, "name" : "127.0.0.1:27038", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 10, "optime" : { "ts" : Timestamp(1612169978, 1), "t" : NumberLong(-1) }, "optimeDurable" : { "ts" : Timestamp(1612169978, 1), "t" : NumberLong(-1) }, "optimeDate" : ISODate("2021-02-01T08:59:38Z"), "optimeDurableDate" : ISODate("2021-02-01T08:59:38Z"), "lastHeartbeat" : ISODate("2021-02-01T08:59:48.399Z"), "lastHeartbeatRecv" : ISODate("2021-02-01T08:59:48.450Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "configVersion" : 1 } ], "ok" : 1, "$gleStats" : { "lastOpTime" : Timestamp(1612169978, 1), "electionId" : ObjectId("000000000000000000000000") }, "lastCommittedOpTime" : Timestamp(0, 0), "$clusterTime" : { "clusterTime" : Timestamp(1612169978, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1612169978, 1) } configs:SECONDARY>
啟動3個分片副本集組:分別開9個窗口啟動執行下面9條dos命令啟動shard1:
mongod -f D:\tool\mongodbmy\mongo\mongo1\conf\shard1.conf mongod -f D:\tool\mongodbmy\mongo\mongo2\conf\shard1.conf mongod -f D:\tool\mongodbmy\mongo\mongo3\conf\shard1.conf
【其他兩個指令截圖類似】
【A1】新開窗口連接到mong1文件夾的shard1
mongo --port 27001
【B1】配置mong1文件夾的shard1的副本集:
config = { _id : "shard1", members : [ {_id : 0, host : "127.0.0.1:27001"}, {_id : 1, host : "127.0.0.1:27021"}, {_id : 2, host : "127.0.0.1:27031"} ] }
【C1】初始化mong1文件夾的副本集:
rs.initiate(config);
開啟分片2副本集:
mongod -f D:\tool\mongodbmy\mongo\mongo1\conf\shard2.conf mongod -f D:\tool\mongodbmy\mongo\mongo2\conf\shard2.conf mongod -f D:\tool\mongodbmy\mongo\mongo3\conf\shard2.conf
【A2】新開窗口連接到mong2文件夾的shard2
mongo --port 27002
【B2】配置mong2文件夾的shard2的副本集:
config = { _id : "shard2",
... members : [
... {_id : 0, host : "127.0.0.1:27002"},
... {_id : 1, host : "127.0.0.1:27022"},
... {_id : 2, host : "127.0.0.1:27032"}
... ] }
【C2】初始化mong2文件夾的副本集:
rs.initiate(config);
開啟分片3副本集:
mongod -f D:\tool\mongodbmy\mongo\mongo1\conf\shard3.conf
mongod -f D:\tool\mongodbmy\mongo\mongo2\conf\shard3.conf mongod -f D:\tool\mongodbmy\mongo\mongo3\conf\shard3.conf
【A3】新開窗口連接到mong3文件夾的shard3
mongo --port 27003
【B3】配置mong3文件夾的shard3的副本集:
config = { _id : "shard3",
... members : [
... {_id : 0, host : "127.0.0.1:27003"},
... {_id : 1, host : "127.0.0.1:27023"},
... {_id : 2, host : "127.0.0.1:27033"}
... ] }
【C3】初始化mong3文件夾的副本集:
rs.initiate(config);
關於上述【A1~A3,B1~B3,C1~C3】,貼出執行打印結果,其他類似:

PS D:\tool\mongodbmy\mongo\bin> mongo --port 27021 MongoDB shell version v4.2.12-6-ga3c3db2 connecting to: mongodb://127.0.0.1:27021/?compressors=disabled&gssapiServiceName=mongodb Implicit session: session { "id" : UUID("c725ae9f-d0d6-4ca3-99c1-24f88eecbcf5") } MongoDB server version: 4.2.12-6-ga3c3db2 Server has startup warnings: 2021-02-01T17:00:34.062+0800 I CONTROL [initandlisten] 2021-02-01T17:00:34.062+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database. 2021-02-01T17:00:34.062+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted. 2021-02-01T17:00:34.063+0800 I CONTROL [initandlisten] --- Enable MongoDB's free cloud-based monitoring service, which will then receive and display metrics about your deployment (disk utilization, CPU, operation statistics, etc). The monitoring data will be available on a MongoDB website with a unique URL accessible to you and anyone you share the URL with. MongoDB may use this information to make product improvements and to suggest MongoDB products and deployment options to you. To enable free monitoring, run the following command: db.enableFreeMonitoring() To permanently disable this reminder, run the following command: db.disableFreeMonitoring() --- shard1:SECONDARY> config = { _id : "shard2", ... members : [ ... {_id : 0, host : "127.0.0.1:27021"}, ... {_id : 1, host : "127.0.0.1:27022"}, ... {_id : 2, host : "127.0.0.1:27023"} ... ] } { "_id" : "shard2", "members" : [ { "_id" : 0, "host" : "127.0.0.1:27021" }, { "_id" : 1, "host" : "127.0.0.1:27022" }, { "_id" : 2, "host" : "127.0.0.1:27023" } ] } shard1:SECONDARY> rs.initiate(config); { "operationTime" : Timestamp(1612170313, 1), "ok" : 0, "errmsg" : "already initialized", "code" : 23, "codeName" : "AlreadyInitialized", "$clusterTime" : { "clusterTime" : Timestamp(1612170313, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } } shard1:SECONDARY>
最后:
分別啟動前端路由器mongos1,mongos2,mongos3,
注意,這里啟動是用mongos!!!!!開三個窗口:
mongos -f D:\tool\mongodbmy\mongo\mongo1\conf\mongos.conf
mongos -f D:\tool\mongodbmy\mongo\mongo2\conf\mongos.conf
mongos -f D:\tool\mongodbmy\mongo\mongo3\conf\mongos.conf
【其他兩個指令截圖類似】
【S1】新開一個窗口:連接任意一個mongos,
mongo --port 27019
【S2】然后使用admin庫,啟用集群分片:
use admin;
sh.addShard("shard1/127.0.0.1:27001,127.0.0.1:27021,127.0.0.1:27031");
sh.addShard("shard2/127.0.0.1:27002,127.0.0.1:27022,127.0.0.1:27032");
sh.addShard("shard3/127.0.0.1:27003,127.0.0.1:27023,127.0.0.1:27033");
db.createUser( { user: "admin", pwd: "admin", roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] } )
#關閉當前mongos 連接,重連如下:
mongo --port 27017 -u "admin" -p "admin" --authenticationDatabase "admin"
至此,分片集群搭建完成,
那么,測試一下:
#設置一下chunk的大小: use config; db.setting.save({"_id":"chunksize","value":1}) # 設置塊大小為1M是方便實驗,不然需要插入海量數據 #模擬寫入數據 use testdb; #啟用數據庫分片 sh.enableSharding("testdb") #創建集合 use testdb; db.createCollection("user"); db.user.createIndex({"name":"hased"}) # 以"name"作哈希索引分片鍵 sh.shardCollection( "testdb.user", { "name" : "hashed" } ) #對user集合啟用分片 for(i=1;i<=50000;i++){db.user.insert({"id":i,"name":"zzx"+i})} #模擬往mytest數據庫的user表寫入5萬數據 sh.status() # 查看分片情況
sh.help() # 查看sh下所有指令
db.settings.help() # 查看數據庫分片幫助指令
db.runCommand({listShards:1}) # 查看分片列表,所有分片
use config; 查詢當前塊大小 db.settings.find({"_id":"chunksize"}) 修改塊大小 db.settings.save( { _id:"chunksize", value: 64 } );
如果看到數據平均分布於shard1,shard2,shard3,那么說明我們搭建成功,啟用分片成功。
4 分片集群下的安全認證實現:
MongoDB支持許多客戶端可用於驗證其身份的身份驗證機制。這些機制允許MongoDB集成到您現有的身份驗證系統中。除了驗證客戶端的身份之外,MongoDB還
可以要求副本集和分片集群的成員對其各自的副本集或分片集群的成員身份進行身份驗證。有關 更多信息,請參閱內部驗證。
首先,生成集群成員內部認證的秘鑰文件,密鑰文件的內容充當成員的共享密碼。密鑰長度必須介於6到1024個字符之間,並且只能包含base64集中的字符。如果是
生產環境,將生成后的秘鑰文件拷貝到存在集群成員的每一台服務器,注意,生產環境下各節點的秘鑰文件內容必須一致。
然后在所有config.conf和shard.conf中增加兩項安全認證配置:
security:
keyFile: D:\tool\mongodbmy\mongo\mongodb-keyfile.file #秘鑰文件路徑
authorization: enabled #開啟客戶端認證
在所有mongos.conf添加:
security:
keyFile: D:\tool\mongodbmy\mongo\mongodb-keyfile.file #秘鑰文件路徑
至此配置結束,那么客戶端的身份認證是通過用戶名和密碼進行認證,我們還需要創建用戶和用戶名,假設我們給testdb庫創建用戶,連接某一個mongos,為其創建用戶:
mongos --port
27019;
use admin;//注意,一定要使用admin庫去創建用戶
db.createUser({user:
"testdb", pwd:
"testdb", roles: [{role:
"readWrite", db:
"testdb"
}]})
用戶創建完畢。重啟集群使安全認證配置生效。
注意,這里啟動是用mongos!!!!!
注:
2.2 集群中數據分布
2.2.1 Chunk是什么
在一個shard server內部,MongoDB還是會把數據分為chunks,每個chunk代表這個shard server內部一部分數據。chunk的產生,會有以下兩個用途:
Splitting:當一個chunk的大小超過配置中的chunk size時,MongoDB的后台進程會把這個chunk切分成更小的chunk,從而避免chunk過大的情況
Balancing:在MongoDB中,balancer是一個后台進程,負責chunk的遷移,從而均衡各個shard server的負載,系統初始1個chunk,chunk size默認值64M,生產庫上選擇適合業務的chunk size是最好的。ongoDB會自動拆分和遷移chunks。
分片集群的數據分布(shard節點)
(1)使用chunk來存儲數據
(2)進群搭建完成之后,默認開啟一個chunk,大小是64M,
(3)存儲需求超過64M,chunk會進行分裂,如果單位時間存儲需求很大,設置更大的chunk
(4)chunk會被自動均衡遷移。
2.2.2 chunksize的選擇
適合業務的chunksize是最好的。
chunk的分裂和遷移非常消耗IO資源;chunk分裂的時機:在插入和更新,讀數據不會分裂。
chunksize的選擇:
小的chunksize:數據均衡是遷移速度快,數據分布更均勻。數據分裂頻繁,路由節點消耗更多資源。大的chunksize:數據分裂少。數據塊移動集中消耗IO資源。通常100-200M
2.2.3 chunk分裂及遷移
隨着數據的增長,其中的數據大小超過了配置的chunk size,默認是64M,則這個chunk就會分裂成兩個。數據的增長會讓chunk分裂得越來越多。
這時候,各個shard 上的chunk數量就會不平衡。這時候,mongos中的一個組件balancer 就會執行自動平衡。把chunk從chunk數量最多的shard節點挪動到數量最少的節點。
chunkSize 對分裂及遷移的影響
MongoDB 默認的 chunkSize 為64MB,如無特殊需求,建議保持默認值;chunkSize 會直接影響到 chunk 分裂、遷移的行為。
chunkSize 越小,chunk 分裂及遷移越多,數據分布越均衡;反之,chunkSize 越大,chunk 分裂及遷移會更少,但可能導致數據分布不均。
chunkSize 太小,容易出現 jumbo chunk(即shardKey 的某個取值出現頻率很高,這些文檔只能放到一個 chunk 里,無法再分裂)而無法遷移;chunkSize 越大,則可能出現 chunk 內文檔數太多(chunk 內文檔數不能超過 250000 )而無法遷移。
chunk 自動分裂只會在數據寫入時觸發,所以如果將 chunkSize 改小,系統需要一定的時間來將 chunk 分裂到指定的大小。
chunk 只會分裂,不會合並,所以即使將 chunkSize 改大,現有的 chunk 數量不會減少,但 chunk 大小會隨着寫入不斷增長,直到達到目標大小。
2.3 數據區分
2.3.1 分片鍵shard key
MongoDB中數據的分片是、以集合為基本單位的,集合中的數據通過片鍵(Shard key)被分成多部分。其實片鍵就是在集合中選一個鍵,用該鍵的值作為數據拆分的依據。
所以一個好的片鍵對分片至關重要。片鍵必須是一個索引,通過sh.shardCollection加會自動創建索引(前提是此集合不存在的情況下)。一個自增的片鍵對寫入和數據均勻分布就不是很好,因為自增的片鍵總會在一個分片上寫入,后續達到某個閥值可能會寫到別的分片。但是按照片鍵查詢會非常高效。
隨機片鍵對數據的均勻分布效果很好。注意盡量避免在多個分片上進行查詢。在所有分片上查詢,mongos會對結果進行歸並排序。
對集合進行分片時,你需要選擇一個片鍵,片鍵是每條記錄都必須包含的,且建立了索引的單個字段或復合字段,MongoDB按照片鍵將數據划分到不同的數據塊中,並將數據塊均衡地分布到所有分片中。
為了按照片鍵划分數據塊,MongoDB使用基於范圍的分片方式或者 基於哈希的分片方式。
注意:
分片鍵是不可變。
分片鍵必須有索引。
分片鍵大小限制512bytes。
分片鍵用於路由查詢。
MongoDB不接受已進行collection級分片的collection上插入無分片
鍵的文檔(也不支持空值插入)
2.3.2 以范圍為基礎的分片Sharded Cluster
Sharded Cluster支持將單個集合的數據分散存儲在多shard上,用戶可以指定根據集合內文檔的某個字段即shard key來進行范圍分片(range sharding)。
對於基於范圍的分片,MongoDB按照片鍵的范圍把數據分成不同部分。
假設有一個數字的片鍵:想象一個從負無窮到正無窮的直線,每一個片鍵的值都在直線上畫了一個點。MongoDB把這條直線划分為更短的不重疊的片段,並稱之為數據塊,每個數據塊包含了片鍵在一定范圍內的數據。在使用片鍵做范圍划分的系統中,擁有”相近”片鍵的文檔很可能存儲在同一個數據塊中,因此也會存儲在同一個分片中。
2.3.3 基於哈希的分片
分片過程中利用哈希索引作為分片的單個鍵,且哈希分片的片鍵只能使用一個字段,而基於哈希片鍵最大的好處就是保證數據在各個節點分布基本均勻。
對於基於哈希的分片,MongoDB計算一個字段的哈希值,並用這個哈希值來創建數據塊。在使用基於哈希分片的系統中,擁有”相近”片鍵的文檔很可能不會存儲在同一個數據塊中,因此數據的分離性更好一些。
Hash分片與范圍分片互補,能將文檔隨機的分散到各個chunk,充分的擴展寫能力,彌補了范圍分片的不足,但不能高效的服務范圍查詢,所有的范圍查詢要分發到后端所有的Shard才能找出滿足條件的文檔。
2.3.4 分片鍵選擇建議
1、遞增的sharding key
數據文件挪動小。(優勢)
因為數據文件遞增,所以會把insert的寫IO永久放在最后一片上,造成最后一片的寫熱點。同時,隨着最后一片的數據量增大,將不斷的發生遷移至之前的片上。
2、隨機的sharding key
數據分布均勻,insert的寫IO均勻分布在多個片上。(優勢)
大量的隨機IO,磁盤不堪重荷。
3、混合型key
大方向隨機遞增,小范圍隨機分布。
為了防止出現大量的chunk均衡遷移,可能造成的IO壓力。我們需要設置合理分片使用策略(片鍵的選擇、分片算法(range、hash))
分片注意:
分片鍵是不可變、分片鍵必須有索引、分片鍵大小限制512bytes、分片鍵用於路由查詢。
MongoDB不接受已進行collection級分片的collection上插入無分片鍵的文檔(也不支持空值插入)
后期運維
啟動關閉
mongodb的啟動順序是,先啟動配置服務器,在啟動分片,最后啟動mongos.
mongod -f /usr/local/mongodb/conf/config.conf mongod -f /usr/local/mongodb/conf/shard1.conf mongod -f /usr/local/mongodb/conf/shard2.conf mongod -f /usr/local/mongodb/conf/shard3.conf mongod -f /usr/local/mongodb/conf/mongos.conf
關閉時,直接killall殺掉所有進程
killall mongod
killall mongos
查看分片
mongos> db.runCommand({listShards:1})
查看分片狀態
mongos>sh.status()
@天才卧龍的博客