MongoDB复制集入门

MongoDB学习笔记系列博客


一,概述

MongoDB复制是将数据同步在多个服务器的过程。
复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性。
复制还允许您从硬件故障和服务中断中恢复数据。


二,什么是复制

  1. 保障数据的安全性
  2. 数据高可用性 (24*7)
  3. 灾难恢复
  4. 无需停机维护(如备份,重建索引,压缩)
  5. 分布式读取数据

三,MongoDB复制原理

mongodb的复制至少需要两个节点。其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据。
mongodb各个节点常见的搭配方式为:一主一从、一主多从。

MongoDB复制结构图如下所示:
MongoDB复制集入门_第1张图片
以上结构图总,客户端总主节点读取数据,在客户端写入数据到主节点是, 主节点与从节点进行数据交互保障数据的一致性。

复制集特征

  1. N 个节点的集群
  2. 任何节点可作为主节点
  3. 所有写入操作都在主节点上
  4. 自动故障转移
  5. 自动恢复

四,部署复制集

这里使用Windows平台部署,基于MongoDB 3.4版本。

创建复制集中每个节点存放数据的目录。
D:\MongoDB\Server\3.4\data\db_rs0\data\rs0_0
D:\MongoDB\Server\3.4\data\db_rs0\data\rs0_1
D:\MongoDB\Server\3.4\data\db_rs0\data\rs0_2

创建复制集中每个节点的日志文件。
D:\MongoDB\Server\3.4\data\db_rs0\data\configs_rs0\rs0_0.conf
D:\MongoDB\Server\3.4\data\db_rs0\data\configs_rs0\rs0_1.conf
D:\MongoDB\Server\3.4\data\db_rs0\data\configs_rs0\rs0_2.conf

创建复制集中的每个节点启动时所需的配置文件。

dbpath = D:\MongoDB\Server\3.4\data\db_rs0\data\rs0_0
logpath = D:\MongoDB\Server\3.4\data\db_rs0\data\logs\rs0_0.log
journal = true
port = 40000
replSet = rs0

文件中dbpath指向数据库数据文件存放的路径(第1步中已经创建好),logpath指向数据库的日志文件路径(第2步中已创建好),journal表示对于此mongod实例是否启动日志功能,port为实例监听的端口号,rs0为实例所在的复制集名称,更多参数意思可以参考MongoDB手册。

第二个节点配置文件为D:\MongoDB\Server\3.4\data\db_rs0\data\configs_rs0\rs0_1.conf,内容如下所示。

dbpath = D:\MongoDB\Server\3.4\data\db_rs0\data\rs0_1
logpath = D:\MongoDB\Server\3.4\data\db_rs0\data\logs\rs0_1.log
journal = true
port = 40001
replSet = rs0

第三个节点配置文件为D:\MongoDB\Server\3.4\data\db_rs0\data\configs_rs0\rs0_2.conf,内容如下所示。

dbpath = D:\MongoDB\Server\3.4\data\db_rs0\data\rs0_2
logpath = D:\MongoDB\Server\3.4\data\db_rs0\data\logs\rs0_2.log
journal = true
port = 40002
replSet = rs0

启动上三个节点对应的MongoDB实例。

mongod -config D:\MongoDB\Server\3.4\data\db_rs0\data\configs_rs0\rs0_0.conf
mongod -config D:\MongoDB\Server\3.4\data\db_rs0\data\configs_rs0\rs0_1.conf
mongod -config D:\MongoDB\Server\3.4\data\db_rs0\data\configs_rs0\rs0_2.conf

现在已经启动了3个实例,但是复制集还没配置好,如上图所描述的那样,我们应该通过配置确定哪个节点为primary,哪个节点为secondary。

启动一个mongo客户端,连接到上面的一个mongod实例。

mongo -port 40000

结果:
MongoDB复制集入门_第2张图片
这个时候的复制集只有刚才这个初始化的成员,通过如下命令查看。

rs.conf()

结果:
MongoDB复制集入门_第3张图片
按照MongoDB的默认设置,刚才执行初始化命令的这个mongod实例将成为复制集中的primary节点。

添加复制集中的secondary节点,继续在上面的mongod实例上执行如下命令。
MongoDB复制集入门_第4张图片

观察整个复制集的状态信息。

rs.status()

结果为:

