搭建高可用mongodb集群(三)—— 深入副本集内部机制

2023-11-12

在上一篇文章《搭建高可用mongodb集群(二)—— 副本集》 介绍了副本集的配置,这篇文章深入研究一下副本集的内部机制。还是带着副本集的问题来看吧!

  • 副本集故障转移,主节点是如何选举的?能否手动干涉下架某一台主节点。
  • 官方说副本集数量最好是奇数,为什么?
  • mongodb副本集是如何同步的?如果同步不及时会出现什么情况?会不会出现不一致性?
  • mongodb的故障转移会不会无故自动发生?什么条件会触发?频繁触发可能会带来系统负载加重?

Bully算法 mongodb副本集故障转移功能得益于它的选举机制。选举机制采用了Bully算法,可以很方便从分布式节点中选出主节点。一个分布式集群架构中一般都有一个所谓的主节点,可以有很多用途,比如缓存机器节点元数据,作为集群的访问入口等等。主节点有就有吧,我们干嘛要什么Bully算法?要明白这个我们先看看这两种架构:

  1. 指定主节点的架构,这种架构一般都会申明一个节点为主节点,其他节点都是从节点,如我们常用的mysql就是这样。但是这样架构我们在第一节说了整个集群如果主节点挂掉了就得手工操作,上架一个新的主节点或者从从节点恢复数据,不太灵活。

    mongodb4

  2. 不指定主节点,集群中的任意节点都可以成为主节点。mongodb也就是采用这种架构,一但主节点挂了其他从节点自动接替变成主节点。如下图:

    mongodb故障转移

好了,问题就在这个地方,既然所有节点都是一样,一但主节点挂了,怎么选择出来下一个节点是谁来做为主节点呢?这就是Bully算法解决的问题。

那什么是Bully算法,Bully算法是一种协调者(主节点)竞选算法,主要思想是集群的每个成员都可以声明它是主节点并通知其他节点。别的节点可以选择接受这个声称或是拒绝并进入主节点竞争。被其他所有节点接受的节点才能成为主节点。节点按照一些属性来判断谁应该胜出。这个属性可以是一个静态ID,也可以是更新的度量像最近一次事务ID(最新的节点会胜出)。详情请参考NoSQL数据库分布式算法的协调者竞选还有维基百科的解释 。

选举 那mongodb是怎进行选举的呢?官方这么描述:

We use a consensus protocol to pick a primary. Exact details will be spared here but that basic process is:

  1. get maxLocalOpOrdinal from each server.
  2. if a majority of servers are not up (from this server’s POV), remain in Secondary mode and stop.
  3. if the last op time seems very old, stop and await human intervention.
  4. else, using a consensus protocol, pick the server with the highest maxLocalOpOrdinal as the Primary.

大致翻译过来为使用一致协议选择主节点。基本步骤为:

  1. 得到每个服务器节点的最后操作时间戳。每个mongodb都有oplog机制会记录本机的操作,方便和主服务器进行对比数据是否同步还可以用于错误恢复。
  2. 如果集群中大部分服务器down机了,保留活着的节点都为 secondary状态并停止,不选举了。
  3. 如果集群中选举出来的主节点或者所有从节点最后一次同步时间看起来很旧了,停止选举等待人来操作。
  4. 如果上面都没有问题就选择最后操作时间戳最新(保证数据是最新的)的服务器节点作为主节点。

这里提到了一个一致协议(其实就是bully算法),这个和数据库的一致性协议还是有些区别,一致协议主要强调的是通过一些机制保证大家达成共识;而一致性协议强调的是操作的顺序一致性,比如同时读写一个数据会不会出现脏数据。一致协议在分布式里有一个经典的算法叫“Paxos算法”,后续再介绍。

上面有个问题,就是所有从节点的最后操作时间都是一样怎么办?就是谁先成为主节点的时间最快就选谁。

选举触发条件 选举不是什么时刻都会被触发的,有以下情况可以触发。

  1. 初始化一个副本集时。
  2. 副本集和主节点断开连接,可能是网络问题。
  3. 主节点挂掉。

选举还有个前提条件,参与选举的节点数量必须大于副本集总节点数量的一半,如果已经小于一半了所有节点保持只读状态。
日志将会出现:

can't see a majority of the set, relinquishing primary

