前言

副本集整理。 开始逐步把mongodb博客补齐了。

正文

什么是副本集

副本集是一组服务器,其中一个是用于处理写入操作的主节点,还有多个用于保存主节点的数据副本的从节点。

如果主节点崩溃了,则从节点会从其中选取出一个新的主节点。

作用

起到一个热备份 和 容灾的作用,如果出现不可预料的事故,比如主节点磁盘损坏,那么可以故障转移,其他节点将会提到主节点进行写入。

实验

现在一台机器上演示。

步骤一

创建对应的目录:

数据:

mkdir -p ~/data/rs{1,2,3}

日志:

mkdir -p ~/logs/rs{1,2,3}
步骤二

启动3个mongod:

mongod --replSet mydb --dbpath ~/data/rs1 --logpath ~/logs/rs1/log --port 27017 --smallfiles --oplogSize=200 &

mongod --replSet mydb --dbpath ~/data/rs2 --logpath ~/logs/rs2/log --port 27018 --smallfiles --oplogSize=200 &

mongod --replSet mydb --dbpath ~/data/rs3 --logpath ~/logs/rs3/log --port 27019 --smallfiles --oplogSize=200 &
步骤三

把副本连接到一起,副本集配置传递:

mongo --port 27017

初始化副本集配置:

rsconf={
"_id" : "mydb",
"members" : [
{
"_id" : 0,
"host" : "localhost:27017"
},
{
"_id" : 1,
"host" : "localhost:27018"
},
{
"_id" : 2,
"host" : "localhost:27019"
}
]
}
rs.initiate(rsconf)

这个配置文档就是副本集的配置。在localhost:27017 上运行的成员会解析配置并将消息发送给其他成员,提醒他们存在新的配置。

一旦所有成员都加载了配置,他们就会选择一个主节点并开始处理读写操作。

注意:

不能在不停机的情况下将单机服务器转换为副本集,以重新启动并初始化该副本集。因此,即使一开始只有一台服务器,你也希望将其配置为一个单成员的副本集。
这样,如果以后想添加更多成员,则可以在不停止运行的情况下进行添加。

然后使用rs.status() 查看副本集的状态

