日期:2014-05-16  浏览次数:20432 次

mongodb利用rs,实现ha和备份

mongodb最简单的部署方式,是单节点部署。国庆前找了台8核,48G RAM的server,在100+并发的压力下跑了一个星期,也没有发现数据丢失和server负载过大的情况


但是单节点部署还是有一些问题,第一是无法做HA,如果该mongod down掉,或者部署的server down掉,应用就无法工作;第二是不利于备份,因为在备份的时候,会给mongod额外的负担,有可能影响业务;第三是无法做读写分离。所以在生产环境下,依然考虑使用集群部署


mongod支持的集群部署方式有3种:

1、master-slave

2、replica set

3、sharding


master-slave可以解决备份的问题,但是无法透明地HA,所以也不大好;sharding是mongo的一个亮点特性,可以自动分片。但是根据我的测试结果,在单集合达到2000万条数据的门槛之后,sharding才开始体现出性能优势,而sharding的数据是分布式的,所以备份会比较复杂,而且也需要更多的服务器,不利于成本。所以最后我考虑,还是使用replica set方式的集群部署比较合适。可以解决HA,备份,读写分离的问题


基本上采用官网推荐的这种TOPO:


理想情况下,最好是3个mongod实例分别部署在单独的server上,这样就需要3台server;出于成本考虑,也可以把2台secondary部署在同一台server上,primary由于要处理读写请求(读写暂不分离),需要很多内存,并且考虑HA因素,所以primary是需要保证独占一台server比较好,这样就一共需要2台server


一、集群配置方式


1、以-replset方式启动mongod

也可以用命令行启动,但是不利于管理,所以建议采用--config参数来启动,配置文件如下:

port=2222
bind_ip=127.0.0.1
dbpath=/home/zhengshengdong/mongo_dbs/db1
fork=true
replSet=rs0
logpath=/home/zhengshengdong/mongo_log/log1.txt
logappend=true
journal=true

./mongod --config /home/zhengshengdong/mongo_confs/mongo1.conf

然后如法炮制,启动另外2个mongod实例

2、初始化replica set,并添加secondary

用./mongo --port 2222连上准备作为primary的mongod实例,然后依次执行以下命令

rs.initiate()
rs.conf()
rs.add("host1:port")
rs.add("host2:port")

3、检查

在primary实例上执行

rs.status()
应该能看到类似下图的效果


二、验证HA场景

用java driver写了以下代码来做验证

public static void main(String[] args) throws UnknownHostException {

		ScheduledExecutorService executor = Executors
				.newSingleThreadScheduledExecutor();

		final MongoClient client = MongoConnectionHelper.getClient();
		client.setWriteConcern(WriteConcern.REPLICA_ACKNOWLEDGED);

		Runnable task = new Runnable() {

			private int i = 0;

			@Override
			public void run() {
				DB db = client.getDB("yilos");
				DBCollection collection = db.getCollection("test");
				DBObject o = new BasicDBObject("name", "MongoDB" + i).append(
						"count", i);
				try {
					collection.insert(o);
				} catch (Exception exc) {
					exc.printStackTrace();
				}

				i++;
			}
		};

		executor.scheduleWithFixedDelay(task, 1, 1, TimeUnit.SECONDS);

	}
每隔1秒往集群中写入一条数据,然后手动把primary shutdown,观察发现jvm console给出提示:

警告: Primary switching from zhengshengdong-K43SA/127.0.0.1:2222 to mongodb.kyfxbl.net/127.0.0.1:4444

这条消息说明,mongo自动处理了primary的切换,对于应用来说是透明的。然后查看mongo中的记录,发现在切换完成以后,写入操作确实继续了


上图可以看到,在2926和2931之间,正在进行primary倒换,在完成之后,应用可以继续写入数据

但是明显可以看到,中间2927,2928,2929,2930这4条数据丢失了(mongo的primary倒换大约需要3-5秒时间),对于业务来说,虽然时间不长,但是如果因此丢失了业务数据,也是不能接受的

接下来再仔细看下这段时间内代码抛出的异常:

com.mongodb.MongoException$Network: Write operation to server mongodb.kyfxbl.net/127.0.0.1:4444 failed on database yilos
at com.mongodb.DBTCPConnector.say(DBTCPConnector.java:153)
at com.mongodb.DBTCPConnector.say(DBTCPConnector.java:115)
at com.mongodb.DBApiLayer$MyCollection.insert(DBApiLayer.java:248)
at com.mongodb.DBApiLayer$MyCollection.insert(DBApiLayer.java:204)
at com.mongodb.DBCollection.insert(DBCollection.java:76)