主节点挂掉能否人为干预?答案是肯定的。

  1. 可以通过replSetStepDown命令下架主节点。这个命令可以登录主节点使用
    db.adminCommand({replSetStepDown : 1})

    如果杀不掉可以使用强制开关

    db.adminCommand({replSetStepDown : 1, force : true})

    或者使用 rs.stepDown(120)也可以达到同样的效果,中间的数字指不能在停止服务这段时间成为主节点,单位为秒。

  2. 设置一个从节点有比主节点有更高的优先级。
    先查看当前集群中优先级,通过rs.conf()命令,默认优先级为1是不显示的,这里标示出来。

    rs.conf();
    {
            "_id" : "rs0",
            "version" : 9,
            "members" : [
                    {
                            "_id" : 0,
                            "host" : "192.168.1.136:27017"                },
                    {
                            "_id" : 1,
                            "host" : "192.168.1.137:27017"                },
                    {
                            "_id" : 2,
                            "host" : "192.168.1.138:27017"                }
            ]
            }

    我们来设置,让id为1的主机可以优先成为主节点。

    cfg = rs.conf()
    cfg.members[0].priority = 1
    cfg.members[1].priority = 2
    cfg.members[2].priority = 1
    rs.reconfig(cfg)

    然后再执行rs.conf()命令查看优先级已经设置成功,主节点选举也会触发。

    {
            "_id" : "rs0",
            "version" : 9,
            "members" : [
                    {
                            "_id" : 0,
                            "host" : "192.168.1.136:27017"                },
                    {
                            "_id" : 1,
                            "host" : "192.168.1.137:27017",
                            "priority" : 2
                    },
                    {
                            "_id" : 2,
                            "host" : "192.168.1.138:27017"                }
              ]
             }

    如果不想让一个从节点成为主节点可以怎么操作?
    a、使用rs.freeze(120)冻结指定的秒数不能选举成为主节点。
    b、按照上一篇设置节点为Non-Voting类型。

  3. 当主节点不能和大部分从节点通讯。把主机节点网线拔掉,嘿嘿:)

    优先级还可以这么用,如果我们不想设置什么hidden节点,就用secondary类型作为备份节点也不想让他成为主节点怎么办?看下图,共三个节点分布在两个数据中心,数据中心2的节点设置优先级为0不能成为主节点,但是可以参与选举、数据复制。架构还是很灵活吧!

    deeprepset1

奇数 官方推荐副本集的成员数量为奇数,最多12个副本集节点,最多7个节点参与选举。最多12个副本集节点是因为没必要一份数据复制那么多份,备份太多反而增加了网络负载和拖慢了集群性能;而最多7个节点参与选举是因为内部选举机制节点数量太多就会导致1分钟内还选不出主节点,凡事只要适当就好。这个“12”、“7”数字还好,通过他们官方经过性能测试定义出来可以理解。具体还有哪些限制参考官方文档《 MongoDB Limits and Thresholds 》。 但是这里一直没搞懂整个集群为什么要奇数,通过测试集群的数量为偶数也是可以运行的,参考这个文章http://www.itpub.net/thread-1740982-1-1.html。后来突然看了一篇stackoverflow的文章终于顿悟了,mongodb本身设计的就是一个可以跨IDC的分布式数据库,所以我们应该把它放到大的环境来看。

假设四个节点被分成两个IDC,每个IDC各两台机器,如下图。但这样就出现了个问题,如果两个IDC网络断掉,这在广域网上很容易出现的问题,在上面选举中提到只要主节点和集群中大部分节点断开链接就会开始一轮新的选举操作,不过mongodb副本集两边都只有两个节点,但是选举要求参与的节点数量必须大于一半,这样所有集群节点都没办法参与选举,只会处于只读状态。但是如果是奇数节点就不会出现这个问题,假设3个节点,只要有2个节点活着就可以选举,5个中的3个,7个中的4个。。。

deeprepset2

心跳 综上所述,整个集群需要保持一定的通信才能知道哪些节点活着哪些节点挂掉。mongodb节点会向副本集中的其他节点每两秒就会发送一次pings包,如果其他节点在10秒钟之内没有返回就标示为不能访问。每个节点内部都会维护一个状态映射表,表明当前每个节点是什么角色、日志时间戳等关键信息。如果是主节点,除了维护映射表外还需要检查自己能否和集群中内大部分节点通讯,如果不能则把自己降级为secondary只读节点。

同步,副本集同步分为初始化同步和keep复制。初始化同步指全量从主节点同步数据,如果主节点数据量比较大同步时间会比较长。而keep复制指初始化同步过后,节点之间的实时同步一般是增量同步。初始化同步不只是在第一次才会被处罚,有以下两种情况会触发:

  1. secondary第一次加入,这个是肯定的。
  2. secondary落后的数据量超过了oplog的大小,这样也会被全量复制。

