MongoDB 快速入门实战教程进阶篇 二:提高数据服务可用性的复制集

前一部分的文章:

MongoDB 快速入门实战教程基础篇 一 :文档的 CR操作
MongoDB 快速入门实战教程基础篇 一 :文档的 UD操作

MongoDB 快速入门实战教程基础篇 二: 流式聚合操作
MongoDB 快速入门实战教程基础篇 三:执行计划与索引

MongoDB 快速入门实战教程进阶篇 一:数据模型

进阶篇 二 提高数据服务可用性的复制集

MongoDB 中的复制指的是将数据同步在多个服务器。复制操作将会在多个服务器上建立数据副本,这些副本的集合称为复制集,它们存储的内容与主服务器上的内容一致。建立了复制集之后,就可以在主服务器出现故障或无法连接的情况下保证数据服务可用。

复制集成员

MongoDB 的复制集可以支持多个节点,但要求至少有两个节点。任何情况下都只有一个主节点(即主服务器),它负责处理客户端发出的命令。除主节点之外的所有节点都称为从节点,它们会主动同步主节点中的数据。在 MongoDB 中,主节点称为 Primary,从节点称为 Secondarie。

主节点 Primary

主节点是复制集中唯一一个可以接收写操作的成员。MongoDB 在主节点上执行写操作,并将操作记录在主节点的 oplog 中,从节点会复制主节点的操作记录,然后执行相同操作以实现数据同步的目的。下图描述了由三个成员组成的复制集的成员关系:
在这里插入图片描述

这个复制集中有两个从节点和一个主节点。主节点接收客户端发起的写操作,从节点通过 oplog 实现数据同步。要注意的是,复制集中的所有从节点都可以接收读操作,但默认情况下读取操作依然是交给主节点。如果想要更改读取规则,可以查阅官方文档 Read Preference。要注意的是,每个复制集最多可拥有 50 名成员。

从节点 Secondary

从节点中存储的是主节点的数据副本。从节点将主节点中的 oplog 操作应用于自身,从而实现数据同步。要注意的是,这个“数据同步”的操作是异步进行的。下图描述了由三个成员组成的复制集的数据同步关系:
在这里插入图片描述

子节点会同步主节点上的操作,以实现数据同步。另外,各节点之间通过心跳(Heartbeat)来判断是否可用,假如某个节点在 10 秒内没有相应其他节点发出的 Heartbeat,那么它将会被标记为“掉线”,意为不可用或不可访问。

复制的基石—操作日志

上面提到,从节点的数据同步操作其实是执行主节点中执行过的操作。所有从节点都会拷贝主节点上的 local.oplog.rs 文件,即 oplog。oplog 记录主节点中的改动操作,但不记录读取操作。oplog 是一个特殊的上限集合,它支持基于顺序插入和检索文档的高吞吐操作。上限集合的大小是固定的,在达到最大记录数之后,如果再有新的记录传入,它会覆盖掉最早的记录。

从 MongoDB4.0 开始,我们可以使用 oplogSizeMB 在创建时设置 oplog 的大小,或者使用 replSetResizeOplog 使其能够突破上限集合的限制。假设我们想要将 oplog 的大小设置为 16000 兆字节,对应命令如下:

db.adminCommand({replSetResizeOplog: 1, size: 16000})

当第一次启用复制集,且未指定 oplog 大小时,MongoDB 将会创建一个默认大小的 oplog。oplog 的大小与操作系统和存储引擎相关,以下默认大小规则适用于类 Unix 操作系统和 Windows 操作系统:

存储引擎 默认的 oplog 大小 下限 上限
内存存储引擎 物理内存的 5% 50 MB 50 GB
WiredTiger 存储引擎 可用磁盘空间的 5% 990 MB 50 GB
MMAPv1 存储引擎 可用磁盘空间的 5% 990 MB 50 GB

对于 64 位的 macOS,oplog 的大小是 192M 的物理内存或磁盘空间,上述三种存储引擎的默认值均相同。

主节点故障的应对机制

在主节点出现故障时,整个系统应该有一个应对机制。MongoDB 为复制集提供了主节点选举和数据回滚来确保数据服务可用和避免数据丢失。

主节点选举

当主节点被标记为“掉线”,那么就意味着复制集需要一个新的主节点,否则将会导致服务不可用。这种情况下,复制集通过选举的方式来确定哪个成员会成为主节点。除了被标记为“掉线”之外,会触发选举的情况还有以下几种:

  • 复制集中添加了新的节点;
  • 初始化复制集;
  • 使用 rs.stepDown() 或者 rs.reconfig() 等方法维护复制集。

下图描述了因为主节点“掉线”引起的选举:
在这里插入图片描述

这是一个由三个成员组成的复制集,主节点“掉线”后,就需要在两个从节点中选出一个作为新的主节点。要注意的是,在选举完成之前,复制集无法处理写操作。在选出新的主节点之后,复制集的功能就会恢复正常。选举采用投票制,每个复制集最多只能拥有 7 名投票成员,这 7 个成员最多拥有 1 票。下图描述了由 9 个成员组成的复制集选举票权:
在这里插入图片描述

