MongoDB从入门到实战(十一):副本集

MongoDB 专栏收录该内容
19 篇文章 4 订阅

一:简介

MongoDB中的复制集是一组维护相同数据集的mongod服务。复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性。复制还可以实现从硬件故障和服务中断中恢复数据。是所有生产部署的基础。

​ 也可以说,复制集类似于有自动故障恢复功能的主从集群。通俗的讲就是用多台机器进行同一数据的异步同步,从而使多台机器拥有同一数据的多个副本,并且当主库关掉时在不需要用户干预的情况下自动切换其他备份服务器做主库。而且还可以利用副本服务器做只读服务器,实现读写分离,提高负载。

(1)冗余和数据可用性

复制提供冗余并提高数据可用性。 通过在不同数据库服务器上提供多个数据副本,复制可提供一定级别的容错功能,以防止丢失单个数据库服务器。

在某些情况下,复制可以提供增加的读取性能,因为客户端可以将读取操作发送到不同的服务上, 在不同数据中心维护数据副本可以增加分布式应用程序的数据位置和可用性。 您还可以为专用目的维护其他副本,例如灾难恢复,报告或备份。

(2)MongoDB中的复制

复制集是一组维护相同数据集的mongod实例。 复制集包含多个数据承载节点和可选的一个仲裁节点。 在承载数据的节点中,一个且仅一个成员被视为主节点,而其他节点被视为次要(从)节点。主节点接收所有写操作。

为什么使用复制集?

  1. 保障数据的安全性;
  2. 数据高可用性 ;
  3. 灾难恢复;
  4. 无需停机维护;
  5. 分布式读取数据等

二:复制集原理

mongodb的复制至少需要两个节点。其中一个是主节点,负责处理客户端请求,其余的都是从节点(后备节点),负责复制主节点上的数据。mongodb各个节点常见的搭配方式为:一主一从、一主多从。主节点记录在其上的所有操作oplog(oplog,操作日志的简称,是local库下一个特殊的固定集合,它保存了与数据库中数据存储相关的所有操作记录。从节点就是通过查看主节点 的oplog这个集合来进行复制的。每个节点都有oplog,记录着从主节点复制过来的信息,这样每个成员都可以作为同步源给其他节点。),从节点定期查询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。

在这里插入图片描述

说明:辅助(副本)节点复制主节点的oplog并将操作应用于其数据集,以使辅助节点的数据集反映主节点的数据集。 如果主节点挂掉,则将在从节点中选举出主节点。

三:复制集的三个角色

复制集有两种类型三种角色。

两种类型:

  • 主节点(Primary)类型:数据操作的主要连接点,可读写。
  • 次要(辅助、从)节点(Secondaries)类型:数据冗余备份节点,可以读或选举。

三种角色:

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

  • 副本成员(Replicate):负责同步主节点的数据操作日志更新本地数据库,从而保证副本节点的数据和主节点上的数据的一致性,不支持写操作;副本节点的从某种意义上来讲有点像赛跑,永远在追赶主节点的数据操作;

  • 仲裁者(Arbiter):不负责保存具体的数据,只是在副本集进行主节点选举时提供自己的一个选票而已。当然也可以将仲裁服务器维护为副本集的一部分,即副本成员同时也可以是仲裁者。也是一种从节点类型。

在这里插入图片描述

关于仲裁者的额外说明:

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

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

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

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

如果你的副本+主节点的个数是奇数,可以不加仲裁者。

四:复制集配置

一主一副本一仲裁

在这里插入图片描述

说明:

​ 本次复制集配置使用一个mongodb数据库,使用了三个节点,一个主节点(端口27000)、一个从节点(端口27001)、一个仲裁节点(端口27002)。在bin同级目录下创建一个data目录、config目录和log目录,分别放置数据库数据、数据库实例配置信息和数据库日志。下面是data和config目录的截图,下面有三个分目录,分别存放每个节点的数据。

在根目录下创建一个data目录,并在data目录下创建三个复制文件夹用于存储各自的配置文件。
在这里插入图片描述

在根目录下创建一个config目录,并在config目录下创建三个复制文件夹用于存储各自的配置文件。
在这里插入图片描述

