不管是对于企业、组织还是个人来讲,数据的重要性已经不需要再多作解释,尤其是处于信息技术飞速发展的今天,从数据中能够挖掘的潜力是不可限量的。所以数据安全也显得格外重要。

本文将对 MongoDB 集群中的 Replica Set 搭建方式作一下简单的介绍。

受环境限制,本文所涉及到的操作都在本地完成(即单机),但是搭建 Replica Set 的操作都是一样的,笔者遇到过的坑会作特别说明。

说明:本文的测试环境为 MongoDB 3.x,所涉及到的操作不适用于 MongoDB 2.x。

什么是 Replica Set?

中文翻译副本集,顾名思义,其由一组服务组成的集合,需要由多组服务来协同工作。其中有一个主节点(primary),用于处理客户端的请求;还有多个备份节点(secondary),用于保存主节点的数据副本。如果主节点崩溃了,备份节点会自动将其中一个成员升级成为新的主节点。

主节点可执行读写操作,备份节点只可执行读操作。

这样看来,即解决了数据备份的问题,也解决了因数据库异常引发的服务中断问题。

如何搭建 Replica Set?

如果你是从零开始搭建 MongoDB 服务集群,那么所涉及到的操作将简单得不能够再简单了。当然,难免也会有马失前蹄的时候,需要对于一些已经投入生产的单机数据库进行扩建。对于后者,笔者并没有什么好的解决方案,是直接将服务 shutdown 了之后进行操作的。

笔者就是属于后者,好在笔者所面对的只是一个用户量还不太的社交服务,所以服务短暂停掉服务一会儿并不会有太大的影响 。

在此也向各位提个醒,无论数据多少及硬件环境如何,即使只有一台服务器,也尽量将其部署成集群的形式,这样后期扩展基本上就不用关闭服务了。

在此假设我们需要部署三个 MongoDB 的实例,分别位于 192.168.192.1、192.168.192.2 和 192.168.192.3。(MongodDB 端口号都用默认的 27017)

其中我们需要将 192.168.192.1 作为主节点,其它两个作为备份节点。

添加用户

对于生产环境,数据安全是必不可少的,需要加上权限访问,所以需要先添加用户。

首先启动 192.168.192.1 上的 MongoDB 服务:

./bin/mongod --dbpath ./myset 

添加一个专门用于管理用户的用户:

> use admin
> db.createUser({user:"admin", pwd:"admin", roles:[{role:"userAdminAnyDatabase", db:"admin"}]})

创建用户成功之后,关闭刚刚在 192.168.192.1 启动的 MongoDB 服务。

添加 –replSet 参数启动 MongoDB

分别在三台服务器上用下列命令启动 MongoDB:

./bin/mongod --dbpath ./myset --replSet rs

rs 为副本集的名字。

连接上主节点

这时候三个 MongoDB 服务都是平等的,他们之间没有任何关系,也没有主次之分,我们接下来的操作就是要建立主次关系。

假如我们要将 192.168.192.1 作为主节点, 只需要用 MongoDB shell 连接上其执行下列操作即可:

> rs.initiate()
> rs.add("192.168.192.2:27017")
> rs.add("192.168.192.3:27017")

执行完上述操作之后,数据库服务之间的主次关系就建立了。

然后执行 rs.conf() 将会看到相关的服务器信息。

验证

现在的数据库是相当不安全的,因为没有设定任何访问权限,我们刚才启动数据服务的时候也没有添加--auth参数。但是很遗憾的告诉你,就算这时候我们把服务停掉,然后加上--auth参数重启服务依然也不行,数据服务之间将不能进行正常的数据同步。

MongoDB 提供了另一种方式,使用 key file。

mongod 命令有另一个参数,叫--keyFile,其需要一个包含密钥的文件作为参数传入,不同的服务之间将以此作为认证的凭证。

可以使用 openssl 生成密钥文件:

openssl rand -base64 513 > mongodb-keyfile

然后将该密钥文件分发到三台服务器上,分别重新重启 MongoDB:

./bin/mongod --dbpath ./myset --replSet rs --keyFile ./mongodb-keyfile

这样三个 MongoDB 节点之间就可以正常通讯了,并且也自动开启了 MongoDB 的授权认证功能。

至此,一个需要授权认证的 MongoDB 副本集就搭建完成。即使 192.168.192.1 上的数据服务挂掉之后,其它的备份节点也会补上来,正常提供数据。

关于 MongoDB 的选举机制在此不作详细的描述,有兴趣可以参考官网上的文档。

仲裁者

对于一些特殊的副本集配置,当主节点挂掉之后,剩余的备份节点可能并不能够进行有效的选举,即不能够提供新的主节点候选。

这时候推荐使用仲裁者,仲裁者并不存储数据,其参与选举。

仲裁者的配置也及极其简单,唯一的不同操作在于:

rs.addArb("ip:port")

仅此而已。

对于生产环境,强烈推荐部署一个仲裁者。

问题一

笔者在部署过程中,遇到过的唯一一个坑就是来自于执行rs.initiate()之后,生成的本机信息中,是用的 hostname 作为 host 字段存入数据库的,这样部署在外网的服务器,无论如何都是没有办法相互通讯的。

这时候就需要参考官方文档 Change hostnames in a replica set :

> cfg = rs.conf()
> cfg.members[0].host = "ip:port"
> rs.reconfig(cfg)

问题二

前面说了备份节点可以执行读操作,但是连接之后,执行查询的时候却出现下列错误:

not master and slaveok=false

虽然备份节点是可读的,但是其默认也是不可读的,需要我们自己开启。

只需要在备份节点执行下列命令即可:

> db.getMongo().setSlaveOk()

应用程序如何访问 Replica Set

话说现在将 MongoDB 部署为集群了,那应用程序改动的地方大吗?这是作为一个开发者很关心的问题。

这一切 MongoDB 都已经处理好了,开发者基本上无需作任何改动,只需要将连接 MongoDB 的 URL 适当的调整一下就好。

参考 Connection String URI Format.