MongoDB的Replica Set POC验证

基础测试环境

硬件环境

虚化环境: 每节点2核心,4G内存,40G存储空间,iSCSI存储

IP:10.25.34.239,240和241

软件环境

操作系统:CentOS 6.2 64bit 内核版本2.6.32

文件系统: ext4

MongoDB版本:2.0.6

测试原始数据

桥论坛发帖和回帖数据,数据复制10分,每份数据当成一个租户,租户之间用uuid识别

测试方法

查询

1.      每个论坛板块的前20篇帖子的标题

2.      每个用户的最近20篇帖子标题

3.      根据帖子id查询帖子内容和回帖内容前20条

4.      根据帖子id查询回帖的最后20条

插入

1.      插入帖子

2.      插入回帖

更新

1.      根据ID更新帖子标题

2.      更加ID更新帖子内容

3.      根据ID更新回帖内容

混合

85%查询+10%的插入+%5的更新

 测试步骤

环境准备

配置和启动单节点MongoDB

#numactl --interleave=all${MONGODB_HOME}/bin/mongod --config conf/replSet.conf

(关闭NUMA

Mongodb配置文件

[root@eBSM-Server2 conf]# more replSet.conf

dbpath=/var/mongodb/data

logpath=/var/mongodb/log/rs0.log

fork = true

logappend = true                                                          

port = 27017

noauth = true

journal = true

rest = true

directoryperdb = true

replSet = rs0

oplogSize = 2048

配置Replica Set

参考

http://docs.mongodb.org/manual/core/replication/#          

在10.25.34.240上执行

./mongo

rs.initiate()

rs.conf()

rs.add("10.25.34.241:27017")

rs.add({_id:2,host:'10.25.34.239:27017', arbiterOnly: true});

 

PRIMARY>rs.status();

{

        "set" : "rs0",

        "date" :ISODate("2012-07-27T16:42:07Z"),

        "myState" : 1,

        "members" : [

                {

                        "_id" : 0,

                        "name" :"mongodb240:27017",

                        "health" : 1,

                        "state" : 1,

                        "stateStr" :"PRIMARY",

                        "optime" : {

                                "t" :1343407300000,

                                "i" :1

                        },

                        "optimeDate": ISODate("2012-07-27T16:41:40Z"),

                        "self" : true

                },

                {

                        "_id" : 1,

                        "name" :"10.25.34.241:27017",

                        "health" : 1,

                        "state" : 2,

                        "stateStr" :"SECONDARY",

                        "uptime" :1168,

                        "optime" : {

                                "t" :1343407300000,

                                "i" :1

                        },

                        "optimeDate": ISODate("2012-07-27T16:41:40Z"),

                       "lastHeartbeat" : ISODate("2012-07-27T16:42:06Z"),

                        "pingMs" : 0

                },

                {

                        "_id" : 2,

                        "name" :"10.25.34.239:27017",

                        "health" : 1,

                        "state" : 7,

                        "stateStr" :"ARBITER",

                        "uptime" :27,

                        "optime" : {

                                "t" :0,

                                "i" :0

                        },

                        "optimeDate" :ISODate("1970-01-01T00:00:00Z"),

                       "lastHeartbeat" : ISODate("2012-07-27T16:42:06Z"),

                        "pingMs" :177088741

                }

        ],

        "ok" : 1

}

导入数据后,collection posts 123万左右,2.4GB,reply 1258万条,4.6GB,具体信息见下图


获取DB对象代码

private DB getDB() {
		dbProperties = new MongoDBProperties();
		dbProperties.load();
		String ips = dbProperties.getIp();
		String[] ip = ips.split(",");
		StringBuilder ipBuilder = new StringBuilder();
		int port = dbProperties.getPort();
		List addrs = new ArrayList();
		for (String ipaddr : ip) {
			try {
				addrs.add(new ServerAddress(ipaddr, port));
				ipBuilder.append(ipaddr);
				ipBuilder.append("\t");

			} catch (UnknownHostException e) {
				LOGGER.error(e);
			}
		}
		String dbname = dbProperties.getDBName();
		MongoOptions options = new MongoOptions();
		options.autoConnectRetry = true;
		options.connectTimeout = 2000;
		try {
			mongo = new Mongo(addrs, options);
			mongo.setReadPreference(ReadPreference.SECONDARY);
		} catch (Exception e) {
			LOGGER.error(e.getMessage());
		}
		db = mongo.getDB(dbname);
		LOGGER.info("connect to MongoDB Server, ip = " + ipBuilder.toString() + " port =" + port
				+ " db = " + dbname);

		return db;
	}

增加secondary节点对应用层的影响

1.        增加一个节点34.238,复制节点数据qiao和local库到data目录

2.        在Primary上增加一条数据

3.        启动34.238

4.        rs.add("10.25.34.238:27017")

5.        等待238成为secondary节点后,查看增加的数据复制到了238节点上:实验结果,正确复制了数据到238

连接IP设置:可以设置集群中任意一个和多个节点,驱动程序会自己发现集群拓扑结构,注:如果mongo = new Mongo(addrs, options)中addrs不是List,那么驱动只是会去找具体的那个IP地址,当前IP连接不上或者不是master节点,程序会出错。

1.        加入一个不存在的节点IP,不影响,不报错

2.        加入一个关闭了的replica set节点ip,驱动程序会报告该节点可能down,如果有一个以上的正常节点可以链接,应用程序会正常执行

2012-8-2 13:12:18com.mongodb.ReplicaSetStatus$Node update

警告: Server seendown: 10.25.78.241:27017

 

3.        当连接的所有节点都不存在的时候,驱动会报错。

com.mongodb.MongoException:Rare case where master=null, probably all servers are down

         atcom.mongodb.DBTCPConnector$MyPort.get(DBTCPConnector.java:366)

 

4.        通过一个线程定期检测配置文件的方式,当配置文件发送变化的时候,定期更新Mongo对象和DB对象。注意:更新DB对象后需要重新执行DBCollection coll = db.getCollection(dbProperties.getCommentsColl());才能生效,否则coll对象依然会老的,不会起到配置文件变化,影响到系统的作用

/**
	 * 定周期执行
	 */
	public void doCheck(){
		ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
		long initialDelay  = 20;
		long delay = 20; //n秒钟检测一次
		final Runnable checker = new Runnable() {
			public void run() {
				getDB();
			}
		};
		scheduler.scheduleWithFixedDelay(checker, initialDelay, delay, TimeUnit.SECONDS);
	}


5.        mongo.setReadPreference(ReadPreference.SECONDARY);基本上的读请求走secondary节点,当有多个secondary节点的时候,请求会分布到多个secondary节点上

6.        动态增加一个secondary节点的时候,读负载会自动请求到secondary节点上,对应用透明

缩减节点对应用层的读影响

2个secondary节点+1个primary节点

1.        关闭一个secondary节点,部分查询报错,过几秒后,所有查询转移到另外一个secondary节点上

2012-8-2 15:11:04com.mongodb.ReplicaSetStatus$Node update

警告: Server seen down: mongodb240:27017
java.io.EOFException
         atorg.bson.io.Bits.readFully(Bits.java:37)
         atorg.bson.io.Bits.readFully(Bits.java:28)
         atcom.mongodb.Response.(Response.java:39)
         atcom.mongodb.DBPort.go(DBPort.java:128)
         atcom.mongodb.DBPort.go(DBPort.java:93)
         atcom.mongodb.DBPort.findOne(DBPort.java:146)
         atcom.mongodb.DBPort.runCommand(DBPort.java:157)
         atcom.mongodb.ReplicaSetStatus$Node.update(ReplicaSetStatus.java:255)
         atcom.mongodb.ReplicaSetStatus.updateAll(ReplicaSetStatus.java:462)
         atcom.mongodb.ReplicaSetStatus$Updater.run(ReplicaSetStatus.java:409)
2012-8-2 15:11:04 com.mongodb.DBPort _open
严重: going to sleep and retry. total sleep time after = 2154ms this time:100ms
2012-8-2 15:11:04 com.mongodb.DBPort _open
严重: going to sleep and retry. total sleep time after = 2060ms this time:100ms
2012-8-2 15:11:05 com.mongodb.DBPort _open
严重: going to sleep and retry. total sleep time after = 4418ms this time:200ms
2012-8-2 15:11:05 com.mongodb.DBPort _open
严重: going to sleep and retry. total sleep time after = 4310ms this time:200ms
2012-8-2 15:11:06 com.mongodb.DBPort _open
严重: going to sleep and retry. total sleep time after = 6880ms this time:400ms

等待超时后,查询retry,并正确返回结果

2.        关闭第二个secondary节点,部分查询报错,过几秒后,所有查询转移到primary节点上

3.        重新启动2个secondary节点,读请求自动转移到secondary节点上。此时关闭primary节点,重新选举一个新的primary节点,在此期间会出现一次错误,读请求不受影响,并自动转移到secondary节点上,新的primary节点上不出现读请求。错误内容如下:

2012-8-2 15:27:50 com.mongodb.ReplicaSetStatus$Nodeupdate

警告: Server seen down: 10.25.34.241:27017

缩减节点对应用层的写影响

设置mongo的连接ip只要任意一个replica set节点的ip都可以,不会报错,即使是连接的secondary节点

1.        停止primary节点,对应用的影响

初始Primary节点34.241,secondary节点:34.240和34.238

在程序insert的过程中,执行db.shutdownServer();关闭34.241节点,经过几秒钟后,34.240成为primary节点。

现象:

WriteResult result =commentsColl.insert(object);

String errorMsg = result.getError();

先抛异常com.mongodb.MongoException$Network:Software caused connection abort: recv failed

errorMsg报告:not master

此时34.240还没有成为primary节点

当34.240成为primary节点后,驱动报告

警告: Master switching from10.25.34.241:27017 to mongodb240:27017

然后正常可以插入记录

在这个过程中,一共5个线程,每个线程插入1000条记录,插入完成一次sleep 100ms,执行结果每个线程正常插入970条,异常30

16:21:13,891第一次插入记录失败,到16:21:16 primary节点切换成功,耗时3秒钟左右

你可能感兴趣的:(NoSQL)