config/rs1/mongod.cfg

dbpath=/Users/mengday/Softwares/mongodb-4.4.5/data/rs1
logpath=/Users/mengday/Softwares/mongodb-4.4.5/log/rs1.log
journal=true
port=27000
replSet=rs
logappend=true

config/rs2/mongod.cfg

dbpath=/Users/mengday/Softwares/mongodb-4.4.5/data/rs2
logpath=/Users/mengday/Softwares/mongodb-4.4.5/log/rs2.log
journal=true
port=27002
replSet=rs
logappend=true

config/rs3/mongod.cfg

dbpath=/Users/mengday/Softwares/mongodb-4.4.5/data/rs3
logpath=/Users/mengday/Softwares/mongodb-4.4.5/log/rs3.log
journal=true
port=27002
replSet=rs
logappend=true

注意:以上三个节点的复制集名字统一为rs。

//主节点实例服务启动命令
./bin/mongod --config ./config/rs1/mongod.cfg
//从节点实例服务启动命令
./bin/mongod --config ./config/rs2/mongod.cfg
//仲裁节点实例服务启动命令
./bin/mongod --config ./config/rs3/mongod.cfg

在这里插入图片描述

// 连接主节点
mongo 127.0.0.1:27000/admin

// 初始化, 注意此时不要初始化从节点和仲裁节点,不然后面主节点添加从节点的时候会报错。
> rs.initiate()
{
	"info2" : "no configuration specified. Using a default configuration for the set",
	"me" : "localhost:27000",
	"ok" : 1
}


