首页 > 技术文章 > 分布式文件存储数据库 MongoDB集群搭建与基本操作

dreammer 2020-11-05 19:07 原文

  

1|0MongoDB 简介

  

  Mongo 并非芒果(Mango)的意思,而是源于 Humongous(巨大的;庞大的)一词。

  MongoDB 是一个基于分布式文件存储的 NoSQL 数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。关于什么是 NoSQL 可阅读《学了那么多 NoSQL 数据库 NoSQL 究竟是啥

  MongoDB 是一个介于关系型数据库和非关系型数据库之间的产品,是非关系型数据库当中功能最丰富,最像关系数据库的。

  MongoDB 使用 BSON(Binary JSON)对象来存储,与 JSON 格式的键值对(key/value)类似,字段值可以包含其他文档,数组及文档数组。支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系型数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

  

2|0MongoDB 历史

  

  2007 年,Dwight Merriman,Eliot Horowitz 和 Kevin Ryan 成立 10gen 软件公司,在成立之初,这家的公司目标是进军云计算行业,为企业提供云计算服务。在开发云计算产品时,他们准备开发一个类似于数据库的组件,为云计算产品提供存储服务。当时是关系型数据库一统天下的时间,他们觉得传统的关系型数据库无法满足他们的要求,他们想要一款程序员不懂SQL语言也可以使用的数据存储产品。

  在网络上找了一圈,不管是开源的还是闭源的产品,都没找到让他们满意的东西,既然找不到,那就自己开发吧,反正他们也有那个技术实力,10gen 的创始人都来自谷歌,他们创建的网络广告公司 DoubleClick 被谷歌收购了,这是他们的第二次创业。

  10gen 公司不使用关系型数据库是有一定原因的,当时他们还在 DoubleClick 公司的时候,就吃过关系型数据库的苦头。DoubleClick 是一家网络广告公司,服务美国众多的知名公司,该公司每秒提供 40 万个广告,但在可伸缩性和敏捷性方面经常遇到困难,因此他们不得不经常自己开发和使用许多自定义数据存储来解决现有关系型数据库的不足,这让他们很是苦恼。

  因此他们决定开发一款数据库产品解决他们在 DoubleClick 时遇到的问题,并为自己的云计算产品提供存储服务。

  • MongoDB 最初于 2007 年开发,由位于纽约的一个名为 10gen 的组织开发,现在被称为 MongoDB Inc.
  • 2009 年,经过将近 2 年的开发,10gen 开发出了 MongoDB 的雏形并将它开源以及正式命名为 MongoDB,同时成立开源社区,通过社区运营 MongoDB。
  • 2009 年 02 月 MongoDB 1.0 发布,提供了大部分基本的查询功能。
  • 2009 年 12 月 MongoDB 1.2 发布,引入了 map-reduce,支持大规模数据处理。
  • MongoDB 的第一个真正产品是从 2010 年 03 月发布的 MongoDB 1.4 版本开始的。
  • 2010 年 8 月 MongoDB 1.6 发布,引入了一些主要特性,比如用于水平伸缩的分片、具备自动故障转移能力的副本集以及对 IPv6 的支持。
  • 2012 年 05 月 23 日,MongoDB 2.1 发布。该版本采用全新架构,包含诸多增强。
  • 2012 年 06 月 06 日,MongoDB 2.0.6 发布,分布式文档数据库。
  • 2012 年 8 月 MongoDB 2.2 发布,引入了聚合管道,可以将多个数据处理步骤组合成一个操作链。
  • 2013 年 MongoDB 推出第一款商业版本 MongoDB Enterprise Advanced。
  • 2013 年 04 月 23 日,MongoDB 2.4.3 发布,此版本包括了一些性能优化,功能增强以及 bug 修复。
  • 2013 年 08 月 20 日,MongoDB 2.4.6 发布,仍然是以性能优化,功能增强和 bug 修复为主。
  • 2015 年 03 月 MongoDB 3.0 发布,包含了新的 WiredTiger 存储引擎、可插拔存储引擎 API、增加了 50 个副本集限制和安全改进。同年晚些时候又发布了 3.2 版本,支持文档验证、部分索引和一些主要的聚合增强。
  • 2016 年 MongoDB 推出了 Atlas 服务,MongoDB Atlas,与公有云服务厂商(谷歌、微软Azure)合作。这一年,MongoDB 爆出了非常严重的安全门事件,黑客通过 MongoDB 的默认监听地址 0.0.0.0 删除数据,并且通过此漏洞进行勒索,支付 0.2 到 0.5 的比特币就可以恢复数据。
  • 2017 年 10 月 MongoDB 公司成立 10 周年之际,顺利通过 IPO 在纽交所上市。开盘 24 美元,公司估值达到 16 亿美元,并获得 1.92 美元的筹资。
  • 2017 年 11 月 MongoDB 3.6 发布,为多集合连接查询、变更流和使用 JSON 模式进行文档验证提供了更好的支持。
  • 2018 年 06 月 MongoDB 4.0 发布,这一版本的发布获得了广泛的关注,提供了跨文档事务处理能力。这是一个重要的里程碑,MongoDB 已经为高数据完整性需求做好了准备。
  • 2019 年 03 月 18 日,Forrester 授予 MongoDB NoSQL 领导者称号。
  • 2019 年 10 月 MongoDB 4.2 发布,开始支持分布式事务。
  • 截至 2020 年 10 月,MongoDB 的社区版版本是 4.4.1,扩展性和性能增强,降低复制延迟,可用性和容错性增强,查询能力和易用性增强,MongoDB 云平台的功能更新。MongoDB 逐渐的从一个专注于数据库服务的厂商,转变为提供数据平台服务的厂商。

  截至 2020 年,MongoDB 的全球下载量达到了 1.1 亿次。MongoDB 公司目前有 2000 多名员工,有超过 18000 名付费客户,其中有很多客户同时使用 MongoDB Atlas 和 MongoDB 企业版。大多数大公司在内部的一些场景中仍然使用的是社区版。MongoDB 社区版仍然是开源的,除了一些关键特性外,它与 MongoDB 企业版差不多。

  

3|0MongoDB 支持语言

  

  

4|0MongoDB 与关系型数据库术语对比

  