那什么是oplog的大小?前面说过oplog保存了数据的操作记录,secondary复制oplog并把里面的操作在secondary执行一遍。但是oplog也是mongodb的一个集合,保存在local.oplog.rs里,但是这个oplog是一个capped collection也就是固定大小的集合,新数据加入超过集合的大小会覆盖。所以这里需要注意,跨IDC的复制要设置合适的oplogSize,避免在生产环境经常产生全量复制。oplogSize 可以通过–oplogSize设置大小,对于linux 和windows 64位,oplog size默认为剩余磁盘空间的5%。

同步也并非只能从主节点同步,假设集群中3个节点,节点1是主节点在IDC1,节点2、节点3在IDC2,初始化节点2、节点3会从节点1同步数据。后面节点2、节点3会使用就近原则从当前IDC的副本集中进行复制,只要有一个节点从IDC1的节点1复制数据。

设置同步还要注意以下几点:

  1. secondary不会从delayed和hidden成员上复制数据。
  2. 只要是需要同步,两个成员的buildindexes必须要相同无论是否是true和false。buildindexes主要用来设置是否这个节点的数据用于查询,默认为true。
  3. 如果同步操作30秒都没有反应,则会重新选择一个节点进行同步。

到此,本章前面提到的问题全部解决了,不得不说mongodb的设计还真是强大!

后续继续解决上一节这几个问题:

  • 主节点挂了能否自动切换连接?目前需要手工切换。
  • 主节点的读写压力过大如何解决?

还有这两个问题后续解决:

  • 从节点每个上面的数据都是对数据库全量拷贝,从节点压力会不会过大?
  • 数据压力大到机器支撑不了的时候能否做到自动扩展?

原创文章,转载请注明: 转载自LANCEYAN.COM

本文链接地址: 搭建高可用mongodb集群(三)—— 深入副本集内部机制



http://www.lanceyan.com/tech/mongodb_repset2.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