// 初始化配置
rs:SECONDARY> rs.conf()
{
	"_id" : "rs",
	"version" : 1,
	"term" : 1,
	"protocolVersion" : NumberLong(1),
	"writeConcernMajorityJournalDefault" : true,
	"members" : [
		{
			"_id" : 0,
			"host" : "localhost:27000",
			"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("6076544a7353de75a9e532de")
	}
}

// 向主节点添加从节点
rs:PRIMARY> rs.add("localhost:27001")
{
	"ok" : 1,
	"$clusterTime" : {
		"clusterTime" : Timestamp(1618367820, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	},
	"operationTime" : Timestamp(1618367820, 1)
}


// 向主节点添加仲裁节点
rs:PRIMARY> rs.addArb("localhost:27002")
{
	"ok" : 1,
	"$clusterTime" : {
		"clusterTime" : Timestamp(1618367859, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	},
	"operationTime" : Timestamp(1618367859, 1)
}


// 查看主节点状态
rs:PRIMARY> rs.status()
{
	"set" : "rs",
	"date" : ISODate("2021-04-14T02:38:11.408Z"),
	"myState" : 1,
	"term" : NumberLong(1),
	"syncSourceHost" : "",
	"syncSourceId" : -1,
	"heartbeatIntervalMillis" : NumberLong(2000),
	"majorityVoteCount" : 2,
	"writeMajorityCount" : 2,
	"votingMembersCount" : 3,
	"writableVotingMembersCount" : 2,
	"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1618367883, 1),
			"t" : NumberLong(1)
		},
		"lastCommittedWallTime" : ISODate("2021-04-14T02:38:03.166Z"),
		"readConcernMajorityOpTime" : {
			"ts" : Timestamp(1618367883, 1),
			"t" : NumberLong(1)
		},
		"readConcernMajorityWallTime" : ISODate("2021-04-14T02:38:03.166Z"),
		"appliedOpTime" : {
			"ts" : Timestamp(1618367883, 1),
			"t" : NumberLong(1)
		},
		"durableOpTime" : {
			"ts" : Timestamp(1618367883, 1),
			"t" : NumberLong(1)
		},
		"lastAppliedWallTime" : ISODate("2021-04-14T02:38:03.166Z"),
		"lastDurableWallTime" : ISODate("2021-04-14T02:38:03.166Z")
	},
	"lastStableRecoveryTimestamp" : Timestamp(1618367859, 1),
	"electionCandidateMetrics" : {
		"lastElectionReason" : "electionTimeout",
		"lastElectionDate" : ISODate("2021-04-14T02:32:42.923Z"),
		"electionTerm" : NumberLong(1),
		"lastCommittedOpTimeAtElection" : {
			"ts" : Timestamp(0, 0),
			"t" : NumberLong(-1)
		},
		"lastSeenOpTimeAtElection" : {
			"ts" : Timestamp(1618367562, 1),
			"t" : NumberLong(-1)
		},
		"numVotesNeeded" : 1,
		"priorityAtElection" : 1,
		"electionTimeoutMillis" : NumberLong(10000),
		"newTermStartDate" : ISODate("2021-04-14T02:32:42.964Z"),
		"wMajorityWriteAvailabilityDate" : ISODate("2021-04-14T02:32:43.021Z")
	},
	"members" : [
		{
			"_id" : 0,
			"name" : "localhost:27000",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 719,
			"optime" : {
				"ts" : Timestamp(1618367883, 1),
				"t" : NumberLong(1)
			},
			"optimeDate" : ISODate("2021-04-14T02:38:03Z"),
			"syncSourceHost" : "",
			"syncSourceId" : -1,
			"infoMessage" : "",
			"electionTime" : Timestamp(1618367562, 2),
			"electionDate" : ISODate("2021-04-14T02:32:42Z"),
			"configVersion" : 3,
			"configTerm" : 1,
			"self" : true,
			"lastHeartbeatMessage" : ""
		},
		{
			"_id" : 1,
			"name" : "localhost:27001",
			"health" : 1,
			"state" : 2,
			"stateStr" : "SECONDARY",
			"uptime" : 71,
			"optime" : {
				"ts" : Timestamp(1618367883, 1),
				"t" : NumberLong(1)
			},
			"optimeDurable" : {
				"ts" : Timestamp(1618367883, 1),
				"t" : NumberLong(1)
			},
			"optimeDate" : ISODate("2021-04-14T02:38:03Z"),
			"optimeDurableDate" : ISODate("2021-04-14T02:38:03Z"),
			"lastHeartbeat" : ISODate("2021-04-14T02:38:09.730Z"),
			"lastHeartbeatRecv" : ISODate("2021-04-14T02:38:09.764Z"),
			"pingMs" : NumberLong(0),
			"lastHeartbeatMessage" : "",
			"syncSourceHost" : "localhost:27000",
			"syncSourceId" : 0,
			"infoMessage" : "",
			"configVersion" : 3,
			"configTerm" : 1
		},
		{
			"_id" : 2,
			"name" : "localhost:27002",
			"health" : 1,
			"state" : 7,
			"stateStr" : "ARBITER",
			"uptime" : 31,
			"lastHeartbeat" : ISODate("2021-04-14T02:38:09.730Z"),
			"lastHeartbeatRecv" : ISODate("2021-04-14T02:38:09.807Z"),
			"pingMs" : NumberLong(0),
			"lastHeartbeatMessage" : "",
			"syncSourceHost" : "",
			"syncSourceId" : -1,
			"infoMessage" : "",
			"configVersion" : 3,
			"configTerm" : 1
		}
	],
	"ok" : 1,
	"$clusterTime" : {
		"clusterTime" : Timestamp(1618367883, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	},
	"operationTime" : Timestamp(1618367883, 1)
}
rs:PRIMARY>

注意members项里面的成员是添加的个数。并且每个节点的“stateStr”分别是“PRIMARY”、“SECONDARY”、“ARBITER”。这时候登录从节点或者仲裁节点(不需要初始化和初始化配置)。查看节点状态,和主节点相同的配置会输出出来。至此,本mongodb数据库的复制集配置完成。

五:Compass 连接副本集

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

六:添加用户

rs:PRIMARY> use admin
switched to db admin
rs:PRIMARY> db.createUser({
... user: "admin",
...     pwd: "admin",
...     roles: [{ role: "userAdminAnyDatabase", db: "admin" }]
... })
Successfully added user: {
	"user" : "admin",
	"roles" : [
		{
			"role" : "userAdminAnyDatabase",
			"db" : "admin"
		}
	]
}
rs:PRIMARY> db.createUser({
... user: "root",
... pwd: "root",
... roles: [ { role: "root", db: "admin" } ]
... })
Successfully added user: {
	"user" : "root",
	"roles" : [
		{
			"role" : "root",
			"db" : "admin"
		}
	]
}
rs:PRIMARY> use test
switched to db test
rs:PRIMARY> db.createUser({
... user: "mongo",
... pwd: "123456",
... roles: [ { role: "dbOwner", db: "test" } ]
... })
Successfully added user: {
	"user" : "mongo",
	"roles" : [
		{
			"role" : "dbOwner",
			"db" : "test"
		}
	]
}
rs:PRIMARY> show users
{
	"_id" : "test.mongo",
	"userId" : UUID("7f842cc4-9c1f-4932-b570-d2f705e7ab34"),
	"user" : "mongo",
	"db" : "test",
	"roles" : [
		{
			"role" : "dbOwner",
			"db" : "test"
		}
	],
	"mechanisms" : [
		"SCRAM-SHA-1",
		"SCRAM-SHA-256"
	]
}
rs:PRIMARY>

// 向主节点插入一条数据
rs:PRIMARY> db.foo.insert({"key": "value"})
WriteResult({ "nInserted" : 1 })
// 登录从节点
./bin/mongo 127.0.0.1:27001/admin

// 查看从节点上的数据库,报错
rs:SECONDARY> show dbs
uncaught exception: Error: listDatabases failed:{
	"topologyVersion" : {
		"processId" : ObjectId("607652cbcf3e7e9151103453"),
		"counter" : NumberLong(4)
	},
	"operationTime" : Timestamp(1618383611, 1),
	"ok" : 0,
	"errmsg" : "not master and slaveOk=false",
	"code" : 13435,
	"codeName" : "NotPrimaryNoSecondaryOk",
	"$clusterTime" : {
		"clusterTime" : Timestamp(1618383611, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}


// 当前从节点只是一个备份,不是奴隶节点,无法读取数据,写当然更不行。
// 因为默认情况下,从节点是没有读写权限的,可以增加读的权限,但需要进行设置。
// 设置为奴隶节点,允许在从成员上运行读的操作
rs:SECONDARY> rs.secondaryOk()

// 从节点上的数据从主节点上复制过来了
rs:SECONDARY> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
test    0.000GB
rs:SECONDARY> use test
rs:SECONDARY> db.foo.find()
{ "_id" : ObjectId("607692bcc83116b2c09bb439"), "key" : "value" }
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

目    录   第一部分  入门指南   第1章  为现代Web而生的数据库 2   1.1  生于云端 3   1.2  MongoDB的主要特性 4   1.2.1  文档数据模型 4   1.2.2  即时查询 6   1.2.3  二级索引 7   1.2.4  复制 8   1.2.5  速度和持久性 9   1.2.6  数据库扩展 10   1.3  MongoDB的核心服务器和工具 11   1.3.1  核心服务器 11   1.3.2  JavaScript Shell 12   1.3.3  数据库驱动 12   1.3.4  命令行工具 13   1.4  为什么选择MongoDB 13   1.4.1  MongoDB与其他数据库的对比 14   1.4.2  使用场景和生产部署 16   1.5  提示与局限 18   1.6  小结 18   第2章  MongoDB JavaScript Shell 19   2.1  深入MongoDB Shell 19   2.1.1  启动Shell 20   2.1.2  插入与查询 20   2.1.3  更新文档 22   2.1.4  删除数据 23   2.2  创建索引并查询 24   2.2.1  创建一个大合 24   2.2.2  索引与explain() 25   2.3  基本管理 27   2.3.1  获取数据库信息 27   2.3.2  命令工作原理 29   2.4  获得帮助 30   2.5  小结 31   第3章  使用MongoDB编写程序 32   3.1  通过Ruby使用MongoDB 32   3.1.1  安装与连接 33   3.1.2  用Ruby插入文档 34   3.1.3  查询与游标 34   3.1.4  更新与删除 35   3.1.5  数据库命令 36   3.2  驱动是如何工作的 37   3.2.1  对象ID生成 37   3.2.2  BSON 38   3.2.3  网络传输 40   3.3  构建简单的应用程序 41   3.3.1  配置 41   3.3.2  收数据 42   3.3.3  查看归档 43   3.4  小结 46   第二部分  MongoDB与应用程序开发   第4章  面向文档的数据 48   4.1  Schema设计原则 48   4.2  设计电子商务数据模型 49   4.2.1  产品与分类 50   4.2.2  用户与订单 53   4.2.3  评论 55   4.3  具体细节数据库、合与文档 56   4.3.1  数据库 56   4.3.2  合 58   4.3.3  文档与插入 61   4.4  小结 65   第5章  查询与聚合 66   5.1  电子商务查询 66   5.1.1  产品、分类与评论 66   5.1.2  用户与订单 68   5.2  MongoDB查询语言 70   5.2.1  查询选择器 70   5.2.2  查询选项 78   5.3  聚合指令 79   5.3.1  根据用户对评论进行分组 79   5.3.2  根据地域对订单应用MapReduce 81   5.4  详解聚合 82   5.4.1  max()与min() 82   5.4.2  distinct 83   5.4.3  group 83   5.4.4  map-reduce 84   5.5  小结 86   第6章  更新、原子操作与删除 87   6.1  文档更新入门 87   6.2  电子商务数据模型中的更新 89   6.2.1  产品与分类 90   6.2.2  评论 93   6.2.3  订单 94   6.3  原子文档处理 96   6.3.1  订单状态变迁 97   6.3.2  库存管理 98   6.4  具体细节MongoDB的更新与删除 101   6.4.1  更新类型与选项 101   6.4.2  更新操作符 103   6.4.3  findAndModify命令 106   6.4.4  删除 106   6.4.5  并发性、原子性与隔离性 107   6.4.6  更新性能说明 107   6.5  小结 109   第三部分  精通MongoDB   第7章  索引与查询优化 112   7.1  索引理论 112   7.1.1  思想实验 112   7.1.2  核心索引概念 115   7.1.3  B树 118   7.2  索引实践 119   7.2.1  索引类型 119   7.2.2  索引管理 121   7.3  查询优化 125   7.3.1  识别慢查询 125   7.3.2  分析慢查询 127   7.3.3  查询模式 133   7.4  小结 134   第8章  复制 135   8.1  复制概述 135   8.1.1  为什么复制很重要 135   8.1.2  复制的使用场景 136   8.2  副本 137   8.2.1  配置 137   8.2.2  复制的工作原理 141   8.2.3  管理 146   8.3  主复制 152   8.4  驱动与复制 152   8.4.1  连接与故障转移 153   8.4.2  写关注 154   8.4.3  读扩展 155   8.4.4  标签 156   8.5  小结 158   第9章  分片 159   9.1  分片概述 159   9.1.1  何谓分片 160   9.1.2  分片的工作原理 161   9.2  示例分片群 164   9.2.1  配置 164   9.2.2  写入分片群 168   9.3  分片群的查询与索引 173   9.3.1  分片查询类型 173   9.3.2  索引 177   9.4  选择分片键 178   9.4.1  低效的分片键 178   9.4.2  理想的分片键 179   9.5  生产环境中的分片 180   9.5.1  部署与配置 180   9.5.2  管理 184   9.6  小结 188   第10章  部署与管理 189   10.1  部署 189   10.1.1  部署环境 189   10.1.2  服务器配置 193   10.1.3  数据的导入与导出 194   10.1.4  安全 195   10.2  监控与诊断 197   10.2.1  日志 197   10.2.2  监控工具 198   10.2.3  外部监控应用程序 201   10.2.4  诊断工具mongosniff、bsondump 201   10.3  维护 202   10.3.1  备份与恢复 202   10.3.2  压紧与修复 204   10.3.3  升级 205   10.4  性能调优 205   10.4.1  为提升性能检查索引和查询 206   10.4.2  添加内存 206   10.4.3  提升磁盘性能 207   10.4.4  水平扩展 207   10.4.5  寻求专业帮助 207   10.5  小结 208   附录A  安装 209   附录B  设计模式 216   附录C  二进制数据与GridFS 226   附录D  在PHP、Java与C++中使用MongoDB 232   附录E  空间索引 240
相关推荐
©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值