Skip to content

两地三中心

两个地方,三个中心的意思是:生产中心、同城容灾中心、异地容灾中心。从意义上来看就是,兼具同城容灾和异地容灾,结合起来就叫两地三中心

第一步:同城双中心,是指在同城或邻近城市建立两个可独立承担关键系统运行的数据中心,双中心具备基本等同的业务处理能力并通过高速链路实时同步数据,日常情况下可同时分担业务及管理系统的运行,并可切换运行;灾难情况下可在基本不丢失数据的情况下进行灾备应急切换,保持业务连续运行。

第二步:异地灾备中心是指在异地的城市建立一个备份的灾备中心,用于双中心的数据备份,当双中心出现自然灾害等原因而发生故障时,异地灾备中心可以用备份数据进行业务的恢复。

同城双活的区别就是,两地三中心比同城双活多了一个异地数据中心。这个异地数据中心主要用于规避大自然灾害发生时,异地的数据中心能够立即启动,保障业务和数据最大限度不受影响,仍能够正常运行,将企业因大自然灾害受到的损失减到最小

两地三中心架构图

MongoDB 两地三中心架构图

两地三中心要点

  • 节点数量建议要 5 个,2+2+1 模式
  • 主数据中心的两个节点要设置高一点的优先级,减少跨中心换主节点
  • 同城双中心之间的网络要保证低延迟和带宽,满足 writeConcern: Majority 的双中心写需求

实验架构

实验架构

实验步骤

1、配置域名解析

# 在 3 台虚拟机上分别执行以下 3 条命令,注意替换实际 IP 地址
echo "192.168.1.1 geekdemo1 member1.example.com member2.example.com" >> /etc/hosts
echo "192.168.1.2 geekdemo2 member3.example.com member4.example.com" >> /etc/hosts
echo "192.168.1.3 geekdemo3 member5.example.com" >> /etc/hosts
# 在 3 台虚拟机上分别执行以下 3 条命令,注意替换实际 IP 地址
echo "192.168.1.1 geekdemo1 member1.example.com member2.example.com" >> /etc/hosts
echo "192.168.1.2 geekdemo2 member3.example.com member4.example.com" >> /etc/hosts
echo "192.168.1.3 geekdemo3 member5.example.com" >> /etc/hosts

2、启动 5 个 MongoDB 实例

  • 在虚拟机1上执行以下命令
mkdir -p member1 member2
mongod --dbpath ~/member1 --replSet demo --bind_ip 0.0.0.0 --port 10001 --fork --logpath member1.log

mongod --dbpath ~/member2 --replSet demo --bind_ip 0.0.0.0 --port 10002 --fork --logpath member2.log
mkdir -p member1 member2
mongod --dbpath ~/member1 --replSet demo --bind_ip 0.0.0.0 --port 10001 --fork --logpath member1.log

mongod --dbpath ~/member2 --replSet demo --bind_ip 0.0.0.0 --port 10002 --fork --logpath member2.log
  • 在虚拟机2上执行以下命令
mkdir -p member3 member4
mongod --dbpath ~/member3 --replSet demo --bind_ip 0.0.0.0 --port 10003 --fork --logpath member3.log

mongod --dbpath ~/member4 --replSet demo --bind_ip 0.0.0.0 --port 10004 --fork --logpath member4.log
mkdir -p member3 member4
mongod --dbpath ~/member3 --replSet demo --bind_ip 0.0.0.0 --port 10003 --fork --logpath member3.log

mongod --dbpath ~/member4 --replSet demo --bind_ip 0.0.0.0 --port 10004 --fork --logpath member4.log
  • 在虚拟机3上执行以下命令
mkdir -p member5
mongod --dbpath ~/member5 --replSet demo --bind_ip 0.0.0.0 --port 10005 --fork --logpath member5.log
mkdir -p member5
mongod --dbpath ~/member5 --replSet demo --bind_ip 0.0.0.0 --port 10005 --fork --logpath member5.log

3、初始化副本集

  • 在任意一台虚拟机上执行
mongo member1.example.com:10001


>rs.initiate({
    "_id" : "demo",
    "version" : 1,
    "members" : [
        { "_id" : 0, "host" : "member1.example.com:10001" },
        { "_id" : 1, "host" : "member2.example.com:10002" },
        { "_id" : 2, "host" : "member3.example.com:10003" },
        { "_id" : 3, "host" : "member4.example.com:10004" },
        { "_id" : 4, "host" : "member5.example.com:10005" }
    ]
})
mongo member1.example.com:10001


>rs.initiate({
    "_id" : "demo",
    "version" : 1,
    "members" : [
        { "_id" : 0, "host" : "member1.example.com:10001" },
        { "_id" : 1, "host" : "member2.example.com:10002" },
        { "_id" : 2, "host" : "member3.example.com:10003" },
        { "_id" : 3, "host" : "member4.example.com:10004" },
        { "_id" : 4, "host" : "member5.example.com:10005" }
    ]
})

4、配置选举优先级

  • 把第一台机器上的2个实例的选举优先级调高为5和10(默认为1)
mongo member1.example.com:10001
>cfg = rs.conf()
>cfg.members[0].priority = 5
>cfg.members[1].priority = 10
>rs.reconfig(cfg)
mongo member1.example.com:10001
>cfg = rs.conf()
>cfg.members[0].priority = 5
>cfg.members[1].priority = 10
>rs.reconfig(cfg)

5、启动持续写脚本

# 4.2 默认 retryWrites,但加上无妨
mongo --retryWrites mongodb://member1.example.com:10001,member2.example.com:10002,member3.example.com:10003,member4.example.com:10004,member5.example.com:10005/test?replicaSet=demo ingest-script
# 4.2 默认 retryWrites,但加上无妨
mongo --retryWrites mongodb://member1.example.com:10001,member2.example.com:10002,member3.example.com:10003,member4.example.com:10004,member5.example.com:10005/test?replicaSet=demo ingest-script
  • ingest-script 内容(每2秒写一条记录)
shell
#cat ingest-script
db.test.drop();
for (var i = 1; i < 1000; i++) {
    db.test.insert({ item: i });
    inserted = db.test.findOne({ item: i });
    if (inserted) {
        print(" Item " + i + " was inserted " + new Date().getTime() / 1000);
    }
    else {
        print("Unexpected " + inserted);
    }
    sleep(2000);
}
#cat ingest-script
db.test.drop();
for (var i = 1; i < 1000; i++) {
    db.test.insert({ item: i });
    inserted = db.test.findOne({ item: i });
    if (inserted) {
        print(" Item " + i + " was inserted " + new Date().getTime() / 1000);
    }
    else {
        print("Unexpected " + inserted);
    }
    sleep(2000);
}

6、模拟从数据中心故障

  • 停止第 2 台虚拟机上所有 mongodb 进程
pkill mongod
pkill mongod

观察第3台虚拟机上的写入未受中断

7、模拟主数据中心故障

  • 停止第 1 台虚拟机上所有 mongodb 进程
pkill mongod
pkill mongod

观察第3台虚拟机上的写入未受中断