搭建高可用mongodb集群(三)—— 深入副本集内部机制 的相关文章

  • Mongoose:转换为 ObjectId 失败

    我正在尝试在 MongoDB 中创建一个类别层次结构 以便通过 Mongoose 与 Node js 一起使用 我正在使用祖先数组方法 http docs mongodb org manual tutorial model tree str
  • mongo docker 镜像创建后未运行脚本

    我使用 docker compose 为前端 后端和 mongo 实例创建 3 个不同的容器 其中三个正在运行并在它们之间连接 但我需要在 mongo 实例运行后立即在数据库上创建一个管理员用户 根据 mongo 图像文档 每个脚本位于do
  • 在 cl-mongo 中实现 MongoDB SASL 身份验证

    我已经从 fons 分叉了 cl mongo common lisp MongoDB 库 存储库 因为它已经不再维护并且不支持 SCRAM SHA 1 登录过程 这是我的叉子 https github com mprelude cl mon
  • 使用 PyMongo 将 MongoDB find() 返回序列化为非匿名 JSON 数组

    我的 Python 代码查询 MongoDB 并返回an array以下对象 u attribute u value u id ObjectId 534776c66e5987041f6154bd 我想要实现的是返回以下 JSON mycol
  • 错误:键 $conditionalHandlers 不得以 '$' mongodb 开头

    我对 mongodb 特别是 Node js 的 mongoose 包有疑问 我有以下架构 var Schema mongoose Schema var location new Schema nomville type String re
  • Mongod 服务启动退出,代码为 100

    Problem 我的 mongo 服务不再启动 root machine service mongod start root machine service mongod status mongod service High perform
  • 多文档事务在使用 mongodb 4.08 社区服务器的 C# 中不起作用

    我需要使用 mongodb 事务更新多个文档 mongodb 社区服务器版本是 4 08 net 的 mongodb 驱动程序是 2 9 beta 也尝试过 2 8 从调试中 我可以看到它执行了 session AbortTransacti
  • mongodb 正在运行吗?

    我已经在我的 Unix 服务器上安装了 Mongodb 和 PHP 驱动程序 我的问题是如何判断 Mongodb 是否正在运行 是否有一个简单的命令行查询来检查状态 如果我从外壳程序启动一次 如果我退出外壳程序 它会继续运行 情况似乎并非如
  • 如何在java中创建mongoDB objectid

    参考帖子如何使用 Java 将数组添加到 MongoDB 文档 https stackoverflow com questions 15371839 how to add an array to a mongodb document usi
  • 清理 MongoDB 的输入

    我正在为 MongoDB 数据库程序编写 REST 接口 并尝试实现搜索功能 我想公开整个 MongoDB 接口 我确实有两个问题 但它们是相关的 所以我将它们放在一篇文章中 使用 Python json 模块解码不受信任的 JSON 是否
  • Spring Data mongodb:添加 MongoDb 访问凭据

    我的 Spring 应用程序中有以下工作配置
  • 我可以将 Play 与 DynamoDB 一起用于 AWS 上的 Web 应用程序吗?

    我正在为最终用户设计一个图像存储应用程序 它将具有许多 CRUD 类型的功能 我想在 Amazon Web Services AWS 上托管该应用程序 并打算使用该游戏 框架 S3 和 NoSQL 数据库 我找不到适用于 Play 的 Dy
  • MongoDB Java 嵌套文档无法使用键名中的点进行访问

    当在Java中使用MongoDB API时 我试图检索以下值two在如下所示的文档中 data id 1234 one two three 我正在运行这个 MongoCollection
  • MongoDB 如何选择候选计划

    我的应用程序中的查询速度很慢 创建两个索引后 它在本地数据库中使用它们以获得更好的性能 但是当我部署在生产数据库上时 它仍然使用原始索引 下面是我所做的 集合中的属性tasks team id project id created by a
  • 如何在 Spring MongoDB 聚合上投影 DBRef?

    我在 MongoDB shell 中完成了以下聚合 以获取每个用户每种类型的警报数量 db getCollection alerts aggregate unwind son group id son son level level cou
  • mongodb 中的 Redact 对我来说似乎很晦涩

    我现在正在与 redact 作斗争 我不确定是否理解它 我刚刚阅读了文档并尝试在集合成绩上使用 redact 它来自 mongodb 在线培训 grades 集合中的文档如下所示 id ObjectId 50b59cd75bed76f465
  • Mongoose 总是返回空数组? [复制]

    这个问题在这里已经有答案了 我是nodejs i的新手 我已经有一个名为aqi的数据库 集合名称为pln 我试图在网页上显示集合中的所有记录 但猫鼬总是返回空数组 我已经用其他数据库测试了它 但我可以从它们获取数据 但对于 pln mong
  • Model.find() 在猫鼬中返回空[重复]

    这个问题在这里已经有答案了 我正在使用 mongoose 来列出 mongodb 数据库中集合中的所有数据 从请求中 http localhost 3000 listdoc model Organization 我正在执行以下代码 expo
  • 本地 SQLite 与远程 MongoDB

    我正在设计一个新的 Web 项目 在研究了一些旨在可扩展性的选项后 我提出了两个数据库解决方案 为可扩展方式精心设计的本地 SQLite 文件 每个 X 用户一个新的数据库文件 因为写入将取决于用户内容 不存在跨用户数据依赖性 远程 Mon
  • 为什么MongoDB不使用复合索引进行查询?

    以下是我对此集合的复合索引和单一索引 db Collection getIndexes 1 v 2 key id 1 name id ns service Collection 2 v 2 key FirstId 1 SecondId 1

