MongoDB分片
1 分片:数据库横向扩展的一种办法
1.1.1 分片目标:
全部工作自动化进行;保持不同片间的数据平衡;尽量最小化不同片间交叉的数据块大小;分布式存储,从而实现分布式读写,负载平衡
1.1.2 分片三大组件:
分片:一个分片就是一个数据库实例或者一个副本集,用来存放数据库集合的部分数据
配置服务器:也是一个数据库实例,用来存放集群的元数据,实现数据块与分片之间的映射。当集群中某个配置服务器down了,其他的配置服务器会变成只读,也就是说不能再进行数据块分裂和移动了。
路由进程(mongos):路由进程把配置服务器的数据复制到内存,依据配置服务器的分块和分片映射关系,把应用程序的读写操作映射到相应分片
2 片键:Sharding key
片键就是数据分块的依据
当数据大小超过一个分块(chunk)时会根据sharding key被split到两个新的chunk中,当两个分片的分块数量达到一定差异,平衡器开始工作。
数据迁移的基本单元是chunk,2.4.4版本默认值为64M,可调整大小。
迁移时先把要迁移的数据从磁盘读到内存,再进行迁移,所以可能会引起热数据被剔除,形成swap颠簸
Sharding前选取良好的Sharding Key非常重要
Sharding Key选取原则:
避免小基数热点片键,如{name:1},如果name取值较少,一个大数据量name所有数据会集中在同一chunk中,这样导致name不易拆分,当chunk满时会出现整块迁移。
写可扩展性,如果用{time:1}作为片键,导致所有的写操作都会落在最新的一个Chunk上去,这样就形成了一个热点区域,选择{name:1,time:1}来作为片键,那么每一个name上的数据将会写在不同的地方
避免随机片键,此方案chunk迁移时的数据有可能是冷数据,不在内存中,会不断进行磁盘交换,严重影响性能。使用随机分片时,写入操作写到不同分片上,但是查询时候由于从不同分片查询,会受到网络,mongos性能等影响影响。而且随机片键还要建立额外索引。
查询隔离,理想的情况是一个查询直接路由到一个实例上去,并且这个实例拥有该次查询的全部数据,如果分散到各个片查询并汇总,会增加mongos主机负载、响应时间与网络成本。
由于Sharding key必须建立索引,有排序查询时以Sharding Key开头的字段为依据最佳。
选择片键时尽量能保持良好的数据局部性而又不会导致过度热点的出现。局部性可以保证查询隔离,不太过分的局部性又可以保证写入分散,组合片键是一种比较常用的做法
1.2 基片
没有分片的集合数据始终存放在一个分片上,这个分片叫做基片,可以用movePrimary命令改变基片,此命令要移动数据,移动期间数据不可操作
1.3 路由操作
路由操作包括Broadcast Operations和Targeted Operations操作,如果路由无法确定针对那个分片进行操作,那么他会把操作广播到所有的分片上。最重要的是查询和插入操作,删除,更新,操作都是建立在查询基础上的。如果有个片键是{ a: 1, b: 1, c: 1 },那么按照条件{a: 1 },{ a: 1, b: 1 },{ a: 1, b: 1 ,c:1}进行的操作都是Targeted Operations操作。
1.4 Shard Key Indexes
每一个片键都需要索引。对于一个空集合,启用分片后,会自动为片键建立索引,对于一个已经有文档的集合,启用分片后,需要手动建立索引,因为需要建立和分片相关索引。2.2版本以后,不再需要手动建立索引了,可以继续用之前的索引,甚至可以用之前的复合索引,只要复合索引的第一个字段是片键。
1.5 分片平衡器:Shard Balancing
当一个分片上分块太多,就需要平衡器移动分块。一次的分块移动可以由集群中的任何一个mongos发出命令。当平衡器启动时,mongos获得了一个锁,修改配置服务器lock集合中列出的文档。
为了不影响性能,只有分块数量超过了移动阀值时候,才进行分块移动。
数据移动的过程实际就是把数据复制到内存,再发送给recivers。在复制过程中,如果还有数据写入,待移动完成后,from服务器会把新的写操作发送个recivers,从而实现一致性。
1.6 Migration Thresholds
分块移动阀值是一个很重要的内容,因为他决定了何时进行数据块移动:
只有当分块最多的分片比分块最少的分片的分块差值(就是阀值)达到一定数量时,分块移动才会发生。当然,也可以自定义分块移动的规则
分块移动结束的条件:
1. 分片之间分块数量差小于2
2. 分块失败,可能有一些大块,mongodb考虑系统性能,不会移动大块。
1.7 Chunk size
默认,当分块大小达到64m后,mongos进程会把它一分为二,剩下来的分块增大后也会发生分裂,分裂的前提是片键有足够多的值,否则大块不会分裂。因为mongodb有个规则:不同块之间,片键值尽量不能有重合的。
随着在基片上的分片越来越多,满足阀值后,就开始进行分块移动。
分块小,移动过于频繁,不仅服务器负担过重,而且路由进程无法实现查询隔离。
分块大,移动不频繁,但是可能使得分片之间不均匀。一般使用默认的64m应该是可以的
1.8 分片大小
默认,mongodb没有限制分片占用空间的大小。在添加分片时候,我们可以使用maxSize参数(单位是mb)指定分片大小。
例如:db.runCommand( { addshard : "example.net:34008", maxSize : 125 } )
当然,还可以更新它:
use config
db.shards.update( { _id : "shard0000" }, { $set : { maxSize : 125 } } )
1.9 分块移动过程:
1. Balaner进程发送moveChunk命令给源分片,请求分块,同时,还传递目的分片的名字。
2. 源分片开始internal moveChunk命令,并且告知目的分块。
3. 目的分片请求分块,并且接受分块。
4 分块接收完成后,目的分片启动一个同步进程,保证移动期间分块上文档的更新得到同步。
1. 同步完成后目的分片连接到配置服务器,更新分块在配置服务器中的信息。
2. 移动结束后,待分块上不再有打开的游标后,源分片删除被复制的分块。(这就是为什么会看到文档数在减少的原因!)
[mongo_44 ~]# tail -f /mongodb/sh1/logs/sh1.log | grep hash
Wed Jul 24 21:53:00.783 [cleanupOldData-51efd92800251121b1508bf3] moveChunk starting delete for: test.test_hash from { C_ID: -2448670538483119681 } -> { C_ID: -1633697876468216578 }
1.10 Detect Connections tomongosInstances
判断连接的是一个路由进程还是普通mongd进程
mongos> db.isMaster()
{
"ismaster" : true,
"msg" : "isdbgrid",
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"localTime" : ISODate("2013-07-24T13:39:50.474Z"),
"ok" : 1
}
通过上面的红色部分,可以判断连接的是一个路由进程,普通的mongo是没有这个的。
1.11 配置服务器的管理
配置服务器存放如下信息:
分块与分片之间的对应关系(chunks集合)
被分片的集合(colecionts)
分片和配置服务器上的数据库信息(databases)
数据移动阶段的锁定(locks)
连接到配置服务器上的mongos实例信息(mongos)
分块设置(settings)
分片信息(shards)
集群环境一般要求具备三个以上配置服务器,各配置服务器节点之间采用两步提交方式,两步提交方式就是各个节点要么同时成功,要么同时失败。因为只有这样才能保证各节点实时同步,数据一致,而非普通的副本集数据复制方式。
配置服务器与路由进程的关系:
路由进程把配置服务器中的数据复制到自己的内存中,在下面条件下对配置服务器进行写入操作:
1. 大块分裂:
2. 分块移动:
在以下条件下,配置服务器将会变成只读的:
集群中有一个配置服务器宕机
路由进程第一次启动,或者重启
分片移动完成后,mongos利用应用配置服务器上新的元数据更新他们自己的内存区间
如果全部的配置服务器宕机后,由于路由存在,集群也可以正常运行,只是不能分块,移动分块。一旦路由进程重启,由于丢失内存数据,集群无法正常工作
1.12 Administration:
1.12.1 Start the Config Server Database Instances
配置服务器存放的是元数据,这些元数据是分片和分块的映射关系,分片的数据库,集合,块大小,片键等信息。
生产环境中,至少部署三台配置服务器,分别放在不同的机器上:
三台机器上分别执行:
[mongo_46 /mongodb/config/data]# mkdir -p /mongodb/config/data/
[mongo_46 /mongodb/config/data]# mkdir -p /mongodb/config/data/logs
numactl --interleave=all mongod --dbpath /mongodb/config/data \
--configsvr --port 20000 \
--logpath /mongodb/config/logs/config.log --fork --directoryperdb --rest
在进行分片之前,所有的配置服务器必须正常启动
1.12.2 Start the mongosIns tances
启用路由进程
路由进程:轻量级进程,用于缓存配置服务器数据,他是应用服务器访问的对象,根据分片和分块映射关系,把应用服务器的查询和插入请求转发到到不同分片。
mongos --port 30000 --configdb 192.168.69.44:20000,192.168.69.45:20000,192.168.69.46:20000 \
--logpath=/mongodb/route/route.log --fork
1.12.3 Add Shards to the Cluster
连接路由进程,查看当前分片状态:
[mongo_44 /mongodb]# mongo --port 30000
mongos> printShardingStatus() --查看分片状态,等同于sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"version" : 3,
"minCompatibleVersion" : 3,
"currentVersion" : 4,
"clusterId" : ObjectId("51ee3497606475660484bf2c")
}
shards:
databases:
{ "_id" : "admin", "partitioned" : false, "primary" : "config" }
mongos> use admin
switched to db admin
mongos> db.runCommand({ listshards: 1 }) --列出分片
{ "shards" : [ ], "ok" : 1 }
mongos> db.runCommand({ isdbgrid:1 })
{ "isdbgrid" : 1, "hostname" : "mongo_44", "ok" : 1 } --判断能否进行分片
分片可以是standalone mongod,生产环境中分片一般是一个副本集。
mongos> sh.addShard("sh1/192.168.69.44:10000,192.168.69.45:10000,192.168.69.46:10000") --可以不写仲裁节点
{ "shardAdded" : "sh1", "ok" : 1 }
添加第分片后,config db会把除了admin,local外的数据库看做是基片
为数据库启用分片:如果不启用分片,他会把所有的数据放在基片上!
mongos> sh.enableSharding("test")
{ "ok" : 1 }
a启用分片后检查,”partitioned”为true
mongos> sh.enableSharding("test")
{ "ok" : 1 }
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"version" : 3,
"minCompatibleVersion" : 3,
"currentVersion" : 4,
"clusterId" : ObjectId("51ee3497606475660484bf2c")
}
shards:
{ "_id" : "sh1", "host" : "sh1/192.168.69.44:10000,192.168.69.45:10000,192.168.69.46:10000" }
databases:
{ "_id" : "admin", "partitioned" : false, "primary" : "config" }
{ "_id" : "test", "partitioned" : true, "primary" : "sh1" }
接下来,本别为几个集合进行分片,分别为单个片键,复合片键,哈希索引分片。
mongos> sh.shardCollection("test.sin", { "C_ID": 1 } ) --单字段片键
{ "collectionsharded" : "test.sin", "ok" : 1 }
mongos> sh.shardCollection("test.com", { "C_ID": 1, "TIME": 1 } ) --复合片键
{ "collectionsharded" : "test.com", "ok" : 1 }
mongos> db.test_hash.ensureIndex( { C_ID: "hashed" } ) --启用哈希索引
mongos> sh.shardCollection("test.test_hash", { "C_ID": "hashed" } ) --哈希索引片键
{ "collectionsharded" : "test.test_hash", "ok" : 1 }
对于一个已经有数据的集合,如果要进行分片,需要先对片键建立索引。
再添加分片:
分别在三台服务器上启动集成,构成副本集sh2
numactl --interleave=all /mongodb/bin/mongod --replSet sh2 --port 10001 \
--dbpath=/mongodb/sh2/data --logpath=/mongodb/sh2/logs/sh2.log --logappend –fork
初始化副本集:
[mongo_44 /mongodb]# mongo --port 10001
use admin
switched to db admin
>
db.runCommand({"replSetInitiate" :
{"_id" : "sh2",
"members" : [{"_id" : 1, "host" : "192.168.69.44:10001"},
{"_id" : 2, "host" : "192.168.69.45:10001","priority":5},
{"_id" : 3, "host" : "192.168.69.46:10001"}
]}})
添加分片:
[mongo_44 /mongodb]# mongo --port 30000
MongoDB shell version: 2.4.4
connecting to: 127.0.0.1:30000/test
mongos> sh.addShard("sh2/192.168.69.44:10001,192.168.69.45:10001,192.168.69.46:10001")
{ "shardAdded" : "sh2", "ok" : 1 }
如果新分片上有和旧分片相同的数据库,添加会失败:
mongos> sh.addShard("sh2/192.168.69.44:10001,192.168.69.45:10001,192.168.69.46:10001")
{
"ok" : 0,
"errmsg" : "can't add shard sh2/192.168.69.44:10001,192.168.69.45:10001,192.168.69.46:10001
because a local database 'test' exists in another sh1:sh1/192.168.69.44:10000,192.168.69.45:10000,192.168.69.46:10000"
}
在这种情况下需要删除这个数据库:
sh2:PRIMARY> use test
switched to db test
sh2:PRIMARY> db.dropDatabase()
{ "dropped" : "test", "ok" : 1 }
db.dropDatabase()
1.12.4 插入数据,观察分片:
mongos> db.sin.getShardDistribution()
Shard sh1 at sh1/192.168.69.44:10000,192.168.69.45:10000,192.168.69.46:10000
data : 245.41MiB docs : 946100 chunks : 10
estimated data per chunk : 24.54MiB
estimated docs per chunk : 94610
Shard sh2 at sh2/192.168.69.44:10001,192.168.69.45:10001,192.168.69.46:10001
data : 265.62MiB docs : 1024000 chunks : 10
estimated data per chunk : 26.56MiB
estimated docs per chunk : 102400
Totals
data : 511.04MiB docs : 1970100 chunks : 20
Shard sh1 contains 48.02% data, 48.02% docs in cluster, avg obj size on shard : 271B
Shard sh2 contains 51.97% data, 51.97% docs in cluster, avg obj size on shard : 272B
1.12.5 移除分片(不能是基片,否则需要修改基片,修改基片会引发数据移动):
mongos> db.runCommand( { removeShard: "sh2" } )
……………………………………………………………………………………
"sh1/192.168.69.44:10000,192.168.69.45:10000,192.168.69.46:10000"
},
{
"_id" : "sh2",
"draining" : true,
"host" : "sh2/192.168.69.44:10001,192.168.69.45:10001,192.168.69.46:10001"
}
],
"ok" : 1
}
1.12.6 为分片和ranges添加tags:
sh.addShardTag("sh2", "222")
mongos> db.shards.find()
{ "_id" : "sh1", "host" : "sh1/192.168.69.44:10000,192.168.69.45:10000,192.168.69.46:10000", "tags" : [ "111" ] }
{ "_id" : "sh2", "host" : "sh2/192.168.69.44:10001,192.168.69.45:10001,192.168.69.46:10001", "tags" : [ "222" ] }
C_ID数值为0-2000,现在分成四个部分,
sh.addTagRange("test.com", { C_ID: "1" }, { C_ID: "500" }, "first")
sh.addTagRange("test.com", { C_ID: "500" }, { C_ID: "1000" }, "second")
sh.addTagRange("test.com", { C_ID: "1000" }, { C_ID: "1500" }, "third")
sh.addTagRange("test.com", { C_ID: "1500" }, { C_ID: "2000" }, "first")
mongos> use config
switched to db config
mongos> db.tags.find()
{ "_id" : { "ns" : "test.com", "min" : { "C_ID" : "1" } }, "ns" : "test.com", "min" : { "C_ID" : "1" }, "max" : { "C_ID" : "500" }, "tag" : "first" }
{ "_id" : { "ns" : "test.com", "min" : { "C_ID" : "500" } }, "ns" : "test.com", "min" : { "C_ID" : "500" }, "max" : { "C_ID" : "1000" }, "tag" : "second" }
{ "_id" : { "ns" : "test.com", "min" : { "C_ID" : "1000" } }, "ns" : "test.com", "min" : { "C_ID" : "1000" }, "max" : { "C_ID" : "1500" }, "tag" : "third" }
{ "_id" : { "ns" : "test.com", "min" : { "C_ID" : "1500" } }, "ns" : "test.com", "min" : { "C_ID" : "1500" }, "max" : { "C_ID" : "2000" }, "tag" : "forth" }
删除其中一个tags
db.tags.remove({ _id: { ns: "test.com", min: { C_ID: "500" }}, tag: "second" })
1.12.7 修改索引
集合test.sin的索引是{C_ID:1},现在修改为{CID:1,TIME:1}
可进行如下操作:
1. 建立新的复合索引:
mongos> db.sin.ensureIndex({C_ID:1,TIME:1})
2. 建立完成后删除原来的索引
mongos> db.sin.dropIndex({C_ID:1})
{
"raw" : {
"sh1/192.168.69.44:10000,192.168.69.45:10000,192.168.69.46:10000" : {
"nIndexesWas" : 3,
"ok" : 1
}
},
"ok" : 1
}
注意:如果time字段中有数组文档,则不能使用上面命令!
1.13 问题
1. 配置服务器从1台扩展到3台
(1).关闭所有的mongod进程和mongos进程:
先关闭mongos进程,再关闭配置服务器进程和副本集
./stop.sh
(2).从现有配置服务器拷贝文件(拷贝目录)
[mongo_44 /mongodb]# cp config config1 –rf
[mongo_44 /mongodb]# cp config config2 –rf
(3)启动配置服务器进程(包括新添加的)
numactl --interleave=all mongod --dbpath /mongodb/config/data --configsvr --port 20000 --logpath /mongodb/config/logs/config.log --fork --directoryperdb
启动新的配置服务器进程:
numactl --interleave=all mongod --dbpath /mongodb/config1/data --configsvr --port 20001 --logpath /mongodb/config1/logs/config1.log --fork --directoryperdb
numactl --interleave=all mongod --dbpath /mongodb/config2/data --configsvr --port 20002 --logpath /mongodb/config2/logs/config2.log --fork --directoryperdb
(4)启动副本集
numactl --interleave=all /mongodb/bin/mongod --replSet sh3 --port 10002 --dbpath=/mongodb/sh3/data --logpath=/mongodb/sh3/logs/sh3.log --fork
numactl --interleave=all /mongodb/bin/mongod --replSet sh2 --port 10001 --dbpath=/mongodb/sh2/data --logpath=/mongodb/sh2/logs/sh2.log --fork
numactl --interleave=all /mongodb/bin/mongod --replSet sh1 --port 10000 --dbpath=/mongodb/sh1/data --logpath=/mongodb/sh1/logs/sh1.log –fork
(5).启动路由进程,路由进程要包含新的配置服务器
Mongos --port 30000 --configdb 192.168.69.44:20000,192.168.69.44:20001,192.168.69.44:20002 \
--logpath=/mongodb/route/route.log –fork
2.1.1 手动分块
有时候分块过大,由于基数较小,导致大块无法分裂,这时候可以手动分块,
例如:
mongos> db.test.getShardDistribution();
Shard sh1 at sh1/mongodb_43:10001,mongodb_44:10001,mongodb_45:10001
data : 528.3MiB docs : 2036657 chunks : 10
estimated data per chunk : 52.83MiB
estimated docs per chunk : 203665
Shard sh2 at sh2/mongodb_44:10002,mongodb_45:10002,mongodb_51:10002
data : 1.05GiB docs : 4164352 chunks : 10
estimated data per chunk : 108.02MiB
estimated docs per chunk : 416435
Shard sh3 at sh3/mongodb_45:10003,mongodb_51:10003,mongodb_52:10003
data : 5.29GiB docs : 20887788 chunks : 10
estimated data per chunk : 541.82MiB
estimated docs per chunk : 2088778
Shard sh4 at sh4/mongodb_51:10004,mongodb_52:10004,mongodb_53:10004
data : 654.63MiB docs : 2523644 chunks : 10
estimated data per chunk : 65.46MiB
estimated docs per chunk : 252364
Shard sh5 at sh5/mongodb_52:10005,mongodb_53:10005,mongodb_54:10005
data : 552.4MiB docs : 2129539 chunks : 9
estimated data per chunk : 61.37MiB
estimated docs per chunk : 236615
Shard sh6 at sh6/mongodb_43:10006,mongodb_53:10006,mongodb_54:10006
data : 515.67MiB docs : 1987943 chunks : 9
estimated data per chunk : 57.29MiB
estimated docs per chunk : 220882
Shard sh7 at sh7/mongodb_43:10007,mongodb_44:10007,mongodb_54:10007
data : 536.83MiB docs : 2069534 chunks : 9
estimated data per chunk : 59.64MiB
estimated docs per chunk : 229948
Totals
data : 9.06GiB docs : 35799457 chunks : 67
Shard sh1 contains 5.68% data, 5.68% docs in cluster, avg obj size on shard : 272B
Shard sh2 contains 11.63% data, 11.63% docs in cluster, avg obj size on shard : 272B
Shard sh3 contains 58.34% data, 58.34% docs in cluster, avg obj size on shard : 271B
Shard sh4 contains 7.04% data, 7.04% docs in cluster, avg obj size on shard : 272B
Shard sh5 contains 5.94% data, 5.94% docs in cluster, avg obj size on shard : 272B
Shard sh6 contains 5.55% data, 5.55% docs in cluster, avg obj size on shard : 272B
Shard sh7 contains 5.78% data, 5.78% docs in cluster, avg obj size on shard : 272B
可以看到,sh3占据58.34%的数据,而且块平均大小是541m,不太平衡,现在就来手动分块并且移动小块,下面是sh3上的分块详情
mongos> sh.status({verbose:true})
--- Sharding Status ---
sharding version: {
"_id" : 1,
"version" : 3,
"minCompatibleVersion" : 3,
"currentVersion" : 4,
"clusterId" : ObjectId("53368d85bcb8bd43e34f807e")
}
shards:
{ "_id" : "sh1", "host" : "sh1/mongodb_43:10001,mongodb_44:10001,mongodb_45:10001" }
{ "_id" : "sh2", "host" : "sh2/mongodb_44:10002,mongodb_45:10002,mongodb_51:10002" }
{ "_id" : "sh3", "host" : "sh3/mongodb_45:10003,mongodb_51:10003,mongodb_52:10003" }
{ "_id" : "sh4", "host" : "sh4/mongodb_51:10004,mongodb_52:10004,mongodb_53:10004" }
{ "_id" : "sh5", "host" : "sh5/mongodb_52:10005,mongodb_53:10005,mongodb_54:10005" }
{ "_id" : "sh6", "host" : "sh6/mongodb_43:10006,mongodb_53:10006,mongodb_54:10006" }
{ "_id" : "sh7", "host" : "sh7/mongodb_43:10007,mongodb_44:10007,mongodb_54:10007" }
databases:
{ "_id" : "admin", "partitioned" : false, "primary" : "config" }
{ "_id" : "test", "partitioned" : true, "primary" : "sh3" }
test.test
shard key: { "C_ID" : 1 }
chunks:
sh1 10
sh2 10
sh4 10
sh5 9
sh6 9
sh7 9
sh3 10
{ "C_ID" : { "$minKey" : 1 } } -->> { "C_ID" : "10" } on : sh1 Timestamp(2, 0)
{ "C_ID" : "10" } -->> { "C_ID" : "1026" } on : sh2 Timestamp(3, 0)
{ "C_ID" : "1026" } -->> { "C_ID" : "1053" } on : sh4 Timestamp(4, 0)
{ "C_ID" : "1053" } -->> { "C_ID" : "1080" } on : sh5 Timestamp(5, 0)
{ "C_ID" : "1080" } -->> { "C_ID" : "1088" } on : sh6 Timestamp(44, 2)
{ "C_ID" : "1088" } -->> { "C_ID" : "1107" } on : sh6 Timestamp(44, 3)
{ "C_ID" : "1107" } -->> { "C_ID" : "1134" } on : sh7 Timestamp(7, 0)
{ "C_ID" : "1134" } -->> { "C_ID" : "1161" } on : sh1 Timestamp(8, 0)
{ "C_ID" : "1161" } -->> { "C_ID" : "1189" } on : sh2 Timestamp(9, 0)
{ "C_ID" : "1189" } -->> { "C_ID" : "1215" } on : sh4 Timestamp(10, 0)
{ "C_ID" : "1215" } -->> { "C_ID" : "1243" } on : sh5 Timestamp(11, 0)
{ "C_ID" : "1243" } -->> { "C_ID" : "127" } on : sh6 Timestamp(12, 0)
{ "C_ID" : "127" } -->> { "C_ID" : "1296" } on : sh7 Timestamp(13, 0)
{ "C_ID" : "1296" } -->> { "C_ID" : "1320" } on : sh2 Timestamp(15, 0)
{ "C_ID" : "1320" } -->> { "C_ID" : "1347" } on : sh4 Timestamp(16, 0)
{ "C_ID" : "1347" } -->> { "C_ID" : "1368" } on : sh1 Timestamp(14, 0)
{ "C_ID" : "1368" } -->> { "C_ID" : "1388" } on : sh5 Timestamp(17, 0)
{ "C_ID" : "1388" } -->> { "C_ID" : "1407" } on : sh6 Timestamp(18, 0)
{ "C_ID" : "1407" } -->> { "C_ID" : "1427" } on : sh7 Timestamp(19, 0)
{ "C_ID" : "1427" } -->> { "C_ID" : "1447" } on : sh1 Timestamp(20, 0)
{ "C_ID" : "1447" } -->> { "C_ID" : "1467" } on : sh2 Timestamp(21, 0)
{ "C_ID" : "1467" } -->> { "C_ID" : "1487" } on : sh4 Timestamp(22, 0)
{ "C_ID" : "1487" } -->> { "C_ID" : "1497" } on : sh5 Timestamp(23, 0)
{ "C_ID" : "1497" } -->> { "C_ID" : "1506" } on : sh6 Timestamp(24, 0)
{ "C_ID" : "1506" } -->> { "C_ID" : "1516" } on : sh7 Timestamp(25, 0)
{ "C_ID" : "1516" } -->> { "C_ID" : "1527" } on : sh1 Timestamp(26, 0)
{ "C_ID" : "1527" } -->> { "C_ID" : "1534" } on : sh2 Timestamp(46, 6)
{ "C_ID" : "1534" } -->> { "C_ID" : "1542" } on : sh2 Timestamp(46, 7)
{ "C_ID" : "1542" } -->> { "C_ID" : "1551" } on : sh4 Timestamp(28, 0)
{ "C_ID" : "1551" } -->> { "C_ID" : "1560" } on : sh5 Timestamp(29, 0)
{ "C_ID" : "1560" } -->> { "C_ID" : "157" } on : sh6 Timestamp(30, 0)
{ "C_ID" : "157" } -->> { "C_ID" : "1577" } on : sh7 Timestamp(31, 0)
{ "C_ID" : "1577" } -->> { "C_ID" : "1584" } on : sh1 Timestamp(32, 0)
{ "C_ID" : "1584" } -->> { "C_ID" : "1591" } on : sh2 Timestamp(33, 0)
{ "C_ID" : "1591" } -->> { "C_ID" : "1599" } on : sh4 Timestamp(34, 0)
{ "C_ID" : "1599" } -->> { "C_ID" : "1605" } on : sh5 Timestamp(35, 0)
{ "C_ID" : "1605" } -->> { "C_ID" : "1612" } on : sh6 Timestamp(36, 0)
{ "C_ID" : "1612" } -->> { "C_ID" : "162" } on : sh7 Timestamp(37, 0)
{ "C_ID" : "162" } -->> { "C_ID" : "1627" } on : sh1 Timestamp(38, 0)
{ "C_ID" : "1627" } -->> { "C_ID" : "1634" } on : sh2 Timestamp(39, 0)
{ "C_ID" : "1634" } -->> { "C_ID" : "1641" } on : sh4 Timestamp(40, 0)
{ "C_ID" : "1641" } -->> { "C_ID" : "1649" } on : sh5 Timestamp(41, 0)
{ "C_ID" : "1649" } -->> { "C_ID" : "1656" } on : sh6 Timestamp(42, 0)
{ "C_ID" : "1656" } -->> { "C_ID" : "1663" } on : sh7 Timestamp(43, 0)
{ "C_ID" : "1663" } -->> { "C_ID" : "1670" } on : sh1 Timestamp(44, 0)
{ "C_ID" : "1670" } -->> { "C_ID" : "1678" } on : sh2 Timestamp(45, 0)
{ "C_ID" : "1678" } -->> { "C_ID" : "1684" } on : sh4 Timestamp(46, 0)
{ "C_ID" : "1684" } -->> { "C_ID" : "1690" } on : sh5 Timestamp(47, 0)
{ "C_ID" : "1690" } -->> { "C_ID" : "1697" } on : sh7 Timestamp(48, 0)
{ "C_ID" : "1697" } -->> { "C_ID" : "1703" } on : sh1 Timestamp(49, 0)
{ "C_ID" : "1703" } -->> { "C_ID" : "1710" } on : sh4 Timestamp(50, 0)
{ "C_ID" : "1710" } -->> { "C_ID" : "1718" } on : sh5 Timestamp(51, 0)
{ "C_ID" : "1718" } -->> { "C_ID" : "1725" } on : sh6 Timestamp(52, 0)
{ "C_ID" : "1725" } -->> { "C_ID" : "1732" } on : sh7 Timestamp(53, 0)
{ "C_ID" : "1732" } -->> { "C_ID" : "174" } on : sh1 Timestamp(54, 0)
{ "C_ID" : "174" } -->> { "C_ID" : "1747" } on : sh2 Timestamp(55, 0)
{ "C_ID" : "1747" } -->> { "C_ID" : "1754" } on : sh4 Timestamp(56, 0)
{ "C_ID" : "1754" } -->> { "C_ID" : "1761" } on : sh3 Timestamp(56, 1)
{ "C_ID" : "1761" } -->> { "C_ID" : "1769" } on : sh3 Timestamp(48, 6)
{ "C_ID" : "1769" } -->> { "C_ID" : "1776" } on : sh3 Timestamp(51, 2)
{ "C_ID" : "1776" } -->> { "C_ID" : "1783" } on : sh3 Timestamp(51, 4)
{ "C_ID" : "1783" } -->> { "C_ID" : "1790" } on : sh3 Timestamp(51, 6)
{ "C_ID" : "1790" } -->> { "C_ID" : "1798" } on : sh3 Timestamp(53, 2)
{ "C_ID" : "1798" } -->> { "C_ID" : "1804" } on : sh3 Timestamp(53, 4)
{ "C_ID" : "1804" } -->> { "C_ID" : "1810" } on : sh3 Timestamp(53, 6)
{ "C_ID" : "1810" } -->> { "C_ID" : "998" } on : sh3 Timestamp(53, 7)
{ "C_ID" : "998" } -->> { "C_ID" : { "$maxKey" : 1 } } on : sh3 Timestamp(2, 3)
分块有两种办法:
sh.splitFind( "test.test", { "C_ID": "1750" } )
这个命令把查询到的文档所在的块分裂成两个大小相等的块,查询条件不一定要包含片键。
sh.splitAt(fullName,middle)
---"test.test", { "C_ID": "1750" }
这个命令把middle值作为大块分裂的边界,分裂后两个块大小不一定相等
现在我们把sh3上的每个块都分成等量的两个块。
mongos> sh.splitFind( "test.test", { "C_ID": "1750" } )
{ "ok" : 1 }
mongos> sh.splitFind( "test.test", { "C_ID": "1765" } )
{ "ok" : 1 }
mongos> sh.splitFind( "test.test", { "C_ID": "1772" } )
{ "ok" : 1 }
mongos> sh.splitFind( "test.test", { "C_ID": "1779" } )
{ "ok" : 1 }
mongos> sh.splitFind( "test.test", { "C_ID": "1786" } )
{ "ok" : 1 }
mongos> sh.splitFind( "test.test", { "C_ID": "1794" } )
{ "ok" : 1 }
mongos> sh.splitFind( "test.test", { "C_ID": "1801" } )
{ "ok" : 1 }
mongos> sh.splitFind( "test.test", { "C_ID": "1807" } )
{ "ok" : 1 }
这个时候可以用查看config中的locks集合发现数据在自动移动了。
mongos> db.locks.find({state:2})
{ "_id" : "balancer", "process" : "mongodb_44:30000:1396165259:1804289383", "state" : 2, "ts" : ObjectId("5337fb55e0d1b0cf1474b5cc"), "when" : ISODate("2014-03-30T11:09:09.082Z"), "who" : "mongodb_44:30000:1396165259:1804289383:Balancer:846930886", "why" : "doing balance round" }
{ "_id" : "test.test", "process" : "mongodb_45:10003:1396165339:1273713519", "state" : 2, "ts" : ObjectId("5337fb55923897566504f4fa"), "when" : ISODate("2014-03-30T11:09:09.527Z"), "who" : "mongodb_45:10003:1396165339:1273713519:conn114:1759073978", "why" : "migrate-{ C_ID: \"1754\" }" }
State为2表示平衡器正在活动,可以看到路由进程mongodb_44:30000持有平衡锁,在进行数据移动。分块完成后最好等待系统自动移动块,分裂后也mongos并不能把分裂后的块移动到其他分片上,可以手动移动分块,例如
db.adminCommand( { moveChunk : "test.test",find : {C_ID : "1778"},to : "sh1" } )