SQL 术语概念MongoDB 术语概念
database(数据库) database(数据库)
table(表) collection(集合)
row(行) document or BSON document(文档)
column(列) field(字段)
index(索引) index(索引)
table joins(表连接) embedded documents and linking(嵌入的文档和链接)
primary key Specify any unique column or column combination as primary key.(指定任意唯一的列或列组合作为主键) primary keyIn MongoDB, the primary key isautomatically set to the _id field.(在 MongoDB 中,主键被自动设置为 _id 字段)
aggregation (e.g. group by) MongoDB provides three ways to perform aggregation: the aggregation pipeline, the map-reduce function, and single purpose aggregation methods.(聚合操作)

  

5|0MongoDB 数据类型

  

数据类型描述
String 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。
Integer 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。
Boolean 布尔值。用于存储布尔值(真/假)。
Double 双精度浮点值。用于存储浮点值。
Min/Max keys 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。
Arrays 用于将数组或列表或多个值存储为一个键。
Timestamp 时间戳。记录文档修改或添加的具体时间。
Object 用于内嵌文档。
Null 用于创建空值。
Symbol 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。
Date 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。
Object ID 对象 ID。用于创建文档的 ID。
Binary Data 二进制数据。用于存储二进制数据。
Code 代码类型。用于在文档中存储 JavaScript 代码。
Regular expression 正则表达式类型。用于存储正则表达式。

  

6|0MongoDB 下载与安装

  

6|1下载

  

  官网:https://www.mongodb.com/

  下载地址:https://www.mongodb.com/try/download/community

  在页面中选择 MongoDB Community Server 社区版,根据自己的系统选择对应的版本,我自己使用的是 CentOS 版本。而 MongoDB 只有 RedHat 版本,下载使用即可。

  CentOS 是 Community ENTerprise Operating System 的简称,也可以叫它社区企业操作系统,是 Linux 操作系统中的一个发行版本。

  CentOS 并不是全新的 Linux 发行版,它是 Red Hat 家族发行的企业版的产品 Red Hat Enterprise Linux(以下称之为 RHEL)的克隆版本。RHEL 是很多企业采用的 Linux 发行版本,需要向 Red Hat 付费才可以使用,并能得到付费对应的服务,技术支持和版本升级。CentOS 可以像 RHEL 一样的构筑 Linux 系统环境,但不需要向 Red Hat 支付任何的产品和服务费用,同时也得不到任何有偿技术支持和升级服务。

  

  还可以通过:https://docs.mongodb.com/manual/installation/ 确认该版本软件是否支持你的操作系统。

  

6|2安装

  

  将资源上传至服务器 /usr/local/src,解压至 /usr/local 并重命名为 mongodb

# 创建 mongodb 目录 mkdir -p /usr/local/mongodb # 解压 mongodb 至指定目录 tar -zxvf /usr/local/src/mongodb-linux-x86_64-rhel70-4.4.1.tgz -C /usr/local/ # 重命名解压目录为 mongodb mv /usr/local/mongodb-linux-x86_64-rhel70-4.4.1/ /usr/local/mongodb

  

6|3创建数据/日志目录

  

  创建用于存放数据和日志的文件夹,并修改其权限增加读写权限。

# 创建存放数据的目录 mkdir -p /usr/local/mongodb/data/db # 创建存放日志的目录 mkdir -p /usr/local/mongodb/logs # 创建日志记录文件 touch /usr/local/mongodb/logs/mongodb.log

  

7|0启动 MongoDB

  

7|1前台启动

  

  MongoDB 的默认启动方式为前台启动。所谓的前台启动就是 MongoDB 启动进程后会占用当前的终端窗口。

# 切换至指定目录 cd /usr/local/mongodb/ # 前台启动 bin/mongod --dbpath /usr/local/mongodb/data/db/ --logpath /usr/local/mongodb/logs/mongodb.log --logappend --port 27017 --bind_ip 0.0.0.0
  • --dbpath:指定数据文件存放目录
  • --logpath:指定日志文件,注意是指定文件不是目录
  • --logappend:使用追加的方式记录日志
  • --port:指定端口,默认为 27017
  • --bind_ip:绑定服务 IP,若绑定 127.0.0.1,则只能本机访问,默认为本机地址

  

7|2后台启动

  

  所谓的后台启动就是以守护进程的方式启动 MongoDB。命令中添加 --fork 即可。

# 后台启动 bin/mongod --dbpath /usr/local/mongodb/data/db/ --logpath /usr/local/mongodb/logs/mongodb.log --logappend --port 27017 --bind_ip 0.0.0.0 --fork

  通过命令启动的方式并不适合管理,毕竟每次输入命令都需要考虑各参数的配置。我们可以通过配置文件来配置启动参数,然后通过指定配置文件的方式启动服务,这样在管理 MongoDB 上就比较方便了。

  

配置文件

  

  在 bin 目录下增加一个 mongodb.conf 配置文件。

# 数据文件存放目录 dbpath = /usr/local/mongodb/data/db # 日志文件存放目录 logpath = /usr/local/mongodb/logs/mongodb.log # 以追加的方式记录日志 logappend = true # 端口默认为 27017 port = 27017 # 对访问 IP 地址不做限制,默认为本机地址 bind_ip = 0.0.0.0 # 以守护进程的方式启用,即在后台运行 fork = true

  

启动

  

# 切换至指定目录 cd /usr/local/mongodb/ # 指定配置文件的方式启动服务 bin/mongod -f bin/mongodb.conf

  

8|0客户端访问

  

  可以通过 bin 目录中的 mongo 来访问 MongoDB 服务器。

  命令为:bin/mongo --host 连接的主机地址(默认127.0.0.1) --port 端口(默认27017)

[root@localhost mongodb]# bin/mongo MongoDB shell version v4.4.1 connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb Implicit session: session { "id" : UUID("2bf54fad-83bc-444c-8bee-166a224445b8") } MongoDB server version: 4.4.1 --- The server generated these startup warnings when booting: 2020-10-21T10:47:44.855+08:00: ***** SERVER RESTARTED ***** 2020-10-21T10:47:47.024+08:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted 2020-10-21T10:47:47.024+08:00: You are running this process as the root user, which is not recommended 2020-10-21T10:47:47.024+08:00: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never' 2020-10-21T10:47:47.024+08:00: /sys/kernel/mm/transparent_hugepage/defrag is 'always'. We suggest setting it to 'never' 2020-10-21T10:47:47.024+08:00: Soft rlimits too low 2020-10-21T10:47:47.024+08:00: currentValue: 1024 2020-10-21T10:47:47.024+08:00: recommendedMinimum: 64000 --- --- Enable MongoDB's free cloud-based monitoring service, which will then receive and display metrics about your deployment (disk utilization, CPU, operation statistics, etc). The monitoring data will be available on a MongoDB website with a unique URL accessible to you and anyone you share the URL with. MongoDB may use this information to make product improvements and to suggest MongoDB products and deployment options to you. To enable free monitoring, run the following command: db.enableFreeMonitoring() To permanently disable this reminder, run the following command: db.disableFreeMonitoring() --- >

  

  help 帮助命令。

