mongodb源码分析(十五)replication replset模式的初始化

本文深入分析了MongoDB复制集(replset)的初始化过程,包括配置集合如local.oplog.rs和local.system.replset的作用。内容涉及replset模式的配置要求,如votes设置对主副节点切换的影响,以及仲裁节点在确保系统正常运行中的作用。文章还概述了启动时的配置加载、心跳连接建立、同步线程和produce线程的功能,并指出状态切换的相关代码逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

          相对于主从模式,replset模式复杂得多,其中的主从对应于这里的primary,secondary概念,primary和

secondary之间可以切换,primary掉线后能够自动的选取一个secondary成为新的primary,当然这里也是有

限制的,本文将会分析到.首先来看replset模式用到的几个集合.

local.oplog.rs: 记录replset模式下的操作日志,master/slave模式下为local.oplog.$main.

local.system.replset  replset模式的配置.就是rs.initiate,rs.add等设置的信息.

先来看看一个典型的replset 配置.

当我们写一个数据时如:

db.foo.insert({x:1})
db.runCommand({getLastError:1,w:"veryImportant"})
只有当这次写被写到了veryImportant指定的三个地方,如ny sf cloud时,getLastError才会返回成功,否则其

会一直等待.这种方式可以确保一份数据被写到了不同的服务器上.来看看另一种的replset配置.

{_id:'myset', members:[{_id:0,host:'192.168.136.1:27040'},{_id:1,host:'192.168.136.1:27050',votes:0}]}

这里只有两台服务器,若端口为27050的服务器关闭,那么27040端口的服务器还是primary.并不会转成secondary

并且无法工作.但是如下配置:

{_id:'myset', members:[{_id:0,host:'192.168.136.1:27040'},{_id:1,host:'192.168.136.1:27050'}]}
那么当27050关闭后27040将从primary转成secondary,整个replset将无法工作.原因在于这里的votes.mongodb的

replset规定在线的服务器的votes总和的两倍要大于所有replset中配置的服务器votes的总和,

2*online_votes>all_replset_config_vote,这时replset才能正常的工作,否则将无法正常的工作.如果不设置votes默

认其值为1.讨论另外一种情况,当27040的服务器掉线时那么27050的服务器将无法成为primary,系统将不再工作.

若一开始配置如下,27040的服务器成为primary,这个时候若27040掉线,27050将接管工作成为primary.但是若

27050掉线,那么服务器将变得不可用,因为votes值为0了.这里最好通过添加仲裁来解决问题,仲裁虽然只做投票,并

{_id:'myset', members:[{_id:0,host:'192.168.136.1:27040',votes:0},{_id:1,host:'192.168.136.1:27050'}]}

不会成为primary,secondary,但是其可以在一些服务器掉线时通过保证votes值让整个系统保持正常运行,所以

10gen也建议:

Deploy an arbiter to ensure that a replica set will have a sufficient number of members to elect a primary. While having replica sets with 2 members is not recommended for production environments, if you have just two members, deploy an arbiter. Also, for any replica set with an even number of members, deploy an arbiter.

继续看replset的流程.

1. 初始化时如果启动参数不配置replset那么启动时replset会不断的加载config.config的来源有三个.一是本地

local.system.replset集合中保存的数据,二是调用rs.initiate函数设置的config,三是来自其它replset集的心跳协

议传过来的.

2. 得到配置信息后初始化,和其它服务器建立心跳连接.

3. 启动同步线程,replset集都需要启动同步线程,但是只有secondary会去同步primary的数据.

4. 启动produce线程,这个线程负责向primary请求数据,同步线程从这个线程得到操作log然后在本地replay.

5. 启动时和后面的心态协议部分会调用msgCheckNewState更改服务器状态,从secondary转primary或者反之.

下面来看代码.首先从rs.initiate(cfg)初始化开始.初始化时执行replSetInitiate命令.直接转到该命令的执行.

virtual bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
    if( cmdObj["replSetInitiate"].type() != Object ) {//配置数据来自于启动命令行
        string name;
        vector<HostAndPort> seeds;
        set<HostAndPort> seedSet;
        parseReplsetCmdLine(cmdLine._replSet, name, seeds, seedSet); // may throw...
        bob b;
        b.append("_id", name);
        bob members;
        members.append("0", BSON( "_id" << 0 << "host" << HostAndPort::me().toString() ));
        result.append("me", HostAndPort::me().toString());
        for( unsigned i = 0; i < seeds.size(); i++ )
            members.append(bob::numStr(i+1), BSON( "_id" << i+1 << "host" << seeds[i].toString()));
        b.appendArray("members", members.obj());
        configObj = b.obj();
    }
    else {//得到配置
        configObj = cmdObj["replSetInitiate"].Obj();
    }
    bool parsed = false;
    ReplSetConfig newConfig(configObj);//从配置数据中得到配置结构.
    parsed = true;
    checkMembersUpForConfigChange(newConfig, result, true);//查看配置的服务器是否能够连接
    createOplog();//建立local.system.replset集合.
    Lock::GlobalWrite lk;
    bo comment = BSON( "msg" << "initiating set");
    newConfig.saveConfigLocally(comment);//将配置保存到local.system.replset
    result.append("info", "Config now saved locally.  Should come online in about a minute.");
    ReplSet::startupStatus = ReplSet::SOON;
    ReplSet::startupStatusMsg.set("Received replSetInitiate - should come online shortly.");
    return true;
}
run->ReplSetConfig

    ReplSetConfig::ReplSetConfig(BSONObj cfg, bool force) :
        _ok(false),_majority(-1)
    {
        _constructed = false;
        clear();
        from(cfg);//具体
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值