MongoDB复制集原理

复制集简介

Mongodb复制集由一组Mongod实例(进程)组成,包含一个Primary节点和多个Secondary节点,Mongodb Driver(客户端)的所有数据都写入Primary,Secondary从Primary同步写入的数据,以保持复制集内所有成员存储相同的数据集,提供数据的高可用。

下图(图片源于Mongodb官方文档)是一个典型的Mongdb复制集,包含一个Primary节点和2个Secondary节点。

Primary选举

复制集通过replSetInitiate命令(或mongo shell的rs.initiate())进行初始化,初始化后各个成员间开始发送心跳消息,并发起Priamry选举操作,获得『大多数』成员投票支持的节点,会成为Primary,其余节点成为Secondary。

初始化复制集

config = {
    _id : "my_replica_set",
    members : [
         {_id : 0, host : "rs1.example.net:27017"},
         {_id : 1, host : "rs2.example.net:27017"},
         {_id : 2, host : "rs3.example.net:27017"},
   ]
}

rs.initiate(config)

复制

『大多数』的定义

假设复制集内投票成员(后续介绍)数量为N,则大多数为 N/2 + 1,当复制集内存活成员数量不足大多数时,整个复制集将无法选举出Primary,复制集将无法提供写服务,处于只读状态。

投票成员数

大多数

容忍失效数

1

1

0

2

2

0

3

2

1

4

3

1

5

3

2

6

4

2

7

4

3

通常建议将复制集成员数量设置为奇数,从上表可以看出3个节点和4个节点的复制集都只能容忍1个节点失效,从『服务可用性』的角度看,其效果是一样的。(但无疑4个节点能提供更可靠的数据存储)

特殊的Secondary

正常情况下,复制集的Seconary会参与Primary选举(自身也可能会被选为Primary),并从Primary同步最新写入的数据,以保证与Primary存储相同的数据。

Secondary可以提供读服务,增加Secondary节点可以提供复制集的读服务能力,同时提升复制集的可用性。另外,Mongodb支持对复制集的Secondary节点进行灵活的配置,以适应多种场景的需求。

Arbiter

Arbiter节点只参与投票,不能被选为Primary,并且不从Primary同步数据。

比如你部署了一个2个节点的复制集,1个Primary,1个Secondary,任意节点宕机,复制集将不能提供服务了(无法选出Primary),这时可以给复制集添加一个Arbiter节点,即使有节点宕机,仍能选出Primary。

Arbiter本身不存储数据,是非常轻量级的服务,当复制集成员为偶数时,最好加入一个Arbiter节点,以提升复制集可用性。

Priority0

Priority0节点的选举优先级为0,不会被选举为Primary

比如你跨机房A、B部署了一个复制集,并且想指定Primary必须在A机房,这时可以将B机房的复制集成员Priority设置为0,这样Primary就一定会是A机房的成员。(注意:如果这样部署,最好将『大多数』节点部署在A机房,否则网络分区时可能无法选出Primary)

Vote0

Mongodb 3.0里,复制集成员最多50个,参与Primary选举投票的成员最多7个,其他成员(Vote0)的vote属性必须设置为0,即不参与投票。

Hidden

Hidden节点不能被选为主(Priority为0),并且对Driver不可见。

因Hidden节点不会接受Driver的请求,可使用Hidden节点做一些数据备份、离线计算的任务,不会影响复制集的服务。

Delayed

Delayed节点必须是Hidden节点,并且其数据落后与Primary一段时间(可配置,比如1个小时)。

因Delayed节点的数据比Primary落后一段时间,当错误或者无效的数据写入Primary时,可通过Delayed节点的数据来恢复到之前的时间点。

数据同步

Primary与Secondary之间通过oplog来同步数据,Primary上的写操作完成后,会向特殊的local.oplog.rs特殊集合写入一条oplog,Secondary不断的从Primary取新的oplog并应用。

因oplog的数据会不断增加,local.oplog.rs被设置成为一个capped集合,当容量达到配置上限时,会将最旧的数据删除掉。另外考虑到oplog在Secondary上可能重复应用,oplog必须具有幂等性,即重复应用也会得到相同的结果。

