共计 4663 个字符,预计需要花费 12 分钟才能阅读完成。
在前面这篇文章“MongoDB 的主从模式搭建实例”中,我们对如何搭建一个主从结构的 Mongodb 服务器环境进行了简单的介绍。但是对于主从结构,Mongodb 官方并不推荐我们使用了,可能是因为主从模式存在以下两个缺点:
(1)主节点不可用之后,无法自动切换到从节点,无法确保业务访问的不间断性;
(2)所有的读写操作都是对主节点的,造成主节点的访问压力较大;
因此,Mongodb 为我们提供了另外一种推荐的使用方法,那就是使用副本集 ReplicaSets。在这篇文章中简单描述一下副本集是如何实现的,又是如何解决以上两个问题的。
首先我们先来搭建一个副本集(因为没有那么多服务器机器,这里采用在一台机器上,使用不同的端口号模拟不同的机器上的 Mongodb 实例)。
第一步:我们在本机的 1111、2222 和 3333 三个端口上启动三个不同的 Mongodb 实例;
mongod –port 1111 –dbpath F:/mongodb1/data/db –logpath F:/mongodb1/data/log/mongodb.log –replSet test –logappend
mongod –port 2222 –dbpath F:/mongodb2/data/db –logpath F:/mongodb2/data/log/mongodb.log –replSet test –logappend
mongod –port 3333 –dbpath F:/mongodb3/data/db –logpath F:/mongodb3/data/log/mongodb.log –replSet test –logappend
在这里我们启动了三个 Mongodb 实例,并指定了相应的数据目录和日志目录,需要说明的是,这里需要使用 –replSet 说明该 Mongodb 实例是副本集中的节点,而该副本集的名称是 test。
第二步:登录到一个实例上,编写指令,将三个不同的 Mongodb 实例结合在一起形成一个完整的副本集;
config_test={“_id”:”test”,members:[
{_id:0,host:”127.0.0.1:1111″},
{_id:1,host:”127.0.0.1:2222″},
{_id:2,host:”127.0.0.1:3333″},
]};
这里,members 中可以包含多个值,这里列举的就是刚才启动的三个 Mongodb 实例,并且通过_id 字段给副本集起了名字 test。
第三步:通过执行下面的命令初始化副本集。
rs.initiate(config_test);
这里使用上面的配置初始化 Mongodb 副本集。
通过上面的三步,便可以简单的搭建起一个由三个 Mongodb 实例构成的名称为 test 的副本集了。如果想查看副本集的状态,可以使用 rs.status()命令来进行查看。
副本集现在搭建起来了,那么这个副本集能不能解决我们上面主从模式的两个问题呢?
我们首先从第一个问题开始看,我们将 1111 端口的 Mongodb 服务器给关闭,然后我们使用 rs.status()命令来查看下,如下所示:
在这里,需要对返回信息中的个别字段进行简单说明,health 表示副本集中该节点是否正常,0 表示不正常,1 表示正常;state 表示节点的身份,0 表示非主节点,1 表示主节点;stateStr 用于对节点身份进行字符描述,PRIMARY 表示主节点,SECONDARY 表示副节点;name 是副本集节点的 ip 和端口信息,等等。
从返回包信息中,可以看到关闭 1111 端口后,在副本集节点的状态中该节点是不可达的,重新选取产生的主节点是 3333 端口上启动的 Mongodb 实例,至于选取的流程在后面的文章中将会讲到,这里简单讲一点,当主节点挂掉之后,其他节点可以发起选举行为,只要在选举过程中某个节点得到副本集节点数一半以上的选票并且没有节点投反对票,那么该节点就可以成为主节点。
在 1111 端口上的 Mongodb 实例挂掉之后,3333 成为了新的主节点,可以实现自动切换,因此解决了第一个问题。
至于第二个问题,那就是主节点负责所有的读写操作造成主节点压力较大,那么在副本集中如何解决这个问题了呢?正常情况下,我们在 Java 中访问副本集是这样的,如下所示:
public class TestMongoDBReplSet {
public static void main(String[] args) {
try {
List<ServerAddress> addresses = new ArrayList<ServerAddress>();
ServerAddress address1 = new ServerAddress(“127.0.0.1” , 1111);
ServerAddress address2 = new ServerAddress(“127.0.0.1” , 2222);
ServerAddress address3 = new ServerAddress(“127.0.0.1” , 3333);
addresses.add(address1);
addresses.add(address2);
addresses.add(address3);
MongoClient client = new MongoClient(addresses);
DB db = client.getDB(“test”);
DBCollection coll = db.getCollection(“test”);
// 插入
BasicDBObject object = new BasicDBObject();
object.append(“key1”, “value1”);
coll.insert(object);
DBCursor dbCursor = coll.find();
while (dbCursor.hasNext()) {
DBObject dbObject = dbCursor.next();
System. out.println(dbObject.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
但是,上面不能做到在副本集中读写压力分散,其实在代码层面,我们可以设置再访问副本集的时候只从副节点上读取数据。副本集读写分离结构如下图所示:
为了在副本集上实现读写分离,我们需要实现以下两步:
(1)在副本节点上设置 setSlaveOk;
(2)代码层面,在读操作过程中设置从副本节点读取数据,如下所示:
public class TestMongoDBReplSet {
public static void main(String[] args) {
try {
List<ServerAddress> addresses = new ArrayList<ServerAddress>();
ServerAddress address1 = new ServerAddress(“127.0.0.1” , 1111);
ServerAddress address2 = new ServerAddress(“127.0.0.1” , 2222);
ServerAddress address3 = new ServerAddress(“127.0.0.1” , 3333);
addresses.add(address1);
addresses.add(address2);
addresses.add(address3);
MongoClient client = new MongoClient(addresses);
DB db = client.getDB(“test”);
DBCollection coll = db.getCollection(“test”);
BasicDBObject object = new BasicDBObject();
object.append(“key1”, “value1”);
ReadPreference preference = ReadPreference.secondary();
DBObject dbObject = coll.findOne(object, null , preference);
System. out .println(dbObject);
} catch (Exception e) {
e.printStackTrace();
}
}
}
读参数除了 secondary 以外,还有其他几个参数可以使用,他们的含义分别如下所示:
primary: 默认参数,只从主节点上进行读取操作;
primaryPreferred: 大部分从主节点上读取数据, 只有主节点不可用时从 secondary 节点读取数据。
secondary: 只从 secondary 节点上进行读取操作,存在的问题是 secondary 节点的数据会比 primary 节点数据“旧”。
secondaryPreferred: 优先从 secondary 节点进行读取操作,secondary 节点不可用时从主节点读取数据;
nearest: 不管是主节点、secondary 节点,从网络延迟最低的节点上读取数据。
这样便实现了在副本集上的读写分离了,也就解决了文章最上面所说的第二个问题了。至于副本集中另一个比较重要的地方,主从数据如何同步?如何选举产生新的主节点?副本集中的各个节点如何信息同步?这些问题,将另起一篇文章进行描述,如敢兴趣,可以关注,谢谢。^_^
更多 MongoDB 相关教程见以下内容:
CentOS 编译安装 MongoDB 与 mongoDB 的 php 扩展 http://www.linuxidc.com/Linux/2012-02/53833.htm
CentOS 6 使用 yum 安装 MongoDB 及服务器端配置 http://www.linuxidc.com/Linux/2012-08/68196.htm
Ubuntu 13.04 下安装 MongoDB2.4.3 http://www.linuxidc.com/Linux/2013-05/84227.htm
MongoDB 入门必读(概念与实战并重) http://www.linuxidc.com/Linux/2013-07/87105.htm
Ubunu 14.04 下 MongoDB 的安装指南 http://www.linuxidc.com/Linux/2014-08/105364.htm
《MongoDB 权威指南》(MongoDB: The Definitive Guide)英文文字版[PDF] http://www.linuxidc.com/Linux/2012-07/66735.htm
Nagios 监控 MongoDB 分片集群服务实战 http://www.linuxidc.com/Linux/2014-10/107826.htm
基于 CentOS 6.5 操作系统搭建 MongoDB 服务 http://www.linuxidc.com/Linux/2014-11/108900.htm
MongoDB 的详细介绍:请点这里
MongoDB 的下载地址:请点这里
本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-06/132247.htm