{
"set" : "mydb",
"date" : ISODate("2022-10-16T02:51:57.670Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1665888717, 1),
"t" : NumberLong(1)
},
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1665888717, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1665888717, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1665888717, 1),
"t" : NumberLong(1)
}
},
"members" : [
{
"_id" : 0,
"name" : "localhost:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 955,
"optime" : {
"ts" : Timestamp(1665888717, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2022-10-16T02:51:57Z"),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1665888285, 1),
"electionDate" : ISODate("2022-10-16T02:44:45Z"),
"configVersion" : 1,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "localhost:27018",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 443,
"optime" : {
"ts" : Timestamp(1665888707, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1665888707, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2022-10-16T02:51:47Z"),
"optimeDurableDate" : ISODate("2022-10-16T02:51:47Z"),
"lastHeartbeat" : ISODate("2022-10-16T02:51:55.983Z"),
"lastHeartbeatRecv" : ISODate("2022-10-16T02:51:57.128Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "localhost:27017",
"syncSourceHost" : "localhost:27017",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 1
},
{
"_id" : 2,
"name" : "localhost:27019",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 443,
"optime" : {
"ts" : Timestamp(1665888707, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1665888707, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2022-10-16T02:51:47Z"),
"optimeDurableDate" : ISODate("2022-10-16T02:51:47Z"),
"lastHeartbeat" : ISODate("2022-10-16T02:51:56.020Z"),
"lastHeartbeatRecv" : ISODate("2022-10-16T02:51:57.065Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "localhost:27017",
"syncSourceHost" : "localhost:27017",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 1
}
],
"ok" : 1,
"operationTime" : Timestamp(1665888717, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1665888717, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}

这样就可以看到27017 是主节点,其他的不是。

然后rs 是一个mongo 命令的封装:

mydb:PRIMARY> rs.help()
rs.status() { replSetGetStatus : 1 } checks repl set status
rs.initiate() { replSetInitiate : null } initiates set with default settings
rs.initiate(cfg) { replSetInitiate : cfg } initiates set with configuration cfg
rs.conf() get the current configuration object from local.system.replset
rs.reconfig(cfg) updates the configuration of a running replica set with cfg (disconnects)
rs.add(hostportstr) add a new member to the set with default attributes (disconnects)
rs.add(membercfgobj) add a new member to the set with extra attributes (disconnects)
rs.addArb(hostportstr) add a new member which is arbiterOnly:true (disconnects)
rs.stepDown([stepdownSecs, catchUpSecs]) step down as primary (disconnects)
rs.syncFrom(hostportstr) make a secondary sync from the given member
rs.freeze(secs) make a node ineligible to become primary for the time specified
rs.remove(hostportstr) remove a host from the replica set (disconnects)
rs.secondaryOk() allow queries on secondary nodes rs.printReplicationInfo() check oplog size and time range
rs.printSecondaryReplicationInfo() check replica set members and replication lag
db.isMaster() check who is primary
db.hello() check who is primary reconfiguration helpers disconnect from the database so the shell will display
an error, even if the command succeeds.

可以看下哪些是自己想要的。

简单的实验

非主节点是否可以写入数据:

结果是不行的。

主节点写入是否从节点会同步:

连接27017 判断是否是主节点:

那么开始连接一个从节点,并从节点上读取数据,和mysql 一样。

可以看到不让我们进行访问

这里面是一个这样的机制:

因为从节点落后于主节点,那么默认情况下是不让从从节点上读取数据。

这和mysql 是不一样的。

那么是否能修改配置来从从节点上读取数据,这也是可以的。

可以修改客户端的连接配置,可以来进行完成, 然后就可以访问从节点数据了。

下面来实验,如果主节点没了,那么是否这个副本集是否就没法使用了?

db.adminCommand({"shutdown":1});

使用上面这个命令进行关闭。

可以看到的确关闭了。

那么随便进入一个节点看下。

进入27018 查看。

那么主节点就变成了27018了。

用rs.status() 查看27017的状况:

已经不健康了,那么再次启动27017一下。

27017 就变成从节点了。

这个时候要增加副本集怎么办:

可以使用rs.add({"localhost":"27020"})

如果要删除怎么办:

可以使用rs.remove({"localhost":"27020"})

如果进行修改怎么办:

var config = rs.config()

config.members[0].host="localhost":"27017"

rs.reconfig(config)

这样就从新加载了。

副本集的一些理论知识

前面知道了,副本集3个情况下,如果一个没了,还是可以运行的。

那么如果两个挂了,是否最后一个可以继续运行呢?

答案是不能的,这里就不实验了。

因为有一个理论知识:

副本集在绝大多数活着的情况下才能正常运行。

也就是说3个有两个正常才能运行,5个就要3个。

为什么这样呢? 假设一个问题,现在有3个副本集,一个因为网络问题,无法与其他节点连接。

那么它自己就选自己为主节点,其他两个选他们自己其中一个为主节点。

那么问题来了,就有两个主节点了,这样就可以写入不同的主节点,那么就出现问题了,两边数据无法同步了。

下一个问题,副本集是如何选举的呢? 什么时候进行选举呢?

当一个从节点无法与主节点连通时候,他就会联系并请求其他的副本集成员将自己选举为主节点。

没错,就像边关大将,如果察觉皇帝不在了,就开始密谋向其他边关大臣推举自己作为皇帝。

然后其他边关大臣要确认是不是皇帝驾崩了,如果确认皇帝没有驾崩,那么是不会进行支持的。

如果确定皇帝不在了,那么也不一样选发起的这个边关大将。

而是先考虑哪个副本集是最新数据,然后是优先级最高的节点作为主节点。

如果一个副本是最新数据,而其他没有,那么会选择这个节点作为主节点。但是值得注意的是,如果优先级更高的节点同步了最新数据后,那么优先级更高的节点,将会成为新的主节点。

副本集之间会互相间隔两秒发送一次心跳。如果某个成员在10秒内没有反馈心跳,则其他成员会将改不良成员标记为无法访问。

前文提及到优先级最高的会作为主节点:

那么如何设置优先级呢?

rs.add({"host":"localhost:27017", "priority":1.5})

这个优先级有一个特殊值,如果选择0的话,那么这个节点永远不会成为新的节点。

然后优先级更高的一般会成为主节点,是这样的,如果设置了优先级更高的副本集,那么当这个副本集拥有最新数据的时候,当前节点会自动退位给这个节点。

config = rs.config()
config.members[0].priority=1.5
rs.reconfig(config)

我们可以看到前面是27018,现在变成了27017了。

根据上面结论得出:优先级最高的节点,才是合法继承人。

如果你想在从节点上读取数据,但是有一个从节点只是用来做备份的,机器性能很差的话,你不希望客户端去访问这台机器怎么办?

你可以设置该节点隐藏。

config.members[0].hidden=true

这样去设置。

其原理也很简单,就是客户端获取副本集信息的时候是调用db.isMaster() 来查看。

如果设置了,那么isMaster() 是不包含该隐藏的信息的。

所以客户端就不会去访问这个副本集了。

然后如果副本集只是作为备份的话,那么其实是不需要索引的,那么可以设置:

{"buildIndexs":false},这样从节点就不会创建索引了,同样它的优先级也应该设置为0,这样就不会选为主节点了。

破烂之道

这个破烂之道,并不是指垃圾的意思。

而是节约成本的方式,个人称为破烂之道。

从上面我们知道副本集肯定是3个和以上。

但是有些数据库很大,比如16T左右的话,如果购买的是云服务器,成本也是不低的。

这个时候公司认为要节约成本,那么其他这个时候只需要一个作为副本集作为备份就好。

这个时候就可以加入仲裁者这种方式。

mongodb 支持一种特殊类型的副本成员,叫做仲裁者。

作用就是参与选举,但是不会选择自己作为主节点。

仲裁者并不保存数据,也不会为客户端提供服务;它只是为了帮助具有两个成员的副本集满足大多数的条件。

设置仲裁者的方式:

rs.addArb("localhost:27021")

或者:

rs.add({"_id":4,"host":"localhost:27021","arbiterOnly":true})

仲裁者一般只有一个,因为仲裁者是为了绝大多数,来打破平衡的,防止偶数的情况,这是唯一的作用。

仲裁者缺点,那就是如果一个数据从节点完全挂了,无法恢复,要启动一个新的数据节点去替换掉旧的。

那么这个时候主节点负荷会很重,因为不仅要将数据复制为从节点,还需要处理应用程序的读写负荷。

下一节副本集的原理。

mongodb基础整理篇————副本概念篇[外篇]的更多相关文章

  1. mongodb基础整理篇————简单介绍[一]

    前言 简单介绍一下文档数据库. 正文 mongodb 是一个以json为数据模型的文档数据库. 这里要介绍一下什么是json.因为有些人认为'{a:1,b:2}' 是json,而"this ...

  2. mongodb基础整理篇————常规操作[二]

    前言 简单整理一下常规操作. 正文 虽然一般说写代码看的是思想,但是呢,如果不知道mongodb 有哪些常用的操作,那么你怎么能知道mongodb是否符合你的需求,比如说如果聚合功能都没有,你得自己写 ...

  3. 【笨木头Lua专栏】基础补充05:迭代器番外篇

    关于迭代器的内容, 另一点点,只是已经无关紧要了.应该算是一种扩展吧.就一起来开开眼界好了~ 笨木头花心贡献.哈?花心?不.是用心~ 转载请注明,原文地址: http://www.benmutou.c ...

  4. 重新整理 .net core 实践篇 ———— dotnet-dump [外篇]

    前言 本文的上一篇为: https://www.cnblogs.com/aoximin/p/16861797.html 该文为dotnet-dump 和 procdump 的实战介绍一下. 正文 现在 ...

  5. VT 入门番外篇——初识 VT

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  6. 羽夏看Win系统内核—— x64 番外篇

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  7. 羽夏看Win系统内核—— VT 入门番外篇

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  8. python自动化测试应用-番外篇--接口测试2

    篇2                 book-python-auto-test-番外篇--接口测试2 --lamecho辣么丑 大家好! 我是lamecho(辣么丑),今天将继续上一篇python接 ...

  9. (八)羽夏看C语言——C番外篇

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章 ...

随机推荐

  1. 转一篇MYSQL文章《数据库表设计,没有最好只有最适合》

    http://mp.weixin.qq.com/s/a8klpzM5iam0_JYSw7-U4g 我们在设计数据库的时候,是否会突破常规,找到最适合自己需求的设计方案,下面来举个例子: 常用的邻接表设 ...

  2. CF906C Party (状压DP)(未完成//鬼知道啥情况)

    CF上下了数据,本地能过,一交就错 这状压不用解释,看代码就懂. #include <iostream> #include <cstdio> #include <cstr ...

  3. Luogu2915 [USACO08NOV]奶牛混合起来Mixed Up Cows (状压DP)

    枚举末位状态 #include <iostream> #include <cstdio> #include <cstring> #include <algor ...

  4. django的csrf跨站请求伪造

    1.什么是跨站请求伪造 请看图: 我们自行写了一个网站模仿中国银行,用户不知道是否是真的中国银行,并且提交了转账信息,生成一个form表单,向银行服务器发送转账请求,这个form表单和正规银行网站的f ...

  5. Spring 14: Spring + MyBatis初步整合开发

    SM整合步骤 预期项目结构 新建数据库和数据表 springuser.sql脚本如下 create database ssm; use ssm; create table users( userid ...

  6. Homework7

    问:了解java的反射机制. 答:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法.而对于任意一个对象,都能够调用它的任意一个方法.这种动态获取的信息以及动态调用对象的 ...

  7. KingbaseES行转列(PIVOT)

    如果以交叉表格式显示,则商业智能查询返回的数据通常是最有用的.SELECT语句的pivot_.数据透视是数据仓库中的一项关键技术.在其中,您可以将多行输入转换为数据仓库中较少且通常较宽的行.进行数据透 ...

  8. SpringBoot使用自定义注解+AOP+Redis实现接口限流

    为什么要限流 系统在设计的时候,我们会有一个系统的预估容量,长时间超过系统能承受的TPS/QPS阈值,系统有可能会被压垮,最终导致整个服务不可用.为了避免这种情况,我们就需要对接口请求进行限流. 所以 ...

  9. logstash客户端传送symantec日志到elasticsearch

    一.安装相应版本的logstash wget https://artifacts.elastic.co/downloads/beats/logstash/logstash-7.5.2-x86_64.r ...

  10. Java开发学习(三十二)----Maven多环境配置切换与跳过测试的三种方式

    一.多环境开发 我们平常都是在自己的开发环境进行开发, 当开发完成后,需要把开发的功能部署到测试环境供测试人员进行测试使用, 等测试人员测试通过后,我们会将项目部署到生成环境上线使用. 这个时候就有一 ...