将海量的数据水平或垂直切割,分区存储到多台服务器上是一个最基本的现实需求。从 1.6 版开始,MongoDB Sharding 总算打上了 "production-ready" 标记。
MongoDB 的数据分块称为 chunk。每个 chunk 都是 Collection 中一段连续的数据记录,通常最大尺寸是 200MB,超出则生成新的数据块。
要构建一个 MongoDB Sharding Cluster,需要三种角色:
Shard Server: mongod 实例,用于存储实际的数据块。
Config Server: mongod 实例,存储了整个 Cluster Metadata,其中包括 chunk 信息。
Route Server: mongos 实例,前端路由,客户端由此接入,且让整个集群看上去像单一进程数据库。
Route 转发请求到实际的目标服务进程,并将多个结果合并回传给客户端。Route 本身并不存储任何数据和状态,仅在启动时从 Config Server 获取信息。Config Server 上的任何变动都会传递给所有的 Route Process。
在实际使用中,为了获取高可用、高性能的集群方案,我们会将 Shard Server 和 Config Server 部署成 Replica Sets,然后用 LVS 部署多个 Route。
我们先构建一个简单的 Sharding Cluster,以熟悉相关的配置。
(1) 启动 Shard Server。
$ sudo mkdir -p /var/mongodb/0
$ sudo mkdir -p /var/mongodb/1
$ sudo ./mongod --shardsvr --port 10000 --dbpath /var/mongodb/0 --fork --logpath /dev/null
forked process: 1414
all output going to: /dev/null
$ sudo ./mongod --shardsvr --port 10001 --dbpath /var/mongodb/1 --fork --logpath /dev/null
forked process: 1424
all output going to: /dev/null
(2) 启动 Config Server。
$ sudo mkdir -p /var/mongodb/config
$ sudo ./mongod --configsvr --port 20000 --dbpath /var/mongodb/config --fork --logpath /dev/null
forked process: 1434
all output going to: /dev/null
(3) 启动 Route Process。
$ sudo ./mongos --configdb localhost:20000 --fork --logpath /dev/null
forked process: 1443
all output going to: /dev/null
可以用 --chunkSize 参数指定分块大小。
(4) 连接到 Route,开始配置。
$ ./mongo
MongoDB shell version: 1.6.1
connecting to: test
> use admin
switched to db admin
> db.runCommand({ addshard:"localhost:10000" })
{ "shardAdded" : "shard0000", "ok" : 1 }
> db.runCommand({ addshard:"localhost:10001" })
{ "shardAdded" : "shard0001", "ok" : 1 }
> db.runCommand({ enablesharding:"test" })
{ "ok" : 1 }
> db.runCommand({ shardcollection: "test.users", key: { _id:1 }})
{ "collectionsharded" : "test.users", "ok" : 1 }
addshard: 添加 Shard Server,相关的命令还有 listshards 和 removeshard。
enablesharding: 用于设置可以被分布存储的数据库。
shardcollection: 用于设置具体被切块的集合名称,且必须指定 Shard Key,系统会自动创建索引。
注: Sharded Collection 只能有一个 unique index,且必须是 shard key。
(5) 相关的管理命令。
listshards 命令列出所有的 Shard Server。
> db.runCommand({ listshards: 1 })
{
"shards" : [
{
"_id" : "shard0000",
"host" : "localhost:10000"
},
{
"_id" : "shard0001",
"host" : "localhost:10001"
}
],
"ok" : 1
}
或用 printShardingStatus 命令查看 Sharding 信息。
> printShardingStatus()
--- Sharding Status ---
sharding version: { "_id" : 1, "version" : 3 }
shards:
{ "_id" : "shard0000", "host" : "localhost:10000" }
{ "_id" : "shard0001", "host" : "localhost:10001" }
databases:
{ "_id" : "admin", "partitioned" : false, "primary" : "config" }
{ "_id" : "test", "partitioned" : true, "primary" : "shard0000" }
test.users chunks:
{ "_id" : { $minKey : 1 } } -->> { "_id" : { $maxKey : 1 } }
on : shard0000 { "t" : 1000, "i" : 0 }
isdbgrid 用来确认当前是否是 Sharding Cluster。
> db.runCommand({ isdbgrid:1 })
{ "isdbgrid" : 1, "hostname" : "yuhen-server64", "ok" : 1 }
> db.runCommand({ ismaster:1 })
{ "ismaster" : 1, "msg" : "isdbgrid", "ok" : 1 }
--------- 华丽的分隔线 --------------
测试一下效果:
$ ipython
In [1]: from pymongo import *
In [2]: conn = Connection()
In [3]: db = conn.test
In [4]: for i in xrange(2000000):
...: u = dict(name = "user" + str(i))
...: print i, db.users.insert(u)
# 呼啦啦,好多东东啊,喝茶去...
In [5]: db.users.count()
Out[5]: 2000000
从 test.users chunks 可以看到分块存储的范围。
> printShardingStatus()
--- Sharding Status ---
sharding version: { "_id" : 1, "version" : 3 }
shards:
{ "_id" : "shard0000", "host" : "localhost:10000" }
{ "_id" : "shard0001", "host" : "localhost:10001" }
databases:
{ "_id" : "admin", "partitioned" : false, "primary" : "config" }
{ "_id" : "test", "partitioned" : true, "primary" : "shard0000" }
test.users chunks:
{ "_id" : { $minKey : 1 } } -->> { "_id" : ObjectId("4c7...000") }
on : shard0001 { "t" : 2000, "i" : 0 }
{ "_id" : ObjectId("4c7...000") } -->> { "_id" : ObjectId("4c7...d3b") }
on : shard0000 { "t" : 3000, "i" : 1 }
{ "_id" : ObjectId("4c7...d3b") } -->> { "_id" : { $maxKey : 1 } }
on : shard0001 { "t" : 3000, "i" : 0 }
看看存储目录使用情况 (删除了一些信息,便于阅读)。
$ du -h /var/mongodb | grep -v _tmp
1.2G /var/mongodb
465M /var/mongodb/0
465M /var/mongodb/1
209M /var/mongodb/config
更详细一些 (删除了一些信息,便于阅读)。
$ ls -lhR /var/mongodb
/var/mongodb:
total 12K
drwxr-xr-x 4 root root 4.0K 2010-08-23 19:21 0
drwxr-xr-x 3 root root 4.0K 2010-08-23 19:23 1
drwxr-xr-x 3 root root 4.0K 2010-08-23 18:33 config
/var/mongodb/0:
total 465M
-rwxr-xr-x 1 root root 5 2010-08-23 18:32 mongod.lock
drwxr-xr-x 3 root root 4.0K 2010-08-23 19:21 moveChunk
-rw------- 1 root root 64M 2010-08-23 19:21 test.0
-rw------- 1 root root 128M 2010-08-23 19:21 test.1
-rw------- 1 root root 256M 2010-08-23 19:14 test.2
-rw------- 1 root root 16M 2010-08-23 19:21 test.ns
drwxr-xr-x 2 root root 4.0K 2010-08-23 18:36 _tmp
/var/mongodb/1:
total 465M
-rwxr-xr-x 1 root root 5 2010-08-23 18:32 mongod.lock
-rw------- 1 root root 64M 2010-08-23 19:25 test.0
-rw------- 1 root root 128M 2010-08-23 19:25 test.1
-rw------- 1 root root 256M 2010-08-23 19:23 test.2
-rw------- 1 root root 16M 2010-08-23 19:25 test.ns
drwxr-xr-x 2 root root 4.0K 2010-08-23 19:21 _tmp
/var/mongodb/config:
total 209M
-rw------- 1 root root 64M 2010-08-23 19:26 config.0
-rw------- 1 root root 128M 2010-08-23 18:33 config.1
-rw------- 1 root root 16M 2010-08-23 19:21 config.ns
-rw-r--r-- 1 root root 41K 2010-08-23 19:22 diaglog.4c724e45
-rwxr-xr-x 1 root root 5 2010-08-23 18:32 mongod.lock
drwxr-xr-x 2 root root 4.0K 2010-08-23 18:36 _tmp