> help db.help() help on db methods db.mycoll.help() help on collection methods sh.help() sharding helpers rs.help() replica set helpers help admin administrative help help connect connecting to a db help help keys key shortcuts help misc misc things to know help mr mapreduce show dbs show database names show collections show collections in current database show users show users in current database show profile show most recent system.profile entries with time >= 1ms show logs show the accessible logger names show log [name] prints out the last segment of log in memory, 'global' is default use <db_name> set current database db.mycoll.find() list objects in collection mycoll db.mycoll.find( { a : 1 } ) list objects in mycoll where a == 1 it result of the last line evaluated; use to further iterate DBQuery.shellBatchSize = x set default number of items to display on shell exit quit the mongo shell

  

  db.version() 查看版本信息。

> db.version() 4.4.1

  

  show dbs 查看所有数据库。

> show dbs admin 0.000GB config 0.000GB local 0.000GB

  这里先简单通过客户端进行访问测试,后面会详细罗列客户端操作 MongoDB 数据库、集合、文档、索引、内置函数等相关的操作。

  

9|0关闭 MongoDB

  

9|1前台启动关闭

  

  使用 Ctrl + c 即可关闭。

  

9|2后台启动关闭

  

  使用 --shutdown 参数即可关闭。

# 命令启动方式的关闭 bin/mongod --dbpath /usr/local/mongodb/data/db/ --logpath /usr/local/mongodb/logs/mongodb.log --logappend --port 27017 --bind_ip 0.0.0.0 --fork --shutdown # 配置文件启动方式的关闭 bin/mongod -f bin/mongodb.conf --shutdown

  

9|3kill 命令关闭

  

  通过 kill -9 的方式强制关闭进程,一般这种方式都不怎么推荐使用。

# 查看 mongodb 运行的进程信息 ps -ef | grep mongodb # kill -9 强制关闭 kill -9 pid

  

9|4MongoDB 函数关闭

  

  连接到 MongoDB 服务后,切换到 admin 数据库,并使用相关函数关闭服务。

# 连接 mongodb bin/mongo # 切换 admin 数据库 use admin # 执行以下函数(2选1)即可关闭服务 db.shutdownServer() db.runCommand(“shutdown”)

  

10|0环境变量

  

  每次操作 MongoDB 都需要进入具体的目录才行,比如启动服务,客户端进行连接等,可不可以在任意目录都能进行操作。答案当然是可以的,只需要将 MongoDB 相关目录添加至系统环境变量即可。

  先通过 vim /etc/profile 编辑系统环境变量文件,添加以下内容。

# 添加环境变量 export MONGODB_HOME=/usr/local/mongodb export PATH=$PATH:$MONGODB_HOME/bin

  然后通过 source /etc/profile 重新加载系统环境变量。这样在系统任意目录下都可以直接操作 MongoDB 了。

 

MongoDB 副本集 Replica Sets 搭建

MongoDB 副本集 Replica Sets 搭建

一 .三种角色 说明

1. 主要成员(Primary):主要接收所有写操作。就是主节点。

2. 副本成员(Replicate):从主节点通过复制操作以维护相同的数据集,即备份数据,不可写操作,但可以读操作(但需要配置)。是默认的一种从节点类型。

3.  仲裁者(Arbiter):不保留任何数据的副本,只具有投票选举作用。当然也可以将仲裁服务器维护为副本集的一部分,即副本成员同时也可以是仲裁者。也是一种从节点类型。

关于仲裁者的额外说明:

您可以将额外的mongod实例添加到副本集作为仲裁者。 仲裁者不维护数据集。 仲裁者的目的是通过响应其他副本集成员的心跳和选举请求来维护副本集中的仲裁。 因为它们不存储数据集,所以仲裁器可以是提供副本集仲裁功能的好方法,其资源成本比具有数据集的全功能副本集成员更便宜。

如果您的副本集具有偶数个成员,请添加仲裁者以获得主要选举中的 “ 大多数 ” 投票。 仲裁者不需要专用 硬件。

 

仲裁者将永远是仲裁者,而主要人员可能会退出并成为次要人员,而次要人员可能成为选举期间的主要人员。

如果你的副本 + 主节点的个数是偶数,建议加一个仲裁者,形成奇数,容易满足大多数的投票。
 
如果你的副本 + 主节点的个数是奇数,可以不加仲裁者

二. 副本集架构目标

一主一副本 一仲裁

1. 创建三个目录 隔离三个配置、数据、日志

myrs_27017  myrs_27018 myrs_27019

[root@VM_0_7_centos mongo]# pwd
/usr/local/mongo
[root@VM_0_7_centos mongo]# ll
total 32
drwxr-xr-x 4 root root 4096 Oct  9 21:20 data
drwxr-xr-x 2 root root 4096 Oct  6 20:30 data28128
drwxr-xr-x 2 root root 4096 Oct  6 20:30 logs
-rw-r--r-- 1 root root  172 Oct  6 20:32 mongo28128.conf
-rw-r--r-- 1 root root  162 Sep 28 22:28 mongo.conf
drwxr-xr-x 4 root root 4096 Oct  9 21:44 myrs_27017
drwxr-xr-x 4 root root 4096 Oct  9 22:05 myrs_27018
drwxr-xr-x 4 root root 4096 Oct  9 21:58 myrs_27019

2. 在每个目录中创建 以下文件及目录

mongod.conf            配置文件

/data/db                    数据目录

/log/                         日志目录

/log/mongod.log      日志文件

3. 配置文件内容

以27017 为例,修改 27018、27019


bind_ip=0.0.0.0
#对应端口
port=27017
#数据目录
dbpath=/usr/local/mongo/myrs_27017/data/db
#日志文件
logpath=/usr/local/mongo/myrs_27017/log/mongod.log
logappend=true
journal=true
maxConns=2000
fork=true
#副本集名称
replSet=myrs

4. 启动三个Mongo服务

