我想尝试使用MongoDB进行分片和副本集

使用MongoDB的分片加副本集。

前提

    AWS EC2 AmazonLinux
    mongoDB 2.6

我之前试过MongoDB的副本集,现在想试试分片功能。通过这样的方式,即使数据量和查询增加,通过扩展来实现负载均衡也是可能的。

    参考 mongoDBのレプリカセットを構築してRails+mongoidで接続する

组成图

mongodb_sharding.png

在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相互协作,变得更加方便。

bannerAds