日期:2014-05-16 浏览次数:20490 次
版本: 2.2.0
以下内容涉及之前的文章<MongoDb move chunk 故障分析和处理 (SERVER-5351)> .
在前面的文章<MongoDb move chunk 故障分析和处理 (SERVER-5351)> 提到的问题, 我们move chunk失败了. 问题的调查直指变量 vector _slaves, 该变量只会在关闭mongod和启动mongod的时候做clear操作, 而其他时候只会增或者改.从我们move chunk日志里面看出来, 我们的mongod的_slaves变量里面应该有 5/2+1 或者 4/2+1 个元素, 那么怎么来的呢? 我们明明只有3个secondary.
经过代码的追查, 发现了几个点
1) 在secondary mongod的rs.me里有唯一一条记录, 我们暂时叫它作 M. M有两个关键的元素 _id 和 host, _id是这个mongod的一个唯一id, 由ObjectId生成, host是这个mongod部署的机器的域名.
2) 在move chunk的过程中primary会向secondary获取一个remoteid, 也就是上面提到的_id
3) secondary在启动后, 一旦需要获取记录M, 则会去rs.me里面查, 查询代码是这样的:
bool replHandshake(DBClientConnection *conn) { string myname = getHostName(); BSONObj me; { Lock::DBWrite l("local"); if ( ! Helpers::getSingleton( "local.me" , me ) || //从数据库local.me里面取出来机器的id, 这个就是所谓的_remoteId ! me.hasField("host") || me["host"].String() != myname ) {//这条记录里面的host和机器当前的host不同, 则需要清空重新设置, 此时就会重置_id Helpers::emptyCollection("local.me"); BSONObjBuilder b; b.appendOID( "_id" , 0 , true );//如果从local.me里面取不到id, 则创建一个id, 作为所谓的_remoteId b.append( "host", myname ); me = b.obj(); Helpers::putSingleton( "local.me" , me ); } } BSONObjBuilder cmd; //把id封装为 {"handshake": _remoteId}, 这个和我们在日志里面看到的一致, _remoteId在bsonobj里面的key是 "handshake" cmd.appendAs( me["_id"] , "handshake" ); if (theReplSet) { cmd.append("member", theReplSet->selfId()); } BSONObj res; bool ok = conn->runCommand( "admin" , cmd.obj() , res );//执行handshake命令 return true; }
5) 经过确认, 我们的集群确实经历过搬机房, 修改域名, 重启过这些部署了secondary的机器.
到此为止, 总结一下
联系另外一篇博文<MongoDb move chunk 故障分析和处理>, _slaves这个变量是primary用来确定自己需要去跟踪多少个secondary的同步状态, map<Ident,OpTime> _slaves 的key值是secondary机器的唯一标识, value是Oplog同步到哪一条状态. 只要是曾经有一次作为secondary去跟primary同步数据, 那么primary的_slaves里面就会记录这个机器的Ident(是_remoteId和host(在我们的集群里面用ip, 我们ip没有修改)和ns(日志显示是local.oplog.rs)的组合),
Ident确定了唯一的一条_slaves记录.
如果修改过域名, 那么就会导致新的Ident被插入到_slaves里面, 其对应的opTime会非常过时, 导致movechunk的时候, 要的等带多数secondary同步完成发生了错误.