/* 1 */
{
    "set" : "rs0",//复制集的名称
    "date" : ISODate("2017-06-11T09:48:41.400Z"),
    "myState" : 1,//当前节点成员所在复制集中的位置,如1表示primary,2表示secondary
    "term" : NumberLong(1),
    "heartbeatIntervalMillis" : NumberLong(2000),
    "optimes" : {
        "lastCommittedOpTime" : {
            "ts" : Timestamp(1497174514, 1),
            "t" : NumberLong(1)
        },
        "appliedOpTime" : {
            "ts" : Timestamp(1497174514, 1),
            "t" : NumberLong(1)
        },
        "durableOpTime" : {
            "ts" : Timestamp(1497174514, 1),
            "t" : NumberLong(1)
        }
    },
    "members" : [ //复制集的所有成员信息
        {
            "_id" : 0,//成员编号
            "name" : "VICTOR-PC:40000",//成员所在的服务器名称
            "health" : 1.0,//成员在复制集中是否运行,1表示运行,0表示失败
            "state" : 1,//成员在复制集中的状态,1是primary
            "stateStr" : "PRIMARY",//成员在复制集中的状态名称
            "uptime" : 1259,//成员的在线时间,单位是秒
            "optime" : {
                "ts" : Timestamp(1497174514, 1),
                "t" : NumberLong(1)
            },
            "optimeDate" : ISODate("2017-06-11T09:48:34.000Z"),
            "electionTime" : Timestamp(1497173622, 1),
            "electionDate" : ISODate("2017-06-11T09:33:42.000Z"),
            "configVersion" : 3,
            "self" : true//成员为当前命令所在的服务器
        }, 
        {
            "_id" : 1,
            "name" : "VICTOR-PC:40001",
            "health" : 1.0,
            "state" : 2,//成员所在复制集中的状态,2是secondary
            "stateStr" : "SECONDARY",
            "uptime" : 119,
            "optime" : {
                "ts" : Timestamp(1497174514, 1),
                "t" : NumberLong(1)
            },
            "optimeDurable" : {
                "ts" : Timestamp(1497174514, 1),
                "t" : NumberLong(1)
            },
            "optimeDate" : ISODate("2017-06-11T09:48:34.000Z"),
            "optimeDurableDate" : ISODate("2017-06-11T09:48:34.000Z"),
            "lastHeartbeat" : ISODate("2017-06-11T09:48:41.231Z"),
            "lastHeartbeatRecv" : ISODate("2017-06-11T09:48:40.686Z"),
            "pingMs" : NumberLong(0),//此远端成员到本实例间一个路由包的来回时间
            "syncingTo" : "VICTOR-PC:40000",//此成员需要从哪个实例同步数据
            "configVersion" : 3
        }, 
        {
            "_id" : 2,
            "name" : "VICTOR-PC:40002",
            "health" : 1.0,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 106,
            "optime" : {
                "ts" : Timestamp(1497174514, 1),
                "t" : NumberLong(1)
            },
            "optimeDurable" : {
                "ts" : Timestamp(1497174514, 1),
                "t" : NumberLong(1)
            },
            "optimeDate" : ISODate("2017-06-11T09:48:34.000Z"),
            "optimeDurableDate" : ISODate("2017-06-11T09:48:34.000Z"),
            "lastHeartbeat" : ISODate("2017-06-11T09:48:41.231Z"),
            "lastHeartbeatRecv" : ISODate("2017-06-11T09:48:39.968Z"),
            "pingMs" : NumberLong(0),
            "syncingTo" : "VICTOR-PC:40001",
            "configVersion" : 3
        }
    ],
    "ok" : 1.0
}

上面复制集状态信息的输出是基于primary实例的,也可以在secondary实例上输出复制集的状态信息,包含的字段与上面大致相同。


五,移除复制集节点

这里提供两个移除复制集节点的方法。

使用 rs.remove() 来移除节点

  • 关闭我们想要移除的 mongod 实例,可以通过在 mongo -port 端口号 连接要移除的mongod实例,执行 db.shutdownServer() 来关闭。
  • 连接到复制集现在的 primary的mongod实例。我们可以连接到任意一个复制集节点并执行 db.isMaster() 来确认是否为主节点。
  • 通过 rs.remove() 来移除节点。

我们以上面创建的复制集为例,删除40002端口的节点。
连接要移除的节点
MongoDB复制集入门_第5张图片
连接primary节点
这里写图片描述

通过 rs.reconfig() 来移除节点

  • 关闭我们想要移除的 mongod 实例,可以通过在 mongo -port 端口号 连接要移除的mongod实例,执行 db.shutdownServer() 来关闭。
  • 连接到复制集现在的 primary的mongod实例。我们可以连接到任意一个复制集节点并执行 db.isMaster() 来确认是否为主节点。
  • 使用 rs.conf() 来查看现在的复制集配置,并记住我们需要移除的节点的 members 数组的位置。
>rs.conf()
/* 1 */
{
    "_id" : "rs0",
    "version" : 5,
    "protocolVersion" : NumberLong(1),
    "members" : [ 
        {
            "_id" : 0,
            "host" : "VICTOR-PC:40000",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1.0,
            "tags" : {},
            "slaveDelay" : NumberLong(0),
            "votes" : 1
        }, 
        {
            "_id" : 1,
            "host" : "VICTOR-PC:40001",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1.0,
            "tags" : {},
            "slaveDelay" : NumberLong(0),
            "votes" : 1
        }, 
        {
            "_id" : 2,
            "host" : "VICTOR-PC:40002",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1.0,
            "tags" : {},
            "slaveDelay" : NumberLong(0),
            "votes" : 1
        }
    ],
    "settings" : {
        "chainingAllowed" : true,
        "heartbeatIntervalMillis" : 2000,
        "heartbeatTimeoutSecs" : 10,
        "electionTimeoutMillis" : 10000,
        "catchUpTimeoutMillis" : 2000,
        "getLastErrorModes" : {},
        "getLastErrorDefaults" : {
            "w" : 1,
            "wtimeout" : 0
        },
        "replicaSetId" : ObjectId("593d1c42196120213b965f1f")
    }
}
  • 将现在的的配置赋值给 cfg。
