以下就是我們將要搭建的mongdb叢集架構建立第一個replset---------------------------------------------------------------------------------------------------------------------------------------------------建立目錄mkdir -p /data/replset_sharding/replset1/r0mkdir -p /data/replset_sharding/replset1/r1mkdir -p /data/replset_sharding/replset1/r2mkdir -p /data/replset_sharding/replset1/log改用下面的就行了(這是裡為方便看日誌,直接在命令列輸出查看)/Apps/mongo/bin/mongod --dbpath /data/replset_sharding/replset1/r0 --replSet replset1 --port 18010 --directoryperdb --rest/Apps/mongo/bin/mongod --dbpath /data/replset_sharding/replset1/r1 --replSet replset1 --port 18011 --directoryperdb --rest/Apps/mongo/bin/mongod --dbpath /data/replset_sharding/replset1/r2 --replSet replset1 --port 18012 --directoryperdb --rest初始化複本集:/Apps/mongo/bin/mongo --port 18010config_replset1 = {_id:"replset1",members:[{_id:0,host:"127.0.0.1:18010",priority:4},{_id:1,host:"127.0.0.1:18011",priority:2},{_id:2,host:"127.0.0.1:18012",arbiterOnly : true}]}注意arbiter仲裁節點只投票,不接收複製的資料!rs.initiate(config_replset1);---------------------------------------------------------------------------------------------------------------------------------------------------建立第二個replset---------------------------------------------------------------------------------------------------------------------------------------------------建立目錄mkdir -p /data/replset_sharding/replset2/r0mkdir -p /data/replset_sharding/replset2/r1mkdir -p /data/replset_sharding/replset2/r2mkdir -p /data/replset_sharding/replset2/log改用下面的就行了(這是裡為方便看日誌,直接在命令列輸出查看)/Apps/mongo/bin/mongod --dbpath /data/replset_sharding/replset2/r0 --replSet replset2 --port 28010 --directoryperdb --rest/Apps/mongo/bin/mongod --dbpath /data/replset_sharding/replset2/r1 --replSet replset2 --port 28011 --directoryperdb --rest/Apps/mongo/bin/mongod --dbpath /data/replset_sharding/replset2/r2 --replSet replset2 --port 28012 --directoryperdb --rest初始化複本集:/Apps/mongo/bin/mongo --port 28010config_replset2 = {_id:"replset2",members:[{_id:0,host:"127.0.0.1:28010",priority:4},{_id:1,host:"127.0.0.1:28011",priority:2},{_id:2,host:"127.0.0.1:28012",arbiterOnly : true}]}注意arbiter仲裁節點只投票,不接收複製的資料!rs.initiate(config_replset2);---------------------------------------------------------------------------------------------------------------------------------------------------建立第三個replset---------------------------------------------------------------------------------------------------------------------------------------------------建立目錄mkdir -p /data/replset_sharding/replset3/r0mkdir -p /data/replset_sharding/replset3/r1mkdir -p /data/replset_sharding/replset3/r2mkdir -p /data/replset_sharding/replset3/log改用下面的就行了(這是裡為方便看日誌,直接在命令列輸出查看)/Apps/mongo/bin/mongod --dbpath /data/replset_sharding/replset3/r0 --replSet replset3 --port 38010 --directoryperdb --rest/Apps/mongo/bin/mongod --dbpath /data/replset_sharding/replset3/r1 --replSet replset3 --port 38011 --directoryperdb --rest/Apps/mongo/bin/mongod --dbpath /data/replset_sharding/replset3/r2 --replSet replset3 --port 38012 --directoryperdb --rest初始化複本集:/Apps/mongo/bin/mongo --port 38010config_replset3 = {_id:"replset3",members:[{_id:0,host:"127.0.0.1:38010",priority:4},{_id:1,host:"127.0.0.1:38011",priority:2},{_id:2,host:"127.0.0.1:38012",arbiterOnly : true}]}注意arbiter仲裁節點只投票,不接收複製的資料!rs.initiate(config_replset3);------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//建立資料庫,記錄檔
mkdir -p /data/replset_sharding/log--------------------------------------------------------------------------------1,啟動Config Server, Config Server : 40000,40001,40002mkdir -p /data/replset_sharding/config0mkdir -p /data/replset_sharding/config1mkdir -p /data/replset_sharding/config2
/Apps/mongo/bin/mongod --dbpath /data/replset_sharding/config0 --configsvr --port 40000 --directoryperdb --rest/Apps/mongo/bin/mongod --dbpath /data/replset_sharding/config1 --configsvr --port 40001 --directoryperdb --rest/Apps/mongo/bin/mongod --dbpath /data/replset_sharding/config2 --configsvr --port 40002 --directoryperdb --rest
正式運行要後台運行就用下面的:/Apps/mongo/bin/mongod --dbpath /data/replset_sharding/config --configsvr --port 40000 --logpath /data/replset_sharding/log/config.log --fork --directoryperdb --rest------------------------------------------------------------------------------------------------------------------------------以上的3個Config Server裡存放叢集分區的配置資訊,如果Config Server出問題是無法正常啟動叢集的!設定管理員使用的是兩步提交機制(而不是普通MongoDB複本集的非同步複製),因為兩步提交是即時的一致性,而非同步複製是最終一致性!
兩步提交機制確保3台機的配置是一致的,如果有某台設定管理員宕機了,那叢集配置資訊將是唯讀! 用戶端還是能夠讀取叢集的資料,還有能有限地更新叢集的資料(只要不需要修改設定管理員的配置,如chunks塊的修改,或片鍵的修改)PS:整個叢集的admin資料庫是存放在Config Sever中的,而3台Config Server不止資料庫config是同步的,而且資料庫admin也是同步的--------------------------------------------------------------------------------2,啟動Route Process,Route Process : 50000/Apps/mongo/bin/mongos --port 50000 --configdb 127.0.0.1:40000,127.0.0.1:40001,127.0.0.1:40002 --chunkSize 1 --chunkSize 1 (MB)指定分區的最小單位容量,這裡設定1M,方便查看效果 正式運行要後台運行就用下面的:/Apps/mongo/bin/mongos --port 50000 --configdb 127.0.0.1:40000 --chunkSize 50 --logpath=/data/replset_sharding/log/route.log --fork--------------------------------------------------------------------------------3,串連到mongos配置Sharding用Mongo Shell 登入 Route Process/Apps/mongo/bin/mongo --port 50000 use admin (記得執行這一點,切換到admin資料庫)//添加分區節點,每個分區都是一個複本集db.runCommand({addshard:"replset1/127.0.0.1:18010,127.0.0.1:18011,127.0.0.1:18012",allowLocal:true})db.runCommand({addshard:"replset2/127.0.0.1:28010,127.0.0.1:28011,127.0.0.1:28012",allowLocal:true})db.runCommand({addshard:"replset3/127.0.0.1:38010,127.0.0.1:38011,127.0.0.1:38012",allowLocal:true})(allowLocal:true僅僅開發時才將分區配置到本地,生產時不能這樣)-----------------------------------------------------------------------------------:配置資訊被添加到Config Server的config資料庫的shards集合中:你會發覺,arbiter仲裁節點因為不接收資料,所以直接被mongos在設定階段就去掉,db.runCommand({addshard:"replset1/127.0.0.1:18010,127.0.0.1:18011,127.0.0.1:18012",allowLocal:true})
等價於:db.runCommand({addshard:"replset1/127.0.0.1:18010,127.0.0.1:18011",allowLocal:true})
-----------------------------------------------------------------------------------
//A,設定資料庫mydb,啟用分區use admindb.runCommand({enablesharding:"mydb"})此時資料庫mydb是以分區replset3為基片(primary shard)mydb被配置成啟用分區後,配置資訊是存放在設定管理員的資料庫config的databases集合裡!
//B,設定要分區的集合:使集合users以片鍵_id來分區db.runCommand({shardcollection:"mydb.users",key:{_id:1}})mydb的users集合被配置成啟用分區後,配置資訊是存放在設定管理員的資料庫config的collections集合裡!
--------------------------------------------------------------------------------這裡可以看到,路由伺服器是不會存放配置資訊(不用配置dbpath也是這個原因,但會緩衝設定管理員上的配置!)5,Sharding,遞增片鍵方式插入資料/Apps/mongo/bin/mongo --port 50000 use mydb測試插入60萬條資料for(var i=1; i<=600000; i++) db.users.insert({age:i,name:"jack",addr:"guangzhou",country:"China"})use admin執行:db.runCommand({enablesharding:"mydb"})使資料庫啟用分區db.runCommand({ shardcollection:"mydb.users",key:{_id:1} }) 使集合users以_id為Sharding Key分區然後等幾分鐘,集合users的資料就均勻分布到各個分區,分區完成1,先看看每個trunk,這裡測試需要,設定了1MB/trunk,每個trunk記錄了片鍵的範圍,還有所在的片--------------------------------------------------------------------------因為Sharding key 是ObjectId這裡ObjectId就像一個遞增片鍵,插入時不能均勻地路由到各片,此時寫入的負載很不均勻,集中在一台機器上!
:Balancer正在移動分區的塊chunk
在遞增片鍵的情況下,資料剛插入完後,資料的分區不均勻,所以資料插入完後,mongos就會用Balancer進行資料的負載平衡!如: Balancer正在執行負載平衡,此時要用到鎖,MongoDB 2.2.0 引入了DB層級的鎖,不知道分區時是不是也是DB層級的鎖呢?這會鎖定分區的資料庫mydb圖: mongos的Balancer正在執行負載平衡圖: mongos的Balancer正在執行負載平衡圖: mongos的Balancer正在執行負載平衡
圖: mongos的Balancer正在執行負載平衡-----------------------------------------------------------------------------過了10+分鐘的狀態,此時應該分區"均勻"了..細心發覺,怎麼"均勻"呢??每個片的chunks是均勻了,每個片的chunks都是33個,因為片replset2是資料庫mydb的primary片(),又因為此時是遞增片,開始時60萬條記錄全部都插入到這個片中,又因為我們給mongos設定的--chunkSize是1Mb,所以給replset2片均衡資料時,使其每個trunk的size均衡到接近1M就可以了(實際是1.1),6,Sharding,隨機片鍵方式插入資料/Apps/mongo/bin/mongo --port 50000 use admin執行:db.runCommand({enablesharding:"mydb"})使資料庫啟用分區db.runCommand({ shardcollection:"mydb.user2",key:{shardkey:1} }) 使集合user2以shardkey為Sharding Key分區空集合user2以shardkey為Sharding Key分區後,就會在設定管理員分配一個(-∞,+∞)的chunks塊給資料庫mydb的基片replset3,基片很重要,對於一個不分區的集合是存放在基片中的,而對於分區的集合,每一個無限大的chunks塊也是分配給基片的!use mydb測試插入60萬條資料,這裡產生的shardkeyfor(var i=1; i<=600000; i++) db.user2.insert({name:"a long name",age:i,addr:"a long address guangzhou",country:"China", shardkey: Math.random()})因為剛開始裡,設定管理員裡沒有chunks塊,第一個無限大的塊位於基片上,而後來邊向資料庫插入資料邊分裂出更細的chunks塊,這時分裂出的塊主要分布在基片shard000上所以導致插入操作集中在基片上執行!現在把集合user2裡的資料全部remove掉!那集合就是剩下chunks塊的資訊(在設定管理員裡)圖:集合user2清空後,各片的chunks塊數量也不均勻圖:沒資料,也會對各片進行chunks塊數量調整,直至數量平均!(再次說明:mongos路由負載平衡的本質是: 在後台對各片進行負載平衡,直至各片的chunks塊數量相等!)向已有69個chunks塊(塊分布均勻)的空集合插入30萬個隨機鍵的文檔for(var i=1; i<=300000; i++) db.user2.insert({name:"a long name",age:i,addr:"a long address guangzhou",country:"China", shardkey: Math.random()})
可見,向已有69個chunks塊(塊分布均勻)的空集合插入30萬個隨機鍵的文檔整個插入過程是相當均勻!而塊的數量僅僅增加了6塊,就是說30萬個文檔幾乎全部"命中"已存在的各個塊!-------------------------------------------------------------------------------------------8,測試6和7的小結
1:如果剛開始對於新的集合,設定管理員裡沒有該集合的chunks塊資訊,這裡無論是遞增鍵或隨機鍵, 資料的插入過程也不會均勻,甚至有可能集中在某台機器上,然後mongos再來執行負載平衡
2: mongos路由會在後台對各片進行負載平衡,直至各片的chunks塊數量相等!
3: 對於負載平衡的Sharding Cluster(各片的chunks塊數量相等),對於隨機鍵的操作會非常有效,基本整個過程是很均勻的 而此時遞增鍵的操作還是會出現嚴重的負載不均衡的情況!
--------------------------------------------------------------------------------5,對現有的表執行Sharding/Apps/mongo/bin/mongo --port 50000 use mydb測試插入60萬條資料for(var i=1; i<=600000; i++) db.users.insert({age:i,name:"irelandken",addr:"guangzhou",country:"China"})然後等幾分鐘,集合users的資料就均勻分布到各個分區,分區完成--------------------------------------------------------------------------------6,移除Shard Server,回收資料db.runCommand({"removeshard" : "127.0.0.1:38010"})因為127.0.0.1:38010是資料庫test和mydb的Primary片"primary" : "shard0000"基片,所以要手動移動資料庫的基片如:/* 1 */{ "_id" : "test", "partitioned" : true, "primary" : "shard0000"}/* 2 */{ "_id" : "mydb", "partitioned" : true, "primary" : "shard0000"}手動修改資料庫test的基片,改為127.0.0.1:38011執行: mongos> db.runCommand({"moveprimary" : "test","to" : "127.0.0.1:38011"}){ "primary " : "shard0001:127.0.0.1:38011", "ok" : 1 }手動修改資料庫test的基片,改為127.0.0.1:38011執行: mongos> db.runCommand({"moveprimary" : "mydb","to" : "127.0.0.1:38011"}){ "primary " : "shard0001:127.0.0.1:38011", "ok" : 1 }依賴要刪除的片的關係全部刪除後,再找執行一次:db.runCommand({"removeshard" : "127.0.0.1:38010"})mongos> db.runCommand({"removeshard" : "127.0.0.1:38010"}){ "msg" : "removeshard completed successfully", "state" : "completed", "shard" : "shard0000", "ok" : 1}mongos分回收該片的資料,平均到其它片,然後在分區叢集中移除該片!多次調用這一句,中間可以看到進行的進度!此操作對使用者完全透明,不需要停機操作!--------------------------------------------------------------------------------7,新增Shard Server串連到mongos因為在各分區裡存在資料庫test和mydb的集合的分區,而規定加入的新mongod不能含有相同的資料庫(試想如果加入的資料庫含有資料庫mydb,且其中含有一定數量的資料,此資料一定要被刪除)向mongos新加入的Shard Server一定不能含有與其它片相同的資料庫的!use admindb.runCommand({addshard:"127.0.0.1:38010",allowLocal:true})新的片被加入後,mongos再次將次執行負載平衡,將資料均勻到各片中!--------------------------------------------------------------------------------從各部分的LOG來看,只有節點Shard Server和路由Route Process是比較"忙"的,Config Server好像僅僅只是同步Route Process的配置而已,因為路由Route Process不會持久化資料,Config Server為它存放配置感覺路由Route Process是一個Facade,外部看來是一個資料庫