绿色背景的节点表示节点可用,灰色背景表示节点“掉线”。votes 代表票权,对应的数值代表初始票数。如果投票成员数量为偶数,就有可能会造成多个节点的票数相同,甚至陷入无限选举的泥潭。为了避免这种情况,我们就需要增加一个仲裁(Arbiter)节点。仲裁节点拥有投票权,但它没有存储数据副本,也不能成为主节点。新增仲裁节点后,票数就会从偶数变成奇数。

默认情况下,从标记主节点“掉线”到选举出新的主节点的时间不会超过 12 秒,但 MongoDB 也提供了可修改的配置来调整该时间。

数据回滚

当主节点发生故障,并选举出新的主节点时,MongoDB 将会在之前的主节点上执行回滚写操作。当“掉线”的主节点重新连接时,它将会以从节点的身份加入到复制集中,并回滚写操作,以便与其他成员的数据保持一致。MongoDB 4.0 版本对数据回滚进行了一些调整:

  • 回滚操作会在后台索引构建完成后进行;
  • 不限制回滚的数据量;
  • 回滚时间默认为 24 小时,且可以配置。

4.0 版本之前,回滚的最大数据量为 300 兆字节,超过上限的数据量需要进行手动干预;回滚时间默认为 30 分钟,且不可配置。

复制集部署实践

我们将介绍由三个成员组成的复制集部署过程,本次部署演示使用 MongoDB 官方的 Docker 镜像,并且不启用访问控制。如果想要了解有访问控制的复制集部署知识,可查阅官方文档 Deploy New Replica Set With Keyfile Access Control

注意:本次部署演示将在同一台计算机上启动多个 Docker 镜像,但实际工作中则是在多台不同的云服务器上部署 MongoDB。

部署复制集

在开始学习本节之前,请确保按照附章 Docker 官方文档 的指引安装 Docker。

首先,我们需要从 DockerHub 中拉取 MongoDB 官方提供的 mongo 服务镜像。在版本选择方面,我们选择最新版,即 latest。对应命令如下:

$ docker pull mongo:latest

将镜像拉取到本地后,分别使用 run 命令启动三个容器。启动时,我们需要为容器指定名称,以便后期使用,同时还需要指定复制集的名称,并设置容器的 bind_ip 。对应命令如下:

$ docker run --name mongoFir -d mongo:latest --replSet "mongoRepas" --bind_ip_all

$ docker run --name mongoSec -d mongo:latest --replSet "mongoRepas" --bind_ip_all

$ docker run --name mongoThr -d mongo:latest --replSet "mongoRepas" --bind_ip_all 

这里将容器分别命名为 mongoFirmongoSecmongoThr,复制集的名称指定为 mongoRepas,并解除 mongo 对于bind_ip 的限制。由于在启动时未绑定 IP,所以我们需要使用 grep 命令找到每个容器对应的 IP。对应命令如下:

$ docker inspect mongoFir | grep IPAddress

命令执行后,终端返回信息如下:

"SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.2",
                    "IPAddress": "172.17.0.2"

返回结果说明容器 mongoFir 绑定的 IP 为 172.17.0.2,mongo 服务的默认端口为 27017,所以名为 mongoFir 的容器中的 mongo 服务完整地址为 172.17.0.2:27017。接着依次查找容器 mongoSecmongoThr 对应的 mongo 服务地址。最终,三个容器对应的 mongo 服务地址依次如下:

172.17.0.2:27017
172.17.0.3:27017
172.17.0.4:27017

容器启动成功后,就可以开始初始化复制集的工作了。首先,连接任意一个容器的 MongoShell,例如容器 mongoFir。对应命令如下:

$ docker exec -it mongoFir mongo

命令执行后,就会连接上容器 mongoFir 的 MongoShell。然后在 MongoShell 中执行复制集初始化的命令:

> rs.initiate({
        _id: "mongoRepas",
        members:[
            {_id: 0, host: "172.17.0.2"},
            {_id: 1, host: "172.17.0.3"},
            {_id: 2, host: "172.17.0.4"}
        ]
})

在初始化复制集的时候指定了复制集的名称,并制定了成员的 _id 和对应的 IP 地址。命令执行后,MongoShell 输出如下文档:

{
    "ok" : 1,
    "operationTime" : Timestamp(1564287051, 1),
    "$clusterTime" : {
        "clusterTime" : Timestamp(1564287051, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    }
}

返回结果中的 ok: 1 代表复制集初始化成功。此时,MongoShell 的命令行标识符从 > 变为 mongoRepas:SECONDARY>,即复制集的 Shell。在复制集 Shell 中使用 rs.status() 命令查看当前复制集的状态信息,命令执行后输出如下内容:

还有 46% 的精彩内容
©著作权归作者所有,转载或内容合作请联系作者
支付 ¥4.99 继续阅读
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容