如下oplog的格式,包含ts、h、op、ns、o等字段

{
  "ts" : Timestamp(1446011584, 2),
  "h" : NumberLong("1687359108795812092"), 
  "v" : 2, 
  "op" : "i", 
  "ns" : "test.nosql", 
  "o" : { "_id" : ObjectId("563062c0b085733f34ab4129"), "name" : "mongodb", "score" : "100" } 
}

复制

ts: 操作时间,当前timestamp + 计数器,计数器每秒都被重置
h:操作的全局唯一标识
v:oplog版本信息
op:操作类型
i:插入操作
u:更新操作
d:删除操作
c:执行命令(如createDatabase,dropDatabase)
n:空操作,特殊用途
ns:操作针对的集合
o:操作内容,如果是更新操作
o2:操作查询条件,仅update操作包含该字段

复制

Secondary初次同步数据时,会先进行init sync,从Primary(或其他数据更新的Secondary)同步全量数据,然后不断通过tailable cursor从Primary的local.oplog.rs集合里查询最新的oplog并应用到自身。

init sync过程包含如下步骤

T1时间,从Primary同步所有数据库的数据(local除外),通过listDatabases + listCollections + cloneCollection敏命令组合完成,假设T2时间完成所有操作。 从Primary应用[T1-T2]时间段内的所有oplog,可能部分操作已经包含在步骤1,但由于oplog的幂等性,可重复应用。 根据Primary各集合的index设置,在Secondary上为相应集合创建index。(每个集合_id的index已在步骤1中完成)。 oplog集合的大小应根据DB规模及应用写入需求合理配置,配置得太大,会造成存储空间的浪费;配置得太小,可能造成Secondary的init sync一直无法成功。比如在步骤1里由于DB数据太多、并且oplog配置太小,导致oplog不足以存储[T1, T2]时间内的所有oplog,这就Secondary无法从Primary上同步完整的数据集。

修改复制集配置

当需要修改复制集时,比如增加成员、删除成员、或者修改成员配置(如priorty、vote、hidden、delayed等属性),可通过replSetReconfig命令(rs.reconfig())对复制集进行重新配置。

比如将复制集的第2个成员Priority设置为2,可执行如下命令

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

复制

细说Primary选举

Primary选举除了在复制集初始化时发生,还有如下场景

复制集被reconfig Secondary节点检测到Primary宕机时,会触发新Primary的选举 当有Primary节点主动stepDown(主动降级为Secondary)时,也会触发新的Primary选举 Primary的选举受节点间心跳、优先级、最新的oplog时间等多种因素影响。

节点间心跳

复制集成员间默认每2s会发送一次心跳信息,如果10s未收到某个节点的心跳,则认为该节点已宕机;如果宕机的节点为Primary,Secondary(前提是可被选为Primary)会发起新的Primary选举。

节点优先级

每个节点都倾向于投票给优先级最高的节点 优先级为0的节点不会主动发起Primary选举 当Primary发现有优先级更高Secondary,并且该Secondary的数据落后在10s内,则Primary会主动降级,让优先级更高的Secondary有成为Primary的机会。

Optime

拥有最新optime(最近一条oplog的时间戳)的节点才能被选为主。

网络分区

只有更大多数投票节点间保持网络连通,才有机会被选Primary;如果Primary与大多数的节点断开连接,Primary会主动降级为Secondary。当发生网络分区时,可能在短时间内出现多个Primary,故Driver在写入时,最好设置『大多数成功』的策略,这样即使出现多个Primary,也只有一个Primary能成功写入大多数。

复制集的读写设置

Read Preference

默认情况下,复制集的所有读请求都发到Primary,Driver可通过设置Read Preference来将读请求路由到其他的节点。

primary: 默认规则,所有读请求发到Primary
primaryPreferred: Primary优先,如果Primary不可达,请求Secondary
secondary: 所有的读请求都发到secondary
secondaryPreferred:Secondary优先,当所有Secondary不可达时,请求Primary
nearest:读请求发送到最近的可达节点上(通过ping探测得出最近的节点)