[root@VM_0_7_centos myrs_27017]# mongod -f /usr/local/mongo/myrs_27017/mongo.conf 
about to fork child process, waiting until server is ready for connections.
forked process: 25929
child process started successfully, parent exiting
[root@VM_0_7_centos myrs_27017]# mongod -f /usr/local/mongo/myrs_27018/mongo.conf 
about to fork child process, waiting until server is ready for connections.
forked process: 26061
child process started successfully, parent exiting
[root@VM_0_7_centos myrs_27017]# mongod -f /usr/local/mongo/myrs_27019/mongo.conf 
about to fork child process, waiting until server is ready for connections.
forked process: 26159
child process started successfully, parent exiting

5. 登录主机
 

mongo --host 172.21.0.7:27017

6. 使用默认配置初始化副本集

示例:

提示:
1 ) “ok” 的值为 1 ,说明创建成功。
2 )命令行提示符发生变化,变成了一个从节点角色,此时默认不能读写。稍等片刻,回车,变成主节 点。
 

7. 查看副本集的配置 rs.config()

rs.conf(configuration)   别名 rs.config()
confifiguration :可选,如果没有配置,则使用默认主节点配置。 .
 
myrs:PRIMARY> rs.config()
{
	"_id" : "myrs",
	"version" : 5,
	"protocolVersion" : NumberLong(1),
	"writeConcernMajorityJournalDefault" : true,
	"members" : [
		{
			"_id" : 0,
			"host" : "VM_0_7_centos:27017",
			"arbiterOnly" : false,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 1,
			"tags" : {
				
			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		}
	],
	"settings" : {
		"chainingAllowed" : true,
		"heartbeatIntervalMillis" : 2000,
		"heartbeatTimeoutSecs" : 10,
		"electionTimeoutMillis" : 10000,
		"catchUpTimeoutMillis" : -1,
		"catchUpTakeoverDelayMillis" : 30000,
		"getLastErrorModes" : {
			
		},
		"getLastErrorDefaults" : {
			"w" : 1,
			"wtimeout" : 0
		},
		"replicaSetId" : ObjectId("5f806d1896301db3f14d0412")
	}
}

 

本质是查询system.replset表中的数据
myrs:PRIMARY> use local
switched to db local
myrs:PRIMARY> show collections
oplog.rs
replset.election
replset.minvalid
replset.oplogTruncateAfterPoint
startup_log
system.replset
system.rollback.id
myrs:PRIMARY> db.system.replset.find()
{ "_id" : "myrs", "version" : 5, "protocolVersion" : NumberLong(1), "writeConcernMajorityJournalDefault" : true, "members" : [ { "_id" : 0, "host" : "VM_0_7_centos:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : {  }, "slaveDelay" : NumberLong(0), "votes" : 1 } ], "settings" : { "chainingAllowed" : true, "heartbeatIntervalMillis" : 2000, "heartbeatTimeoutSecs" : 10, "electionTimeoutMillis" : 10000, "catchUpTimeoutMillis" : -1, "catchUpTakeoverDelayMillis" : 30000, "getLastErrorModes" : {  }, "getLastErrorDefaults" : { "w" : 1, "wtimeout" : 0 }, "replicaSetId" : ObjectId("5f806d1896301db3f14d0412") } }

 

 8. 查看副本集的状态 rs.status()

说明 :

    "set" : "myrs",:副本集的名称

    "myState" : 1,说明状态正常

    "members" : [  副本集成员数组。

myrs:PRIMARY> rs.status()
{
	"set" : "myrs",
	"date" : ISODate("2020-10-10T08:01:46.987Z"),
	"myState" : 1,
	"term" : NumberLong(2),
	"syncingTo" : "",
	"syncSourceHost" : "",
	"syncSourceId" : -1,
	"heartbeatIntervalMillis" : NumberLong(2000),
	"majorityVoteCount" : 1,
	"writeMajorityCount" : 1,
	"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1602316900, 1),
			"t" : NumberLong(2)
		},
		"lastCommittedWallTime" : ISODate("2020-10-10T08:01:40.808Z"),
		"readConcernMajorityOpTime" : {
			"ts" : Timestamp(1602316900, 1),
			"t" : NumberLong(2)
		},
		"readConcernMajorityWallTime" : ISODate("2020-10-10T08:01:40.808Z"),
		"appliedOpTime" : {
			"ts" : Timestamp(1602316900, 1),
			"t" : NumberLong(2)
		},
		"durableOpTime" : {
			"ts" : Timestamp(1602316900, 1),
			"t" : NumberLong(2)
		},
		"lastAppliedWallTime" : ISODate("2020-10-10T08:01:40.808Z"),
		"lastDurableWallTime" : ISODate("2020-10-10T08:01:40.808Z")
	},
	"lastStableRecoveryTimestamp" : Timestamp(1602316880, 1),
	"lastStableCheckpointTimestamp" : Timestamp(1602316880, 1),
	"electionCandidateMetrics" : {
		"lastElectionReason" : "electionTimeout",
		"lastElectionDate" : ISODate("2020-10-10T07:41:00.774Z"),
		"electionTerm" : NumberLong(2),
		"lastCommittedOpTimeAtElection" : {
			"ts" : Timestamp(0, 0),
			"t" : NumberLong(-1)
		},
		"lastSeenOpTimeAtElection" : {
			"ts" : Timestamp(1602253127, 1),
			"t" : NumberLong(1)
		},
		"numVotesNeeded" : 2,
		"priorityAtElection" : 1,
		"electionTimeoutMillis" : NumberLong(10000),
		"numCatchUpOps" : NumberLong(0),
		"newTermStartDate" : ISODate("2020-10-10T07:41:00.783Z"),
		"wMajorityWriteAvailabilityDate" : ISODate("2020-10-10T07:41:01.749Z")
	},
	"members" : [
		{
			"_id" : 0,
			"name" : "VM_0_7_centos:27017",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 1281,
			"optime" : {
				"ts" : Timestamp(1602316900, 1),
				"t" : NumberLong(2)
			},
			"optimeDate" : ISODate("2020-10-10T08:01:40Z"),
			"syncingTo" : "",
			"syncSourceHost" : "",
			"syncSourceId" : -1,
			"infoMessage" : "",
			"electionTime" : Timestamp(1602315660, 1),
			"electionDate" : ISODate("2020-10-10T07:41:00Z"),
			"configVersion" : 5,
			"self" : true,
			"lastHeartbeatMessage" : ""
		}
	],
	"ok" : 1,
	"$clusterTime" : {
		"clusterTime" : Timestamp(1602316900, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	},
	"operationTime" : Timestamp(1602316900, 1)
}
myrs:PRIMARY> 

9. 添加 副本从节点

rs.add(host, arbiterOnly)
 
主机成员的配置文档:
{  
    _id: <int>,
 host: <string>, // required
 arbiterOnly: <boolean>,
 buildIndexes: <boolean>,
 hidden: <boolean>, 
 priority: <number>, 
 tags: <document>, 
 slaveDelay: <int>, 
 votes: <number>
}
将27018的副本节点添加到副本集中:
myrs:PRIMARY> rs.add("172.21.0.7:27018")
{
	"ok" : 1,
	"$clusterTime" : {
		"clusterTime" : Timestamp(1602317234, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	},
	"operationTime" : Timestamp(1602317234, 1)
}

OK:1 说明添加成功

此时查看副本集的状态: 

members中增加了27018  ,其角色是"stateStr" : "SECONDARY",

myrs:PRIMARY> rs.status()
{
	"set" : "myrs",
	"date" : ISODate("2020-10-10T08:08:05.179Z"),
	"myState" : 1,
	"term" : NumberLong(2),
	"syncingTo" : "",
	"syncSourceHost" : "",
	"syncSourceId" : -1,
	"heartbeatIntervalMillis" : NumberLong(2000),
	"majorityVoteCount" : 2,
	"writeMajorityCount" : 2,
	"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1602317280, 1),
			"t" : NumberLong(2)
		},
		"lastCommittedWallTime" : ISODate("2020-10-10T08:08:00.815Z"),
		"readConcernMajorityOpTime" : {
			"ts" : Timestamp(1602317280, 1),
			"t" : NumberLong(2)
		},
		"readConcernMajorityWallTime" : ISODate("2020-10-10T08:08:00.815Z"),
		"appliedOpTime" : {
			"ts" : Timestamp(1602317280, 1),
			"t" : NumberLong(2)
		},
		"durableOpTime" : {
			"ts" : Timestamp(1602317280, 1),
			"t" : NumberLong(2)
		},
		"lastAppliedWallTime" : ISODate("2020-10-10T08:08:00.815Z"),
		"lastDurableWallTime" : ISODate("2020-10-10T08:08:00.815Z")
	},
	"lastStableRecoveryTimestamp" : Timestamp(1602317234, 1),
	"lastStableCheckpointTimestamp" : Timestamp(1602317234, 1),
	"electionCandidateMetrics" : {
		"lastElectionReason" : "electionTimeout",
		"lastElectionDate" : ISODate("2020-10-10T07:41:00.774Z"),
		"electionTerm" : NumberLong(2),
		"lastCommittedOpTimeAtElection" : {
			"ts" : Timestamp(0, 0),
			"t" : NumberLong(-1)
		},
		"lastSeenOpTimeAtElection" : {
			"ts" : Timestamp(1602253127, 1),
			"t" : NumberLong(1)
		},
		"numVotesNeeded" : 2,
		"priorityAtElection" : 1,
		"electionTimeoutMillis" : NumberLong(10000),
		"numCatchUpOps" : NumberLong(0),
		"newTermStartDate" : ISODate("2020-10-10T07:41:00.783Z"),
		"wMajorityWriteAvailabilityDate" : ISODate("2020-10-10T07:41:01.749Z")
	},
	"members" : [
		{
			"_id" : 0,
			"name" : "VM_0_7_centos:27017",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 1660,
			"optime" : {
				"ts" : Timestamp(1602317280, 1),
				"t" : NumberLong(2)
			},
			"optimeDate" : ISODate("2020-10-10T08:08:00Z"),
			"syncingTo" : "",
			"syncSourceHost" : "",
			"syncSourceId" : -1,
			"infoMessage" : "",
			"electionTime" : Timestamp(1602315660, 1),
			"electionDate" : ISODate("2020-10-10T07:41:00Z"),
			"configVersion" : 6,
			"self" : true,
			"lastHeartbeatMessage" : ""
		},
		{
			"_id" : 1,
			"name" : "172.21.0.7:27018",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 48,
			"optime" : {
				"ts" : Timestamp(1602317280, 1),
				"t" : NumberLong(2)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1602317280, 1),
				"t" : NumberLong(2)
			},
			"optimeDate" : ISODate("2020-10-10T08:08:00Z"),
			"optimeDurableDate" : ISODate("2020-10-10T08:08:00Z"),
			"lastHeartbeat" : ISODate("2020-10-10T08:08:04.632Z"),
			"lastHeartbeatRecv" : ISODate("2020-10-10T08:08:03.633Z"),
			"pingMs" : NumberLong(0),
			"lastHeartbeatMessage" : "",
			"syncingTo" : "VM_0_7_centos:27017",
			"syncSourceHost" : "VM_0_7_centos:27017",
			"syncSourceId" : 0,
			"infoMessage" : "",
			"configVersion" : 6
		}
	],
	"ok" : 1,
	"$clusterTime" : {
		"clusterTime" : Timestamp(1602317280, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	},
	"operationTime" : Timestamp(1602317280, 1)
}

10.添加仲裁从节点

添加仲裁节点到副本集

rs.addArb(host)

将27019以仲裁节点添加到副本集中

myrs:PRIMARY> rs.addArb("172.21.0.7:27019")
{
	"ok" : 1,
	"$clusterTime" : {
		"clusterTime" : Timestamp(1602317560, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	},
	"operationTime" : Timestamp(1602317560, 1)
}

此时查看副本集状态

myrs:PRIMARY> rs.status()
{
	"set" : "myrs",
	"date" : ISODate("2020-10-10T08:13:09.745Z"),
	"myState" : 1,
	"term" : NumberLong(2),
	"syncingTo" : "",
	"syncSourceHost" : "",
	"syncSourceId" : -1,
	"heartbeatIntervalMillis" : NumberLong(2000),
	"majorityVoteCount" : 2,
	"writeMajorityCount" : 2,
	"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1602317580, 1),
			"t" : NumberLong(2)
		},
		"lastCommittedWallTime" : ISODate("2020-10-10T08:13:00.821Z"),
		"readConcernMajorityOpTime" : {
			"ts" : Timestamp(1602317580, 1),
			"t" : NumberLong(2)
		},
		"readConcernMajorityWallTime" : ISODate("2020-10-10T08:13:00.821Z"),
		"appliedOpTime" : {
			"ts" : Timestamp(1602317580, 1),
			"t" : NumberLong(2)
		},
		"durableOpTime" : {
			"ts" : Timestamp(1602317580, 1),
			"t" : NumberLong(2)
		},
		"lastAppliedWallTime" : ISODate("2020-10-10T08:13:00.821Z"),
		"lastDurableWallTime" : ISODate("2020-10-10T08:13:00.821Z")
	},
	"lastStableRecoveryTimestamp" : Timestamp(1602317540, 1),
	"lastStableCheckpointTimestamp" : Timestamp(1602317540, 1),
	"electionCandidateMetrics" : {
		"lastElectionReason" : "electionTimeout",
		"lastElectionDate" : ISODate("2020-10-10T07:41:00.774Z"),
		"electionTerm" : NumberLong(2),
		"lastCommittedOpTimeAtElection" : {
			"ts" : Timestamp(0, 0),
			"t" : NumberLong(-1)
		},
		"lastSeenOpTimeAtElection" : {
			"ts" : Timestamp(1602253127, 1),
			"t" : NumberLong(1)
		},
		"numVotesNeeded" : 2,
		"priorityAtElection" : 1,
		"electionTimeoutMillis" : NumberLong(10000),
		"numCatchUpOps" : NumberLong(0),
		"newTermStartDate" : ISODate("2020-10-10T07:41:00.783Z"),
		"wMajorityWriteAvailabilityDate" : ISODate("2020-10-10T07:41:01.749Z")
	},
	"members" : [
		{
			"_id" : 0,
			"name" : "VM_0_7_centos:27017",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 1964,
			"optime" : {
				"ts" : Timestamp(1602317580, 1),
				"t" : NumberLong(2)
			},
			"optimeDate" : ISODate("2020-10-10T08:13:00Z"),
			"syncingTo" : "",
			"syncSourceHost" : "",
			"syncSourceId" : -1,
			"infoMessage" : "",
			"electionTime" : Timestamp(1602315660, 1),
			"electionDate" : ISODate("2020-10-10T07:41:00Z"),
			"configVersion" : 7,
			"self" : true,
			"lastHeartbeatMessage" : ""
		},
		{
			"_id" : 1,
			"name" : "172.21.0.7:27018",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 353,
			"optime" : {
				"ts" : Timestamp(1602317580, 1),
				"t" : NumberLong(2)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1602317580, 1),
				"t" : NumberLong(2)
			},
			"optimeDate" : ISODate("2020-10-10T08:13:00Z"),
			"optimeDurableDate" : ISODate("2020-10-10T08:13:00Z"),
			"lastHeartbeat" : ISODate("2020-10-10T08:13:08.288Z"),
			"lastHeartbeatRecv" : ISODate("2020-10-10T08:13:08.292Z"),
			"pingMs" : NumberLong(0),
			"lastHeartbeatMessage" : "",
			"syncingTo" : "VM_0_7_centos:27017",
			"syncSourceHost" : "VM_0_7_centos:27017",
			"syncSourceId" : 0,
			"infoMessage" : "",
			"configVersion" : 7
		},
		{
			"_id" : 2,
			"name" : "172.21.0.7:27019",
			"health" : 1,
			"state" : 7,
			"stateStr" : "ARBITER",
			"uptime" : 27,
			"lastHeartbeat" : ISODate("2020-10-10T08:13:08.290Z"),
			"lastHeartbeatRecv" : ISODate("2020-10-10T08:13:08.293Z"),
			"pingMs" : NumberLong(0),
			"lastHeartbeatMessage" : "",
			"syncingTo" : "",
			"syncSourceHost" : "",
			"syncSourceId" : -1,
			"infoMessage" : "",
			"configVersion" : 7
		}
	],
	"ok" : 1,
	"$clusterTime" : {
		"clusterTime" : Timestamp(1602317580, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	},
	"operationTime" : Timestamp(1602317580, 1)
}
myrs:PRIMARY> 

说明

            "name" : "172.21.0.7:27019", 名称
            "health" : 1,         健康
            "state" : 7,
            "stateStr" : "ARBITER",  状态是仲裁者

11 . 副本集的数据读写操作

11.1 主节点写入数据

myrs:PRIMARY> show dbs
admin      0.000GB
articledb  0.000GB
config     0.000GB
local      0.000GB
myrs:PRIMARY> use articledb
switched to db articledb
myrs:PRIMARY> db.content.insert({title:'AAA',content:'BBB'})
WriteResult({ "nInserted" : 1 })
myrs:PRIMARY> db.content.find()
{ "_id" : ObjectId("5f817a179595bc6e7dfc444c"), "title" : "AAA", "content" : "BBB" }
myrs:PRIMARY> 

11.2 副节点尝试读数据

myrs:SECONDARY> show dbs
2020-10-10T17:10:01.034+0800 E  QUERY    [js] uncaught exception: Error: listDatabases failed:{
	"operationTime" : Timestamp(1602321000, 1),
	"ok" : 0,
	"errmsg" : "not master and slaveOk=false",
	"code" : 13435,
	"codeName" : "NotMasterNoSlaveOk",
	"$clusterTime" : {
		"clusterTime" : Timestamp(1602321000, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs/<@src/mongo/shell/mongo.js:135:19
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:87:12
shellHelper.show@src/mongo/shell/utils.js:906:13
shellHelper@src/mongo/shell/utils.js:790:15
@(shellhelp2):1:1
myrs:SECONDARY> 

发现,不能读取集合的数据。当前从节点只是一个备份,不是奴隶节点,无法读取数据,写当然更不行。因为默认情况下,从节点是没有读写权限的,可以增加读的权限,但需要进行设置

11.3 副节点设置 与 取消 读操作权限

rs.slaveOk()  
或 
rs.slaveOk(true)

设置为奴隶节点,允许在从成员上运行读的操作

myrs:SECONDARY> rs.slaveOk(true)
myrs:SECONDARY> show dbs
admin      0.000GB
articledb  0.000GB
config     0.000GB
local      0.000GB
myrs:SECONDARY> use articledb
switched to db articledb
myrs:SECONDARY> db.content.find()
{ "_id" : ObjectId("5f817a179595bc6e7dfc444c"), "title" : "AAA", "content" : "BBB" }
myrs:SECONDARY> 

现在可实现了读写分离,让主插入数据,让从来读取数据。
如果要取消作为奴隶节点的读权限:

myrs:SECONDARY> rs.slaveOk(false)
myrs:SECONDARY> show dbs
2020-10-10T17:14:34.613+0800 E  QUERY    [js] uncaught exception: Error: listDatabases failed:{
	"operationTime" : Timestamp(1602321270, 1),
	"ok" : 0,
	"errmsg" : "not master and slaveOk=false",
	"code" : 13435,
	"codeName" : "NotMasterNoSlaveOk",
	"$clusterTime" : {
		"clusterTime" : Timestamp(1602321270, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs/<@src/mongo/shell/mongo.js:135:19
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:87:12
shellHelper.show@src/mongo/shell/utils.js:906:13
shellHelper@src/mongo/shell/utils.js:790:15
@(shellhelp2):1:1
myrs:SECONDARY> rs.slaveOk(true)

冲裁者 节点,不存放任何业务数据的,可以登录查看

先配置为奴隶节点赋予读权限,再查看数据。

myrs:ARBITER> rs.slaveOk()
myrs:ARBITER> show dbs
local  0.000GB
myrs:ARBITER> use local
switched to db local
myrs:ARBITER> show collections
replset.election
replset.minvalid
replset.oplogTruncateAfterPoint
startup_log
system.replset
system.rollback.id
myrs:ARBITER> 

12 . 主节点的选举原则


MongoDB在副本集中,会自动进行主节点的选举,主节点选举的触发条件:
1) 主节点故障
2) 主节点网络不可达(默认心跳信息为10秒)
3) 人工干预(rs.stepDown(600))

一旦触发选举,就要根据一定规则来选主节点。
选举规则是根据票数来决定谁获胜:

  • 票数最高,且获得了“大多数”成员的投票支持的节点获胜。

    “大多数”的定义为:假设复制集内投票成员数量为N,则大多数为 N/2 + 1。例如:3个投票成员,则大多数的值是2。当复制集内存活成员数量不足大多数时,整个复制集将无法选举出Primary,
    复制集将无法提供写服务,处于只读状态。

  • 若票数相同,且都获得了“大多数”成员的投票支持的,数据新的节点获胜。

    数据的新旧是通过操作日志oplog来对比的。

在获得票数的时候,优先级(priority)参数影响重大。可以通过设置优先级(priority)来设置额外票数。优先级即权重,取值为0-1000,相当于可额外增加 0-1000的票数,优先级的值越大,就越可能获得多数成员的投票(votes)数。指定较高的值可使成员 更有资格成为主要成员,更低的值可使成员更不符合条件。


默认情况下,优先级的值是1

通过rs.conf()命令查看每个members中的优先级字段 prioriry 

myrs:ARBITER> rs.conf()
{
	"_id" : "myrs",
	"version" : 7,
	"protocolVersion" : NumberLong(1),
	"writeConcernMajorityJournalDefault" : true,
	"members" : [
		{
			"_id" : 0,
			"host" : "VM_0_7_centos:27017",
			"arbiterOnly" : false,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 1,
			"tags" : {
				
			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		},
		{
			"_id" : 1,
			"host" : "172.21.0.7:27018",
			"arbiterOnly" : false,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 1,
			"tags" : {
				
			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		},
		{
			"_id" : 2,
			"host" : "172.21.0.7:27019",
			"arbiterOnly" : true,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 0,
			"tags" : {
				
			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		}
	],
	"settings" : {
		"chainingAllowed" : true,
		"heartbeatIntervalMillis" : 2000,
		"heartbeatTimeoutSecs" : 10,
		"electionTimeoutMillis" : 10000,
		"catchUpTimeoutMillis" : -1,
		"catchUpTakeoverDelayMillis" : 30000,
		"getLastErrorModes" : {
			
		},
		"getLastErrorDefaults" : {
			"w" : 1,
			"wtimeout" : 0
		},
		"replicaSetId" : ObjectId("5f806d1896301db3f14d0412")
	}
}


可以看出,主节点和副本节点的优先级各为1,即,默认可以认为都已经有了一票。但选举节点,优先级是0,(要注意是,官方说了,选举节点的优先级必须是0,不能是别的值。即不具备选举权,但具有投票权)

修改优先级方法:

1)先将配置导入cfg变量

myrs:SECONDARY> cfg=rs.conf()


2)然后修改值(ID号默认从0开始):

myrs:SECONDARY> cfg.members[1].priority=2
2


3)重新加载配置  需要在主机操作。
myrs:SECONDARY> rs.reconfig(cfg) 
稍等片刻会重新开始选举。

13. 故障测试

13.1 副本节点故障测试

关闭27018副本节点:

使用127.0.0.1:27018登录, 否则提示

"errmsg" : "shutdown must run from localhost when running db without auth",

 

[root@VM_0_7_centos ~]# mongo --host 127.0.0.1:27018
....

myrs:SECONDARY> use admin 
switched to db admin
myrs:SECONDARY> db.shutdownServer()


发现,主节点和仲裁节点对27018的心跳失败。因为主节点还在,因此,没有触发投票选举。
如果此时,在主节点写入数据。

myrs:PRIMARY> db.content.insert({title:'CCC',content:'DDD'})
WriteResult({ "nInserted" : 1 })

重启 副节点,配置读权限,再进行读数据

myrs:SECONDARY> rs.slaveOk()
myrs:SECONDARY> show dbs
admin      0.000GB
articledb  0.000GB
config     0.000GB
local      0.000GB
myrs:SECONDARY> use articledb
switched to db articledb
myrs:SECONDARY> db.content.find()
{ "_id" : ObjectId("5f817a179595bc6e7dfc444c"), "title" : "AAA", "content" : "BBB" }
{ "_id" : ObjectId("5f8180369595bc6e7dfc444d"), "title" : "CCC", "content" : "DDD" }
myrs:SECONDARY> 

数据已经同步过来了

13.2 主节点故障测试

关闭27017节点
发现,从节点和仲裁节点对27017的心跳失败,当失败超过10秒,此时因为没有主节点了,会自动发起
投票。
而副本节点只有27018,因此,候选人只有一个就是27018,开始投票。
27019向27018投了一票,27018本身自带一票,因此共两票,超过了“大多数”
27019是仲裁节点,没有选举权,27018不向其投票,其票数是0.
最终结果,27018成为主节点。具备读写功能。
在27018写入数据查看。

主节点关闭,再启动,使用27018查看状态

myrs:SECONDARY> rs.status()
{
	"set" : "myrs",
	"date" : ISODate("2020-10-10T09:40:44.700Z"),
	"myState" : 1,
	"term" : NumberLong(3),
	"syncingTo" : "",
	"syncSourceHost" : "",
	"syncSourceId" : -1,
	"heartbeatIntervalMillis" : NumberLong(2000),
	"majorityVoteCount" : 2,
	"writeMajorityCount" : 2,
	"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1602322836, 1),
			"t" : NumberLong(3)
		},
		"lastCommittedWallTime" : ISODate("2020-10-10T09:40:36.790Z"),
		"readConcernMajorityOpTime" : {
			"ts" : Timestamp(1602322836, 1),
			"t" : NumberLong(3)
		},
		"readConcernMajorityWallTime" : ISODate("2020-10-10T09:40:36.790Z"),
		"appliedOpTime" : {
			"ts" : Timestamp(1602322836, 1),
			"t" : NumberLong(3)
		},
		"durableOpTime" : {
			"ts" : Timestamp(1602322836, 1),
			"t" : NumberLong(3)
		},
		"lastAppliedWallTime" : ISODate("2020-10-10T09:40:36.790Z"),
		"lastDurableWallTime" : ISODate("2020-10-10T09:40:36.790Z")
	},
	"lastStableRecoveryTimestamp" : Timestamp(1602322780, 1),
	"lastStableCheckpointTimestamp" : Timestamp(1602322780, 1),
	"electionCandidateMetrics" : {
		"lastElectionReason" : "stepUpRequestSkipDryRun",
		"lastElectionDate" : ISODate("2020-10-10T09:39:46.784Z"),
		"electionTerm" : NumberLong(3),
		"lastCommittedOpTimeAtElection" : {
			"ts" : Timestamp(1602322780, 1),
			"t" : NumberLong(2)
		},
		"lastSeenOpTimeAtElection" : {
			"ts" : Timestamp(1602322780, 1),
			"t" : NumberLong(2)
		},
		"numVotesNeeded" : 2,
		"priorityAtElection" : 1,
		"electionTimeoutMillis" : NumberLong(10000),
		"priorPrimaryMemberId" : 0,
		"numCatchUpOps" : NumberLong(0),
		"newTermStartDate" : ISODate("2020-10-10T09:39:46.789Z"),
		"wMajorityWriteAvailabilityDate" : ISODate("2020-10-10T09:40:24.592Z")
	},
	"members" : [
		{
			"_id" : 0,
			"name" : "VM_0_7_centos:27017",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 19,
			"optime" : {
				"ts" : Timestamp(1602322836, 1),
				"t" : NumberLong(3)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1602322836, 1),
				"t" : NumberLong(3)
			},
			"optimeDate" : ISODate("2020-10-10T09:40:36Z"),
			"optimeDurableDate" : ISODate("2020-10-10T09:40:36Z"),
			"lastHeartbeat" : ISODate("2020-10-10T09:40:42.792Z"),
			"lastHeartbeatRecv" : ISODate("2020-10-10T09:40:43.086Z"),
			"pingMs" : NumberLong(0),
			"lastHeartbeatMessage" : "",
			"syncingTo" : "172.21.0.7:27018",
			"syncSourceHost" : "172.21.0.7:27018",
			"syncSourceId" : 1,
			"infoMessage" : "",
			"configVersion" : 7
		},
		{
			"_id" : 1,
			"name" : "172.21.0.7:27018",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 297,
			"optime" : {
				"ts" : Timestamp(1602322836, 1),
				"t" : NumberLong(3)
			},
			"optimeDate" : ISODate("2020-10-10T09:40:36Z"),
			"syncingTo" : "",
			"syncSourceHost" : "",
			"syncSourceId" : -1,
			"infoMessage" : "",
			"electionTime" : Timestamp(1602322786, 1),
			"electionDate" : ISODate("2020-10-10T09:39:46Z"),
			"configVersion" : 7,
			"self" : true,
			"lastHeartbeatMessage" : ""
		},
		{
			"_id" : 2,
			"name" : "172.21.0.7:27019",
			"health" : 1,
			"state" : 7,
			"stateStr" : "ARBITER",
			"uptime" : 295,
			"lastHeartbeat" : ISODate("2020-10-10T09:40:42.788Z"),
			"lastHeartbeatRecv" : ISODate("2020-10-10T09:40:44.303Z"),
			"pingMs" : NumberLong(0),
			"lastHeartbeatMessage" : "",
			"syncingTo" : "",
			"syncSourceHost" : "",
			"syncSourceId" : -1,
			"infoMessage" : "",
			"configVersion" : 7
		}
	],
	"ok" : 1,
	"$clusterTime" : {
		"clusterTime" : Timestamp(1602322836, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	},
	"operationTime" : Timestamp(1602322836, 1)
}
myrs:PRIMARY> 

27018 变为主节点,写入数据,在27017 上读取

myrs:PRIMARY> show dbs
admin      0.000GB
articledb  0.000GB
config     0.000GB
local      0.000GB
myrs:PRIMARY> use articledb
switched to db articledb
myrs:PRIMARY> show collections
comment
content
myrs:PRIMARY> db.content.insert({"k1":'v1'})
WriteResult({ "nInserted" : 1 })
myrs:PRIMARY> 
myrs:SECONDARY> rs.slaveOk()
myrs:SECONDARY> show dbs
admin      0.000GB
articledb  0.000GB
config     0.000GB
local      0.000GB
myrs:SECONDARY> use articledb
switched to db articledb
myrs:SECONDARY> db.content.find()
{ "_id" : ObjectId("5f817a179595bc6e7dfc444c"), "title" : "AAA", "content" : "BBB" }
{ "_id" : ObjectId("5f8180369595bc6e7dfc444d"), "title" : "CCC", "content" : "DDD" }
{ "_id" : ObjectId("5f818206997162c565e0d7ff"), "k1" : "v1" }
myrs:SECONDARY> 


13.3 仲裁节点和主节点故障 


先关掉仲裁节点27019,
关掉现在的主节点27018
登录27017后,发现,27017仍然是从节点,副本集中没有主节点了,导致此时,副本集是只读状态,
无法写入。
为啥不选举了?因为27017的票数,没有获得大多数,即没有大于等于2,它只有默认的一票(优先级
是1)
如果要触发选举,随便加入一个成员即可。

如果只加入27019仲裁节点成员,则主节点一定是27017,因为没得选了,仲裁节点不参与选举,
但参与投票。(不演示)
如果只加入27018节点,会发起选举。因为27017和27018都是两票,则按照谁数据新,谁当主节


13.4 仲裁节点和从节点故障  


先关掉仲裁节点27019,
关掉现在的副本节点27018
10秒后,27017主节点自动降级为副本节点。(服务降级)
副本集不可写数据了,已经故障了。

推荐阅读