随机推荐

  • 通过反编译定制android ROM

    以下操作是基于接近原生Android 4 4的系统下进行 是白牌设备 1 copy system 整个目录的 apk copy 到本地 2 对里面的 apk 重新进行签名 3 放回设备里面 重新启动 如果运行正常 那么现在就拥有设备的系统签
  • 上海链节科技的介绍

    上海链节科技有限公司 诞生于产业加速重塑 数字化金融格局加速转型的浪潮中 立足于区块链 数字经济为实体经济赋能 为社会进步和经济发展提供高效率 低成本的数字化转型解决方案 通过与实体企业 人民大众的生产 生活消费产生直接 正向的链接 从真正
  • JavaFX 程序退出时结束子线程

    1 前言 在JavaFX的程序开发中 在调用子线程之后子线程还未结束时 我们点击应用程序右上角的关闭按钮的时候 我们会发现程序还没有真正的结束运行 这是因为我们的子线程没有在JavaFX的管理之下 2 如何关闭 在主方法中找到Stage类
  • 机器学习数据集_机器学习数据集的选择

    机器学习数据集 Before you is an article guide to open data sets for machine learning In it I for a start will collect a selecti
  • 会话列表

    java实现 题目描述 小云正在参与开发一个即时聊天工具 他负责其中的会话列表部分 会话列表为显示为一个从上到下的多行控件 其中每一行表示一个会话 每一个会话都可以以一个唯一正整数id表示 当用户在一个会话中发送或接收信息时 如果该会话已经
  • Wifi模块—源码分析Wifi热点扫描2(Android P)

    一 前言 这次接着讲Wifi工程流程中的Wifi热点扫描过程部分的获取扫描结果的过程 也是Wifi扫描过程的延续 可以先看前面Wifi扫描的分析过程 Wifi模块 源码分析Wifi热点扫描 Android P 二 图示调用流程 这次的调用流
  • 【华为OD机试真题2023B卷 JS】勾股数元组

    华为OD2023 B卷 机试题库全覆盖 刷题指南点这里 勾股数元组 知识点编程基础 时间限制 1s 空间限制 256MB 限定语言 不限 题目描述 如果3个正整数 a b c 满足a2 b2 c2的关系 则称 a b c 为勾股数 著名的勾
  • 【华为OD】最多几个直角三角形_全组合求解

    目录 一 题目描述 二 输入描述 三 输出描述 3 1 描述 四 题目解析 五 Java玩法 六 JavaScript玩法 一 题目描述 有 N 条线段 长度分别为 a 1 a n 现要求你计算这 N 条线段最多可以组合成几个直角三角形 每
  • Java中内部类详解(类的五成员之五:内部类)

    目录 友情提醒 概述 Java类的五成员之五 内部类 一 内部类 1 成员内部类 2 方法内部类 3 匿名内部类 4 静态内部类 二 匿名内部类与Lambda表达式 友情提醒 先看文章目录 大致了解知识点结构 直接点击文章目录可以跳转到文章
  • Git 如何优雅地回退代码

    前言 从接触编程就开始使用 Git 进行代码管理 先是自己玩 Github 又在工作中使用 Gitlab 虽然使用时间挺长 可是也只进行一些常用操作 如推拉代码 提交 合并等 更复杂的操作没有使用过 看过的教程也逐渐淡忘了 有些对不起 Li
  • 测试开发工程师的简历和面试准备

    文章目录 职业规划 核心事项 不必等待准备 完美 才投简历 准备简历 确定一批目标公司和目标职位 详细事项 可以慢慢完备 时间有限 注意结合所需 简历 简历命名 邮件标题同理 携带个人信息 优先使用pdf格式的简历 最好打印大小是A4 简历
  • WINAPI WinMain

    include
  • 为什么每个程序执行都有内核地址空间和程序地址空间?

    为什么每个用户态的程序映射到虚拟地址空间 都需要有内核地址空间和程序地址空间呢 因为程序地址空间最终都会调用系统调用 也就是内核的东东 所以每个程序要想执行 就必须有内核地址空间 也必须有程序地址空间 所用的application程序要想使
  • 11 种加密 & 哈希算法的原理及其 Java 实现

    11 种加密 哈希算法的原理及其 Java 实现 一 目的 二 运行环境 三 基本原理及步骤 I 各种加密算法的原理 DES 数据加密标准 Data Encryption Standard 算法介绍 算法流程 优点 缺点 破解方式 适用场景
  • Linux期末考试题库(超全)

    文章目录 Linux期末考试题库 选择题 填空题 简答题 操作题 Linux期末考试题库 选择题 在创建Linux分区时 一定要创建 D 两个分区 A FAT NTFS B FAT SWAP C NTFS SWAP D SWAP 根分区 在
  • react样式处理

    react样式处理有两种处理方式 行内样式处理 使用className来定义类名 使用行内样式处理 语法 lt 元素 style css属性1 值1 css属性2 值2 gt 用法 引入react核心包 import React from
  • 完全免费快速搭建个人www服务器

    想拥有自己的web服务器吗 想把服务器放到自己家里吗 通过ADSL拨号也能建立个人的服务器吗 本文告诉你答案 要建立自己的web服务器 需要两个最重要的工作 1 让别人知道你的主机 目前访问Internet上主机的方式主要有两种 一是通过I
  • [JAVAee]SpringBoot配置文件

    配置文件的介绍 配置文件当中记录了许多重要的配置信息 例如 数据库的连接信息 用户的账户与密码 项目的启动端口 第三方系统的调用密匙 用于记录问题产生的日志 在spring框架中一些特定的框架会自动调用配置文件中的配置信息来运用 配置文件中
  • KCF论文技术路线

    https blog csdn net crazyice521 article details 53525366 http www cnblogs com YiXiaoZhou p 5925019 html 一 算法介绍 KCF全称为Ker
  • 搭建高可用mongodb集群(三)—— 深入副本集内部机制

    在上一篇文章 搭建高可用mongodb集群 二 副本集 介绍了副本集的配置 这篇文章深入研究一下副本集的内部机制 还是带着副本集的问题来看吧 副本集故障转移 主节点是如何选举的 能否手动干涉下架某一台主节点 官方说副本集数量最好是奇数 为什