要在真實環境中實現MongoDB分片至少須要四臺服務器作分片集羣服務器,其中包含兩個Shard分片副本集(每一個包含兩個副本節點及一個仲裁節點)、一個配置副本集(三個副本節點,配置不須要仲裁節點),其中Shard的副本節點必須擁有單獨的服務器,一般一個Shard副本集由3個以上副本節點組成更好,奇數個副本節點不須要額外配置仲裁節點。由於仲裁節點和配置節點不須要耗費不少的資源,能夠與其餘進程共享一臺服務器。數據庫
固然了,對於平時學習而言,配置那麼多服務器是不現實的,用VM虛擬機也不現實,畢竟MongoDB內存開銷不小,因此暫時將全部須要的數據庫配置在同一臺電腦,以不一樣端口區分,其中包含如下幾個數據庫服務器
Shard節點app
Shard-a-1 端口 37001學習
Shard-a-2 端口 37002spa
Shard-a-3 端口 370033d
-------------------------------------------------------------------- rest
Shard-b-1 端口 37011日誌
Shard-b-2 端口 37012code
Shard-b-3 端口 37013router
Config節點
Config-1 端口 41001
Config-2 端口 41002
Config-3 端口 41003
Router節點
Router 端口 50000
文件目錄大概以下,其中router中的config改成 mongos.cfg
其中Shard節點和Config節點和開啓普通MongoDB數據庫同樣,用Mongod啓動,在Windows下不能使用 fork參數後臺化,我的更推薦使用Service來託管
其中Shard節點的配置以下,每一個文件夾下對應的配置把dbpath/logpath/replSet(shard-a和shard-b)改掉,由於要開啓多個db因此httpinterface設置爲false,不開啓監聽,不然每一個db都會對應多一個端口號+1000的監聽端口,37002的監聽端口爲38002
dbpath=D:\mongodatas\shard-a2\data
logpath=D:\mongodatas\shard-a2\log\mongod.log
logappend=true
directoryperdb=true
rest=true
httpinterface=false
port=37002
shardsvr=true
replSet=shard-a
Config節點的配置以下,與shard節點的區別就是shardsvr換成了configsvr,配置服務器是不會開啓監聽端口的
dbpath=D:\mongodatas\config1\data
logpath=D:\mongodatas\config1\log\mongod.log
logappend=true
directoryperdb=true
rest=true
port=41001
configsvr=true
replSet=configset
接下來以託管到Service的方式啓動全部的Shard節點和Config節點,如下只是啓動其中一個,一共有九個(shard-a有3個,shard-b有3個,config有3個),在命令提示符(管理員) 的窗口執行,普通權限會報錯的,下文用到Service的同樣
sc create MongoShardA1 binPath= "C:\Program Files\MongoDB\Server\3.4\bin\mongod.exe --config=D:\mongodatas\shard-a1\mongod.cfg --service"
net start MongoShardA1
使用命令 services.msc打開服務窗口查看服務是否開啓或者使用 netstat -nao指令查端口是否開啓,若是全都正常開啓,則開始配置Shard副本集
任意鏈接shard-a中服務器 (37001/37002/37003)打開MongoDB Shell
mongo --port 37001
對副本集進行初始化,若是對rs方法不熟悉,可使用rs.help()顯示幫助文檔
rs.initiate()
此時發現37001端口的命令輸入已經成爲了副本集的形式,接下來添加另外兩個成員,一個副本節點,一個仲裁節點
rs.add("localhost:37002")
rs.add("localhost:37003",{arbiterOnly:true})
最好使用本機的內網地址,而不是使用localhost或者127.0.0.1
接下來查看副本集是否運行正常
rs.status()
退出現有MongoDB Shell或者開啓新的CMD進入Shard-b中任意服務器對Shard-b副本集進行初始化,進入Config副本集任意服務器對Config副本集進行初始化,注意Config副本集進行初始化的時候不須要指定仲裁節點
以上全部操做,對Config副本集進行初始化很是重要,網上有不少示例都沒有對Config副本集進行初始化,會致使mongos服務沒法開啓,鏈接不上router服務器
如今開始配置router的配置mongos.cfg
configdb=configset/DESKTOP-4NVUAKK:41001,192.168.20.229:41002,192.168.20.229:41003
logpath=D:\mongodatas\router\log\mongod.log
logappend=true
port=50000
注意configdb的配置,新版本里面採用 replSet/hsot:port,host:port的形式,其中host必須採用config副本集裏面rs.status()出來的members中的name,不然會執行失敗,若是configdb中的副本集沒有執行初始化設定Primary ,此時用Service是沒法啓動成功的,可是用指令啓動會給人一種啓動成功的假象,查看router對應的日誌會發現一隻在嘗試鏈接Config副本集: No primary detected for set configset,此時查看任務管理器會發現有mongos的進程,查看端口會發現router的端口並未打開
以託管到Service的方式開始Router服務
sc create MongoRouter binPath= "C:\Program Files\MongoDB\Server\3.4\bin\mongos.exe --config=D:\mongodatas\shard-a1\mongos.cfg --service"
net start MongoRouter
注意上面的執行程序是mongos而不是mongod 配置文件名不要弄錯了
正常啓動Router服務器以後,鏈接到router數據庫的MongoDB Shell
mongo --port 50000
開始爲router指定分片副本集,具體操做如截圖所示
sh.addShard("replSet/host:port,host:port")
注意不要使用localhost或者127.0.0.1,不然會報錯
使用與副本集Members裏面name不一致的host也是會報錯的
正常狀況下添加成功以下
查看數據庫config中的shards集合
db.getSiblingDB("config").shards.find() 或者 db.runCommand({listshards:1})
到如今爲止,分片環境已經搭建成功,但要引用到數據庫和文檔上,還須要對數據庫和文檔進行分片
開啓一個數據庫上的分片,這是對任何集合進行分片的先決條件
sh.enableSharding("dbName")
完成以後去config裏查看是否分片
db.getSiblingDB("config").databases.find()
對數據庫上的某個集合進行分片,要定義一個分片鍵,可使用組合分片建,像我使用的是author和_id的組合,若是是對現有集合進行分片,必須在運行shardcollection命令前建立一個與分片鍵對應的索引
sh.shardCollection("dbName.collectionName",{key1:1,key2:1})
db.getSiblingDB("config").collections.find()
對空集合進行、分片時 MongoDB會字每一個分片上建立一個與分片鍵對應的索引,能夠直接鏈接分片,用getIndexes()驗證,此時數據量還沒達到分片標準啊,分片shard-a副本集尚未建立books
用客戶端鏈接router服務器(和鏈接普通服務器同樣)插入大量數據,調用sh.status()能夠看到分配到兩個shard上保存了
db.chunks.count("shard","shard-a")
db.chunks.count("shard","shard-b")
查看拆分次數
db.changelog.count({what:"split"})
查看遷移次數
db.changelog.find({what:"moveChunk.commit"}).count()
能夠經過db.books.find(****).explain() 查看執行計劃
若是查詢條件包含分片鍵,則能很快找到對應分區 針對性查詢,不然將遍歷全部分區 全局/分散/彙集查詢
db.books.ensureIndex({title:1}) 在title上建立索引
每一個分片都維護本身的索引,每一個分片上的分片集合都應該擁有相同的索引
分片集合只容許在_id字段和分片鍵上添加惟一索引
分片鍵是不能夠修改的,不要使用升序分片鍵,粒度不能太細(如照片就不該該按md5分,而應該按所屬人分)
副本集的每一個成員都應該在一個單獨的服務器上,用於複製的成員要有本身的機器,
仲裁節點和配置節點能夠與其餘進程共享主機,但須要部署在不一樣服務器
少數大分片比大量小分片好
手動塊拆分
sh.splitAt("dbname.collectionName",{key,value,key:value}) 根據key分塊 value是數據庫中的值,根據這個值拆分紅兩塊
sh.moveChunk("dbname.collectionName",{key,value},"shardB") 將包含key爲value的文檔移動到分片B