我想尝试使用MongoDB进行分片和副本集
使用MongoDB的分片加副本集。
前提
-
AWS EC2 AmazonLinux
mongoDB 2.6
我之前试过MongoDB的副本集,现在想试试分片功能。通过这样的方式,即使数据量和查询增加,通过扩展来实现负载均衡也是可能的。
-
参考 mongoDBのレプリカセットを構築してRails+mongoidで接続する
组成图

在MongoDB的分片中,有一种名为mongos的路由器服务器和一种名为配置服务器的配置服务器。
蒙古斯路由器
这是一个将分片和客户端进行协调的路由过程。这个服务器本身只是一个简单的接口,不保存任何数据或状态。Rails等应用程序将连接到这个mongos服务。请注意,不是连接到mongod,而是mongos。
配置服务器
这是一个存储有分片元数据的设置服务器。可以在1台或3台服务器上运行,但在正式环境中,建议使用3台配置服务器。负载不大,所以即使规格较低也没问题。或者,也可以与其他服务器共存。但是,配置服务器之间不可以共存。
碎片
我们拥有分散存储数据的数据库集群。这次我们打算将一个由主数据库、副本数据库和仲裁节点组成的三台结构创建为一个分片。
分片设置
第一碎片(替换_1)
主服务器+备用服务器+仲裁者的配置设置完全相同。
logpath=/var/log/mongodb/mongod.log
logappend=true
fork=true
dbpath=/var/lib/mongo
pidfilepath=/var/run/mongodb/mongod.pid
#bind_ip=127.0.0.1 ←コメントアウト
port=27017
shardsvr=true
replSet=repl_1
进行复制设置。
> config = {_id: 'repl_1',
members: [
{_id: 0, host: '172.31.100.10:27017'},
{_id: 1, host: '172.31.100.11:27017'},
{_id: 2, host: '172.31.100.12:27017', arbiterOnly: true},
]
}
> rs.initiate(config)
第二个碎片(repl_2)
所有的Primary、Secondary和Arbiter都有相同的设置。
logpath=/var/log/mongodb/mongod.log
logappend=true
fork=true
dbpath=/var/lib/mongo
pidfilepath=/var/run/mongodb/mongod.pid
#bind_ip=127.0.0.1 ←コメントアウト
port=27017
shardsvr=true
replSet=repl_2
我要进行复制套装的设置。
> config = {_id: 'repl_2',
members: [
{_id: 0, host: '172.31.100.20:27017'},
{_id: 1, host: '172.31.100.21:27017'},
{_id: 2, host: '172.31.100.22:27017', arbiterOnly: true},
]
}
> rs.initiate(config)
配置服务器 qì)
logpath=/var/log/mongodb/mongod.log
logappend=true
fork=true
dbpath=/var/lib/mongo
pidfilepath=/var/run/mongodb/mongod.pid
#bind_ip=127.0.0.1 ←コメントアウト
port=27017
configsvr=true
mongo人
在配置服务器中指定主机和端口。在这种情况下,使用主机名而不是IP地址更方便,因为当发生服务器故障等情况时。
另外,我們將創建一個名為mongos.conf的設定文件,而不是mongod.conf。
logpath=/var/log/mongodb/mongod.log
logappend=true
fork=true
pidfilepath=/var/run/mongodb/mongod.pid
#bind_ip=127.0.0.1 ←コメントアウト
port=27017
configdb=mongo-config.example.com:27017
# configサーバが複数台の場合はカンマ区切り
# configdb=mongo-config1.example.com:27017,mongo-config2.example.com:27017,mongo-config3.example.com:27017
启动mongos。
$ sudo mongos -f /etc/mongos.conf
分片设置
> db.adminCommand({addshard: "repl_1/172.31.10.155:27017,172.31.100.11:27017", name: "repl_1", allowLocal: true})
> db.adminCommand({addshard: "repl_2/172.31.20.155:27017,172.31.100.21:27017", name: "repl_2", allowLocal: true})
我确认。
> sh.status()
用这个完成了分片设置。
确定分片的对象
让我们将样本数据库的hoges集合进行分片。
> use admin
> sh.enableSharding("sample")
> sh.shardCollection("sample.hoges" , { uid : 1 })
> use sample
> db.logs.ensureIndex( { uid : 1 } );
我将实际投入数据。
> use sample
> for(var i=1; i<=10000; i++) db.hoges.insert({"uid":i, "value":Math.floor(Math.random()*100000+1)})
我会确认实际是否已经分散了。
> db.hoges.count()
10000
> db.hoges.count()
4800
> db.hoges.count()
5200
我已经确认数据已正确分布在每个分片中了。
选择Sharky的key
确定数据的分割规则和分片键的设置是非常重要且困难的事情。
在样本中,我们将简单的UID指定为分片键,但这似乎不是一种非常有效的指定方法。原因是,如果简单地将递增的值指定为分片键,那么负载将集中在一个分片上。
如果仅仅增加的值不可行,那么简单地将随机值作为分片键是不太可行的。虽然在写入(插入)时分散是高效的,但在查询时可能需要访问所有分片。例如,在获取用户最新的10条帖子时。在查询时,数据尽量集中在同一个分片上是更高效的。
那么,我们应该怎么办呢?具体要看数据和应用的需求,但基本上使用复合键可能会更好。例如,使用用户ID和帖子ID进行复合。
概括一下
MongoDB的分片架构本身非常简单。但是,要实际稳定处理大量数据和流量,需要相应的运维经验。在这方面,只能踏实积累了…。
如果管理MongoDB基础架构的成本太高的话,虽然存在一些差异,但我认为考虑使用DynamoDB等也是不错的选择。因为它能够改变全局次要索引,并能够与AWS Lambda相互协作,变得更加方便。