cfg = rs.conf()
  • 修改 cfg 来移除节点。
//移除VICTOR-PC:40002节点
cfg.members.splice(2,1)
  • 通过如下命令将新的配置覆盖应用在复制集用。
rs.reconfig(cfg)
  • 通过 rs.conf() 命令来再确认新的配置。
/* 1 */
{
    "_id" : "rs0",
    "version" : 6,
    "protocolVersion" : NumberLong(1),
    "members" : [ 
        {
            "_id" : 0,
            "host" : "VICTOR-PC:40000",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1.0,
            "tags" : {},
            "slaveDelay" : NumberLong(0),
            "votes" : 1
        }, 
        {
            "_id" : 1,
            "host" : "VICTOR-PC:40001",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1.0,
            "tags" : {},
            "slaveDelay" : NumberLong(0),
            "votes" : 1
        }
    ],
    "settings" : {
        "chainingAllowed" : true,
        "heartbeatIntervalMillis" : 2000,
        "heartbeatTimeoutSecs" : 10,
        "electionTimeoutMillis" : 10000,
        "catchUpTimeoutMillis" : 2000,
        "getLastErrorModes" : {},
        "getLastErrorDefaults" : {
            "w" : 1,
            "wtimeout" : 0
        },
        "replicaSetId" : ObjectId("593d1c42196120213b965f1f")
    }
}

六,添加仲裁者节点

添加仲裁者节点跟添加普通节点思路大致相同。

创建节点存储数据的目录。
D:\MongoDB\Server\3.4\data\db_rs0\data\rs0_3

创建节点的日志文件。
D:\MongoDB\Server\3.4\data\db_rs0\data\logs\rs0_3.log

创建节点启动时所需的配置文件。
D:\MongoDB\Server\3.4\data\db_rs0\data\configs_rs0\rs0_3.conf
配置文件内容

dbpath = D:\MongoDB\Server\3.4\data\db_rs0\data\rs0_3
logpath = D:\MongoDB\Server\3.4\data\db_rs0\data\logs\rs0_3.log
journal = true
port = 40003
replSet = rs0

启动节点的MongoDB实例

mongod -config D:\MongoDB\Server\3.4\data\db_rs0\data\configs_rs0\rs0_3.conf

primary节点加入仲裁者节点

rs.addArb("VICTOR-PC:40003")

查看效果。

>rs.conf()
/* 1 */
{
    "_id" : "rs0",
    "version" : 7,
    "protocolVersion" : NumberLong(1),
    "members" : [ 
        {
            "_id" : 0,
            "host" : "VICTOR-PC:40000",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1.0,
            "tags" : {},
            "slaveDelay" : NumberLong(0),
            "votes" : 1
        }, 
        {
            "_id" : 1,
            "host" : "VICTOR-PC:40001",
            "arbiterOnly" : false,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1.0,
            "tags" : {},
            "slaveDelay" : NumberLong(0),
            "votes" : 1
        }, 
        {
            "_id" : 2,
            "host" : "VICTOR-PC:40003",
            "arbiterOnly" : true,
            "buildIndexes" : true,
            "hidden" : false,
            "priority" : 1.0,
            "tags" : {},
            "slaveDelay" : NumberLong(0),
            "votes" : 1
        }
    ],
    "settings" : {
        "chainingAllowed" : true,
        "heartbeatIntervalMillis" : 2000,
        "heartbeatTimeoutSecs" : 10,
        "electionTimeoutMillis" : 10000,
        "catchUpTimeoutMillis" : 2000,
        "getLastErrorModes" : {},
        "getLastErrorDefaults" : {
            "w" : 1,
            "wtimeout" : 0
        },
        "replicaSetId" : ObjectId("593d1c42196120213b965f1f")
    }
}

七,将单节点转为复制集

关闭 standalone mongod 实例。
重启实例,并使用 –replSet 参数来指定复制集的名字。

mongod -config 配置文件路径 --replSet rs0

剩下的步骤跟上面添加节点一致。


八,更换复制集节点

我们可以通过下列命令来将复制集的members[0]节点的主机名修改为 “VICTOR-PC:40004”

cfg = rs.conf()
cfg.members[0].host = "VICTOR-PC:40004"
rs.reconfig(cfg)

注意:
复制集的任何配置变动都会使 primary 降职,并进行 election 。在选举过程中,所有已经建立的链接将会释放,这将返回一个错误,及时操作执行成功了。


九,参考

更多详细内容可以参考MongoDB官文文档https://docs.mongodb.com/manual/replication/

进一步学习复制集MongoDB复制集深入(设计复制集,日志,写关注,读关注,标签)

  • http://www.runoob.com/mongodb/mongodb-replication.html
  • http://docs.mongoing.com/manual-zh/administration/replica-sets.html
  • 《大数据存储 MongoDB实战指南》

你可能感兴趣的:(MongoDB)