复制

Write Concern

默认情况下,Primary完成写操作即返回,Driver可通过设置[Write Concern(https://docs.mongodb.org/manu...来设置写成功的规则。

如下的write concern规则设置写必须在大多数节点上成功,超时时间为5s。

db.products.insert(
  { item: "envelopes", qty : 100, type: "Clasp" },
  { writeConcern: { w: majority, wtimeout: 5000 } }
)

复制

上面的设置方式是针对单个请求的,也可以修改副本集默认的write concern,这样就不用每个请求单独设置。

cfg = rs.conf()
cfg.settings = {}
cfg.settings.getLastErrorDefaults = { w: "majority", wtimeout: 5000 }
rs.reconfig(cfg)

复制

异常处理(rollback)

当Primary宕机时,如果有数据未同步到Secondary,当Primary重新加入时,如果新的Primary上已经发生了写操作,则旧Primary需要回滚部分操作,以保证数据集与新的Primary一致。

旧Primary将回滚的数据写到单独的rollback目录下,数据库管理员可根据需要使用mongorestore进行恢复。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/33716.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

3.springboot开发篇

SpringBoot开发实用篇 ​ KF-1.热部署 热部署是不用重启项目,项目自动更新 非springboot项目热部署实现原理 ​ 开发非springboot项目时,我们要制作一个web工程并通过tomcat启动,通常需要先安装tomcat服务器到磁盘中,开发的程序…

密码学证明方案寒武纪大爆发——扩容、透明性和隐私的变革潜力

1. 引言 前序博客有: ZKP大爆炸 本文主要参考: StarkWare 2023年6月博客 Cambrian Explosion of Cryptographic Proofs----The transformative potential for scalability, transparency, and privacy2023年3月Eli Ben-Sasson在The 13th BIU Winter …

vmware postgresql大杂烩

Vmware 窗口过界: https://blog.csdn.net/u014139753/article/details/111603882 vmware, ubuntu 安装: https://zhuanlan.zhihu.com/p/141033713 https://blog.csdn.net/weixin_41805734/article/details/120698714 centos安装: https://w…

形式化验证,QED: Quick Error Detection Tests for Effective Post-Silicon Validation(二)

目录 一、Article:文献出处(方便再次搜索) (1)作者 (2)文献题目 (3)文献时间 (4)引用 二、Data:文献数据(总结归纳,方便理解&am…

抖音短视频矩阵系统源码:技术开发与实践

目录 一.短视频账号矩阵管理系统囊括的技术 1.开发必备的开发文档说明: 二.技术文档分享: 1.底层框架系统架构: 2.数据库接口设计 1.技术开发必备的开发文档说明: 1.1系统架构: 抖音SEO排名系统主要由以下几个模…

Spring Boot 属性加载原理解析

基于Spring Boot 3.1.0 系列文章 Spring Boot 源码阅读初始化环境搭建Spring Boot 框架整体启动流程详解Spring Boot 系统初始化器详解Spring Boot 监听器详解Spring Boot banner详解Spring Boot 属性配置解析Spring Boot 属性加载原理解析 在《Spring Boot 框架整体启动流程详…

【计算机视觉 | 图像分类】arxiv 计算机视觉关于图像分类的学术速递(6月 29 日论文合集)

文章目录 一、分类|识别相关(12篇)1.1 Pseudo-Bag Mixup Augmentation for Multiple Instance Learning Based Whole Slide Image Classification1.2 Improving Primate Sounds Classification using Binary Presorting for Deep Learning1.3 Challenges of Zero-Shot Recognit…

阿里云docker启动xxljob,部署自己的定时任务

本次安装版本xxl-job-admin:2.3.0 一:创建xxl-job数据库的各种表 作者官方地址 下载sql执行 二:docker拉取xxl-job镜像 docker pull xuxueli/xxl-job-admin:2.3.0 三:docker启动xxl-job服务 docker run -e PARAMS"--spring.datasour…

Tensorflow神经网络模型-鲜花种类识别

必应壁纸供图 Tensorflow神经网络模型-鲜花种类识别 数据集:https://download.csdn.net/download/weixin_53742691/87982215 导入相关依赖 import warnings import re from IPython.display import clear_output, display from tkinter import Tk, filedialog fro…

wampServer安装Redis 扩展

第一步:查看php版本信息 使用 phpinfo() 函数查看 PHP 的版本信息(用于选择扩展包) 版本信息:PHP版本为 8.0.26,编译器版本 Visual C 2019,CPU架构 x64 。 第二步:根据第一步信息的版本选择扩…

基于树莓派4B的YOLOv5-Lite目标检测的移植与部署(含训练教程)

前言:本文为手把手教学树莓派4B项目——YOLOv5-Lite目标检测,本次项目采用树莓派4B(Cortex-A72)作为核心 CPU 进行部署。该篇博客算是深度学习理论的初步实战,选择的网络模型为 YOLOv5 模型的变种 YOLOv5-Lite 模型。Y…

【AI底层逻辑】——篇章3(上):数据、信息与知识香农信息论信息熵

目录 引入 一、数据、信息、知识 二、“用信息丈量世界” 1、香农信息三定律 2、一条信息的价值 3、信息的熵 总结 引入 AI是一种处理信息的模型,我们把信息当作一种内容的载体,计算机发明以前很少有人思考它的本质是什么。随着通信技术的发展&a…

【ISO26262】汽车功能安全第3部分:概念阶段

GB/T34590《道路车辆 功能安全》分为以下部分: 需要文档的朋友,可以和我联系! tommi_wei@163.com GB/T34590的本部分规定了车辆在概念阶段的要求: ———相关项定义; ———安全生命周期启动; ———危害分析和风险评估;及 ———功能安全概念。 危害事件分类 对于每一个…

wsl子系统Ubuntu18.04,cuDNN安装

如果觉得本篇文章对您的学习起到帮助作用,请 点赞 关注 评论 ,留下您的足迹💪💪💪 本文主要wls子系统Ubuntu18.04安装cuDNN,安装cudnn坑巨多,因此记录以备日后查看,同时&#xff0…

GaussDB WDR报告分析

标题 问题描述问题现象告警业务影响原因分析处理方法步骤 1步骤 2步骤 3步骤 4步骤 6步骤 7步骤 8步骤9步骤 10步骤 11步骤 12 问题描述 CPU使用率高。 问题现象 出现CPU使用率超过阈值,CPU使用率快速上涨或短时间持续较高水平等现象。 告警 CPU使用率告警。 …

uniapp的表单校验方式整理

uniapp的表单校验方式整理 这里我使用的模板为: 第一种: uniapp本身自带表单校验的js文件,代码写的很简洁,也是比较全面的 只要按照规则校验即可,下面是对应的校验代码: /** 数据验证(表…

PyQt中数据库的访问(一)

访问数据库的第一步是确保ODBC数据源配置成功,我接下来会写数据源配置的文章,请继续关注本栏! (一)数据库连接 self.DBQSqlDatabase.addDatabase("QODBC") self.DB.setDatabaseName("Driver{sqlServer…

ModaHub AI模型开源社区——向量数据库Milvus存储操作教程

目录 存储操作 数据插入 数据落盘 定时触发 客户端触发 缓冲区达到上限触发 数据合并 建立索引 删除 删除集合 删除分区 删除实体 数据段整理 数据读取 常见问题 存储操作 阅读本文前,请先阅读 存储相关概念。 数据插入 客户端通过调用 insert 接…

【计算机视觉】DINO

paper:Emerging Properties in Self-Supervised Vision Transformers 源码:https://github.com/facebookresearch/dino 20230627周二目前只把第一部分看完了。 论文导读:DINO -自监督视觉Transformers - deephub的文章 - 知乎 综述类型&a…

线程不安全举例

1、举例说明集合类线程不安全 &#xff08;1&#xff09;查看源码可证明 看ArrayList源码 没有sync、lock&#xff0c;线程不安全 &#xff08;2&#xff09;创建多个线程写入读取数据 List<String> list new ArrayList<>(); for (int i 1; i <30 ; i) {n…