分片
在Mongodb里面存在另一种集群,就是分片技术,可以满足MongoDB数据量大量增长的需求。
当MongoDB存储海量的数据时,一台机器可能不足以存储数据,也可能不足以提供可接受的读写吞吐量。这时,我们就可以通过在多台机器上分割数据,使得数据库系统能存储和处理更多的数据。
为什么使用分片
- 复制所有的写入操作到主节点
- 延迟的敏感数据会在主节点查询
- 单个副本集限制在12个节点
- 当请求量巨大时会出现内存不足。
- 本地磁盘不足
- 垂直扩展价格昂贵
MongoDB分片
下图展示了在MongoDB中使用分片集群结构分布:
上图中主要有如下所述三个主要组件:
- Shard:
用于存储实际的数据块,实际生产环境中一个shard server角色可由几台机器组个一个replica set承担,防止主机单点故障
- Config Server:
mongod实例,存储了整个 ClusterMetadata,其中包括 chunk信息。 - Query Routers:
前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用可以透明使用。
分片实例
分片结构端口分布如下:
Shard Server 1:27020 Shard Server 2:27021 Shard Server 3:27022 Shard Server 4:27023 Config Server :27100 Route Process:40000
步骤一:启动Shard Server
[email protected]:/# mkdir -p /www/mongoDB/shard/s0 [email protected]:/# mkdir -p /www/mongoDB/shard/s1 [email protected]:/# mkdir -p /www/mongoDB/shard/s2 [email protected]:/# mkdir -p /www/mongoDB/shard/s3 [email protected]:/# mkdir -p /www/mongoDB/shard/log
-
[email protected]:/# mongod -port 27020 -dbpath "/www/mongoDB/shard/s0/" -logpath "/www/mongoDB/shard/log/s0.log" -logappend -fork about to fork child process, waiting until server is ready for connections. forked process: 2797 child process started successfully, parent exiting [email protected]:/# mongod -port 27021 -dbpath "/www/mongoDB/shard/s1/" -logpath "/www/mongoDB/shard/log/s1.log" -logappend -fork about to fork child process, waiting until server is ready for connections. forked process: 2818 child process started successfully, parent exiting [email protected]:/# mongod -port 27022 -dbpath "/www/mongoDB/shard/s2/" -logpath "/www/mongoDB/shard/log/s2.log" -logappend -fork about to fork child process, waiting until server is ready for connections. forked process: 2839 child process started successfully, parent exiting [email protected]:/# mongod -port 27023 -dbpath "/www/mongoDB/shard/s3/" -logpath "/www/mongoDB/shard/log/s3.log" -logappend -fork about to fork child process, waiting until server is ready for connections. forked process: 2861 child process started successfully, parent exiting
步骤二: 启动Config Server
[email protected]:/# mkdir -p /www/mongoDB/shard/config [email protected]:/# mongod -port 27100 -dbpath "/www/mongoDB/shard/config/" -logpath "/www/mongoDB/shard/log/config.log" -logappend -fork about to fork child process, waiting until server is ready for connections. forked process: 2885 child process started successfully, parent exiting
注意:这里我们完全可以像启动普通mongodb服务一样启动,不需要添加—shardsvr和configsvr参数。因为这两个参数的作用就是改变启动端口的,所以我们自行指定了端口就可以。
步骤三: 启动Route Process
[email protected]:/# mongos -port 40000 -configdb 127.0.0.1:27100 -fork -logpath "www/mongoDB/shard/log/route.log" -chunkSize 500 2017-06-01T07:41:53.624-0700 W SHARDING [main] Running a sharded cluster with fewer than 3 config servers should only be done for testing purposes and is not recommended for production. about to fork child process, waiting until server is ready for connections. forked process: 2928 child process started successfully, parent exiting
mongos启动参数中,chunkSize这一项是用来指定chunk的大小的,单位是MB,默认大小为200MB.
步骤四: 配置Sharding
接下来,我们使用MongoDB Shell登录到mongos,添加Shard节点
[email protected]:/# mongo admin -port 40000 #此操作需要连接admin库 MongoDB shell version: 3.2.13 connecting to: 127.0.0.1:40000/admin mongos> db.runCommand({addshard:"localhost:27020"}) { "shardAdded" : "shard0000", "ok" : 1 } mongos> db.runCommand({addshard:"localhost:27021"}) { "shardAdded" : "shard0001", "ok" : 1 } mongos> db.runCommand({addshard:"localhost:27022"}) { "shardAdded" : "shard0002", "ok" : 1 } mongos> db.runCommand({addshard:"localhost:27023"}) { "shardAdded" : "shard0003", "ok" : 1 }
#设置分片存储的数据库:开启数据库分片功能,命令很简单 enablesharding(),这里开启test数据库
mongos> db.runCommand({enablesharding:"test"}) { "ok" : 1 }
#指定集合中分片的片键,这里指定为id,time字段。
mongos> db.runCommand({shardcollection:"test.log",key:{id:1,time:1}}) { "collectionsharded" : "test.log", "ok" : 1 }
步骤五: 程序代码内无需太大更改,直接按照连接普通的mongo数据库那样,将数据库连接接入接口40000
[email protected]:~# mongo -port 40000 MongoDB shell version: 3.2.13 connecting to: 127.0.0.1:40000/test
步骤六: 至此分片操作全部结束,接下来我们通过mongos向mongodb插入10w记录,然后通过printShardingStatus命令查看mongodb的数据分片情况。
mongos> for(i = 0;i < 100000;i++){db.test.insert({"time":"time_" + i,"age" : i,"name":"lime_" + i})} WriteResult({ "nInserted" : 1 })
返回结果:???(源自贴吧不知道怎么验证,再重头配置太麻烦:应该是在启动 config 服务器那一步出了问题,我在启动config服务器时漏了 --configsvr ,加上就好了)
mongos> db.printShardingStatus() 2017-06-01T08:01:26.838-0700 E QUERY [thread1] Error: error: { "ok" : 0, "errmsg" : "Surprised to discover that 127.0.0.1:27100 does not believe it is a config server", "code" : 72 } : _getErrorWithCode@src/mongo/shell/utils.js:25:13 [email protected]/mongo/shell/query.js:689:1 DBQuery.prototype._exec@src/mongo/shell/query.js:118:28 [email protected]/mongo/shell/query.js:276:5 [email protected]/mongo/shell/collection.js:289:10 [email protected]/mongo/shell/utils_sh.js:544:19 [email protected]/mongo/shell/db.js:1135:9 @(shell):1:1
预期结果:
这里主要看三点信息:
① shards:我们清楚的看到已经别分为两个片了,shard0000和shard0001。
② databases:这里有个partitioned字段表示是否分区,这里清楚的看到test已经分区。
③ chunks:这个很有意思,我们发现集合被砍成四段:无穷小 —— jack0,jack0 ——jack234813,jack234813——jack9999,jack9999——无穷大。分区情况为:3:1,从后面的 on shardXXXX也能看得出。
啦啦啦
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
下面我对这张图解释一下:
人脸:代表客户端,客户端肯定说,你数据库分片不分片跟我没关系,我叫你干啥就干啥,没什么好商量的。
mongos:首先我们要了解”片键“的概念,也就是说拆分集合的依据是什么?按照什么键值进行拆分集合....好了,mongos就是一个路由服务器,它会根据管理员设置的“片键”将数据分摊到自己管理的mongod集群,数据和片的对应关系以及相应的配置信息保存在"config服务器"上。
mongod:一个普通的数据库实例,如果不分片的话,我们会直接连上mongod。
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
啦啦啦