MongoDB是一个NoSQL数据库,它使用类似JSON的文档,具有动态模式。当使用数据库时,有一个应急计划总是好的,以防你的一个数据库服务器发生故障。旁白,你可以通过为你的WordPress网站利用一个灵巧的管理工具来减少发生这种情况的机会。
这就是为什么有许多数据的副本是有用的。它还可以减少读取延迟。同时,它可以提高数据库的可扩展性和可用性。这就是副本的作用。它被定义为在多个数据库之间同步数据的做法。
在这篇文章中,我们将深入探讨MongoDB复制副本集的各个突出方面,比如它的功能和机制,仅举几例。
- 什么是MongoDB的副本?
- 什么是MongoDB副本集?
- 副本在MongoDB中是如何工作的?
- 如何创建一个MongoDB副本集?
- 处理副本延迟的问题
- MongoDB副本集的故障排除
- 使用密钥文件认证确保安全通信
什么是MongoDB的副本?
在MongoDB中,副本集执行复制。这是一组服务器通过复制维护相同的数据集。你甚至可以将MongoDB副本作为负载平衡的一部分。在这里,你可以根据使用情况,在所有的实例上分配写和读的操作。
什么是MongoDB副本集?
属于某个副本集的每个MongoDB实例都是一个成员。每个副本集都需要有一个主要成员和至少一个辅助成员。
主要成员是与副本集进行交易的主要访问点。它也是唯一可以接受写操作的成员。副本首先复制主成员的OPLOG(操作日志)。接下来,它在第二层的各自数据集上重复记录的变化。因此,每个副本集在同一时间只能有一个主要成员。不同的主站接受写操作会导致数据冲突。
通常情况下,应用程序只查询主要成员的写和读操作。你可以设计你的设置,从一个或多个辅助成员中读取。异步数据传输会导致二级节点的读取为旧数据服务。因此,这样的安排并不是每个用例的理想选择。
副本集的特点
自动故障转移机制使MongoDB的副本集在其竞争中脱颖而出。在没有主节点的情况下,副节点之间的自动选举会选出一个新的主节点。
MongoDB副本集vs MongoDB集群
一个MongoDB副本集将在副本集节点上创建同一数据集的各种副本。副本集的主要目的是:
- 提供一个内置的备份解决方案
- 增加数据的可用性
MongoDB集群是一个完全不同的球赛。它通过一个分片键将数据分布在许多节点上。这个过程将把数据分割成许多碎片,称为分片。接下来,它将每个分片副本到不同的节点上。集群的目的是支持大型数据集和高吞吐量操作。它通过横向扩展工作负载来实现这一目标。
下面是副本集和集群的区别,通俗地说:
- 集群分配了工作负载。它还在许多服务器上存储数据片段(碎片)。
- 副本集则完全复制了数据集。
MongoDB允许你通过建立一个分片集群来结合这些功能。在这里,你可以将每个分片复制到一个辅助服务器。这使得分片可以提供高冗余度和数据可用性。
维护和设置一个副本集在技术上是很费力和费时的。而找到合适的托管服务?这又是一个令人头痛的问题。有这么多的选择,很容易在研究上浪费时间,而不是建立你的业务。
让我给你介绍一个工具,它可以做所有这些事情,还有更多,这样你就可以回去用你的服务/产品粉碎它。
MongoDB中的副本是如何工作的?
在MongoDB中,你将写操作发送到主服务器(节点)。主服务器将这些操作分配到次服务器上,复制数据。
MongoDB复制过程图解(图片来源:MongoDB)
在三种类型的MongoDB节点中,有两种曾经出现过:主节点和次节点。第三种在复制过程中派上用场的MongoDB节点是一个仲裁者。仲裁者节点没有数据集的副本,不能成为主节点。虽然如此,仲裁者确实参与了主节点的选举。
我们之前提到过当主节点瘫痪时会发生什么,但如果次要节点被咬了怎么办?在这种情况下,主节点变成了次要节点,数据库变得无法访问。
成员选举
选举可以在以下情况下发生:
- 初始化一个副本集
- 失去与主节点的连接(可以通过心跳检测)。
- 使用
rs.reconfig
或stepDown
方法维护一个副本集 - 向现有的副本集添加一个新的节点
一个副本集最多可以拥有50个成员,但只有7个或更少的成员可以在任何选举中投票。
集群选举一个新的主节点之前的平均时间不应该超过12秒。选举算法将试图让具有最高优先级的副手可用。同时,优先级值为0的成员不能成为主选,不参与选举。
二级节点成为一级节点(图片来源:Medium)
写的问题
对于耐用性,写操作有一个框架,在指定的节点数量中复制数据。你甚至可以借此向客户端提供反馈。这个框架也被称为 “写关注”。它有数据承载成员,在操作返回成功之前,需要确认写关注。一般来说,副本集的值是1,作为一个写关注。因此,在返回写关注的确认之前,只有主站应该确认写。
你甚至可以增加确认写操作所需的成员数量。你可以拥有的成员数量没有上限。但是,如果数量很高,你需要处理高延迟的问题。这是因为客户端需要等待所有成员的确认。另外,你可以设置 “多数人 “的写入关注。这是在收到一半以上的成员的确认后计算出来的。
读取偏好
对于读取操作,你可以提到读取偏好,它描述了数据库如何将查询指向副本集的成员。一般来说,主节点会收到读取操作,但客户可以提及读取偏好,将读取操作发送到二级节点。以下是读取偏好的选项:
- primaryPreferred:通常情况下,读取操作来自主节点,但如果这一点不可用,数据就会从二级节点中提取。
- primary:所有的读取操作都来自于主节点。
- secondary:所有的读取操作都由二级节点执行。
- nearest:这里,读取请求被路由到最近的可达节点,这可以通过运行
ping
命令来检测。读取操作的结果可以来自副本集的任何成员,不管它是主节点还是次节点。 - secondaryPreferred:在这里,大部分的读取操作来自于二级节点,但如果其中有无可用的节点,则从主节点获取数据。
副本集的数据同步
为了维护共享数据集的最新副本,副本集的二级成员从其他成员那里复制或同步数据。
MongoDB利用了两种形式的数据同步。初始同步,用完整的数据集来填充新成员。复制以执行对完整数据集的持续更改。
初始同步
在初始同步期间,辅助节点运行 init sync
命令,将所有数据从主节点同步到另一个包含最新数据的辅助节点。因此,二级节点始终利用 tailable cursor
功能来查询主节点的local.oplog.rs集合内的最新oplog条目,并在这些oplog条目内应用这些操作。
从MongoDB 5.2开始,初始同步可以是基于文件拷贝或逻辑同步。
(1)逻辑同步
当你执行逻辑同步时,MongoDB:
- 在为每个集合副本文件时,开发所有的集合索引。
- 副本除本地数据库以外的所有数据库。
mongod
扫描所有源数据库中的每个集合,并将所有数据插入其副本的这些集合中。 - 执行数据集上的所有变化。通过利用源数据库的OPLOG,
mongod
升级其数据集以描述副本集的当前状态。 - 在数据复制过程中提取新添加的OPLOG记录。确保目标成员在本地数据库内有足够的磁盘空间,以便在这个数据复制阶段的时间内暂存这些otlog记录。
当初始同步完成后,成员从 STARTUP2
过渡到 SECONDARY
。
(2)基于文件拷贝的初始同步
一开始,只有当你使用MongoDB企业版时才能执行这个。这个过程通过复制和移动文件系统上的文件来运行初始同步。这种同步方法在某些情况下可能比逻辑初始同步更快。请记住,如果你在没有查询谓词的情况下运行count()方法,基于文件副本的初始同步可能导致不准确的计数。
但是,这种方法也有它的局限性。
- 在基于文件拷贝的初始同步过程中,你不能写到被同步的成员的本地数据库中。你也不能在被同步的成员或被同步的成员上运行备份。
- 当利用加密存储引擎时,MongoDB使用源密钥对目标进行加密。
- 你每次只能从一个给定的成员运行初始同步。
副本
二级成员在初始同步后持续复制数据。二级成员将副本他们从源头同步的OPLOG,并在一个异步过程中执行这些操作。
二级成员能够根据其他成员副本的ping时间和状态的变化,根据需要自动修改其从源同步。
(1)流式副本
从MongoDB 4.4开始,来自源的同步向其同步的第二方发送连续的OPLOG条目流。流式副本减少了高负荷和高延迟网络中的副本滞后。它还可以:
- 减少由于主站故障切换而导致的
w:1
的写操作丢失的风险。 - 减少从第二级读取的滞后性。
- 减少
w:“majority”
和w:>1
的写操作的延迟。简而言之,任何需要等待副本的写关注。
(2)多线程副本
MongoDB习惯于通过多线程分批写操作,以提高并发性。MongoDB通过文档ID对批次进行分组,同时用不同的线程应用每组操作。
MongoDB总是以其原始的写入顺序执行对给定文档的写入操作。这在MongoDB 4.0中有所改变。
从MongoDB 4.0开始,如果读取发生在应用副本批次的二级系统上,针对二级系统并配置了 “majority”
或 “local”
的读取操作现在将从WiredTiger的数据快照读取。从快照中读取保证了数据的一致性,并让读取与正在进行的副本同时发生而不需要锁。
因此,需要这些读取关注级别的次级读取不再需要等待副本批次的应用,可以在收到时进行处理。
如何创建一个MongoDB的副本集
如前所述,MongoDB通过副本集处理副本。在接下来的几节中,我们将强调一些方法,你可以用这些方法来为你的使用情况创建副本集。
方法一:在Ubuntu上创建一个新的MongoDB副本集
在我们开始之前,你需要确保你至少有三台运行Ubuntu 20.04的服务器,每台服务器上都安装有MongoDB。
要建立一个副本集,必须提供一个地址,让副本集的每个成员都能被副本集中的其他人联系到。在这种情况下,我们在该组中保留三个成员。虽然我们可以使用IP地址,但不建议这样做,因为地址可能会意外地改变。一个更好的选择是在配置副本集时使用逻辑的DNS主机名。
我们可以通过为每个副本成员配置子域来做到这一点。虽然这可能是生产环境的理想选择,但本节将概述如何通过编辑每个服务器各自的hosts文件来配置DNS解析。这个文件允许我们将可读的主机名分配给数字IP地址。因此,如果在任何情况下,你的IP地址发生了变化,你所要做的就是更新三个服务器上的hosts’文件,而不是从头开始重新配置副本集!
大多数情况下,hosts
被存储在 /etc/
目录下。在你的三台服务器上分别重复下面的命令:
sudo nano /etc/hosts
在上面的命令中,我们使用nano作为我们的文本编辑器,然而,你可以使用你喜欢的任何文本编辑器。在配置本地主机的前几行之后,为副本集的每个成员添加一个条目。这些条目的形式是一个IP地址,后面是你选择的可读名称。虽然你可以随心所欲地命名它们,但一定要有描述性,这样你才知道如何区分每个成员。在本教程中,我们将使用下面的主机名:
- mongo0.replset.member
- mongo1.replset.member
- mongo2.replset.member
使用这些主机名,你的/etc/hosts文件将看起来类似于以下突出显示的行:
主机名图解
保存并关闭该文件。
在为副本集配置了DNS解析后,我们需要更新防火墙规则,以允许它们相互通信。在mongo0上运行以下 ufw
命令,为mongo1提供对mongo0上27017端口的访问:
sudo ufw allow from mongo1_server_ip to any port 27017
在 mongo1_server_ip
参数的位置,输入mongo1服务器的实际IP地址。另外,如果你已经更新了该服务器上的Mongo实例以使用非默认的端口,请确保改变27017以反映你的MongoDB实例正在使用的端口。
现在添加另一个防火墙规则,让mongo2访问同一个端口:
sudo ufw allow from mongo2_server_ip to any port 27017
在 mongo2_server_ip
参数的地方,输入你的mongo2服务器的实际IP地址。然后,为你的另外两个服务器更新防火墙规则。在mongo1服务器上运行以下命令,确保改变server_ip参数中的IP地址,以分别反映mongo0和mongo2的地址:
sudo ufw allow from mongo0_server_ip to any port 27017
sudo ufw allow from mongo2_server_ip to any port 27017
最后,在mongo2上运行这两条命令。同样,要确保你为每台服务器输入正确的IP地址:
sudo ufw allow from mongo0_server_ip to any port 27017
sudo ufw allow from mongo1_server_ip to any port 27017
你的下一步是更新每个MongoDB实例的配置文件以允许外部连接。为了允许这一点,你需要修改每台服务器的配置文件,以反映IP地址并指明副本集。虽然你可以使用任何首选的文本编辑器,但我们再次使用nano文本编辑器。让我们在每个mongod.conf文件中做如下修改。
On mongo0:
# network interfaces net: port: 27017 bindIp: 127.0.0.1,mongo0.replset.member# replica set replication: replSetName: "rs0"
On mongo1:
# network interfaces net: port: 27017 bindIp: 127.0.0.1,mongo1.replset.member replication: replSetName: "rs0"
On mongo2:
# network interfaces net: port: 27017 bindIp: 127.0.0.1,mongo2.replset.member replication: replSetName: "rs0"
Important
如果你想改变rs0的指令值,请确保在上述命令中替换相同的指令。你可以把指令命名为任何你想要的东西,但是,请确保它有足够的描述性。更新完成后,在每个实例中重新启动mongod服务以重新加载配置。
sudo systemctl restart mongod
这样,你就为每个服务器的MongoDB实例启用了副本功能。
现在你可以通过使用 rs.initiate()
方法来初始化副本集。这个方法只需要在副本集中的单个MongoDB实例上执行。确保副本集的名称和成员与你之前在每个配置文件中的配置一致。
rs.initiate( { _id: "rs0", members: [ { _id: 0, host: "mongo0.replset.member" }, { _id: 1, host: "mongo1.replset.member" }, { _id: 2, host: "mongo2.replset.member" } ] })
如果该方法返回 “ok”。1,这意味着副本集被正确启动。下面是一个输出结果的例子,应该是这样的:
{ "ok": 1, "$clusterTime": { "clusterTime": Timestamp(1612389071, 1), "signature": { "hash": BinData(0, "AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId": NumberLong(0) } }, "operationTime": Timestamp(1612389071, 1) }
关闭MongoDB服务器
你可以通过使用 db.shutdownServer()
方法关闭MongoDB服务器。下面是同样的语法。force
和 timeoutsecs
都是可选参数。
db.shutdownServer({ force: <boolean>, timeoutSecs: <int> })
如果mongod replica set成员在建立索引时运行某些操作,这个方法可能会失败。要中断这些操作并强制成员关闭,你可以将布尔参数 force
输入为true。
用-replSet重启MongoDB
要重置配置,请确保副本组中的每个节点都已停止。然后删除每个节点的本地数据库。使用 –replSet
标志再次启动它,并且只在副本集的一个mongod实例上运行 rs.initiate()
。
mongod --replSet "rs0"
rs.initiate()
可以接受一个可选的副本集配置文件,即:
Replication.replSetName
或—replSet
选项,在_id
字段中指定副本集名称。- 成员数组,其中包含每个副本集成员的一个文件。
rs.initiate()
方法触发一个选举,并选出其中一个成员作为主选。
将成员添加到副本集
为了向该集合添加成员,在不同的机器上启动mongod实例。接下来,启动一个mongo客户端并使用 rs.add()
命令。
rs.add()
命令的基本语法如下:
rs.add(HOST_NAME:PORT)
比如说,
假设mongo1是你的mongod实例,它在27017端口监听。使用Mongo客户端命令 rs.add()
将这个实例添加到副本集中。
rs.add("mongo1:27017")
只有在你连接到主节点后,你才能将mongod实例添加到副本集。要验证你是否连接到主节点,可以使用 db.isMaster()
命令。
移除用户
要移除一个成员,我们可以使用 rs.remove()
要做到这一点,首先,通过使用我们上面讨论的 db.shutdownServer()
方法,关闭你想删除的mongod实例。
接下来,连接到副本集的当前主节点。要确定当前的主副本,可以在连接到副本集的任何成员时使用 db.hello()
。一旦你确定了主站,运行下面的命令:
rs.remove("mongodb-node-04:27017") rs.remove("mongodb-node-04")
上面的图片显示,该节点被成功地从副本集中移除。(图片来源:Bmc)
如果副本集需要选出一个新的主节点,MongoDB可能会短暂地断开shell的连接。在这种情况下,它将自动再次重新连接。另外,它可能会显示一个 DBClientCursor::init call()
失败的错误,即使命令成功了。
方法二:配置MongoDB副本集进行部署和测试
一般来说,你可以在启用或禁用RBAC的情况下为测试设置副本集。在这个方法中,我们将在禁用访问控制的情况下设置副本集,以便在测试环境中部署。
首先,使用下面的命令为所有属于副本集的实例创建目录:
mkdir -p /srv/mongodb/replicaset0-0 /srv/mongodb/replicaset0-1 /srv/mongodb/replicaset0-2
这个命令将为三个MongoDB实例replicaset0-0、replicaset0-1和replicaset0-2创建目录。现在,使用下面这组命令为每个实例启动MongoDB实例:
For Server 1:
mongod --replSet replicaset --port 27017 --bind_ip localhost,<hostname(s)|ip address(es)> --dbpath /srv/mongodb/replicaset0-0 --oplogSize 128
For Server 2:
mongod --replSet replicaset --port 27018 --bind_ip localhost,<hostname(s)|ip address(es)> --dbpath /srv/mongodb/replicaset0-0 --oplogSize 128
For Server 3:
mongod --replSet replicaset --port 27019 --bind_ip localhost,<hostname(s)|ip address(es)> --dbpath /srv/mongodb/replicaset0-0 --oplogSize 128
–oplogSize
参数用于防止机器在测试阶段过载。它有助于减少每个磁盘所消耗的磁盘空间。
现在,通过使用下面的端口号,用Mongo shell连接到其中一个实例。
mongo --port 27017
我们可以使用 rs.initiate()
命令来启动副本过程。你必须用你的系统名称替换 hostname
参数。
rs conf = { _id: "replicaset0", members: [ { _id: 0, host: "<hostname>:27017}, { _id: 1, host: "<hostname>:27018"}, { _id: 2, host: "<hostname>:27019"} ] }
现在你可以把配置对象文件作为initiate命令的参数传递给它,并按如下方式使用:
rs.initiate(rsconf)
就这样,你拥有了它! 你已经成功创建了一个用于开发和测试的MongoDB副本集。
方法三:将独立实例转化为MongoDB副本集
MongoDB允许其用户将他们的独立实例转化为副本集。独立实例主要用于测试和开发阶段,而副本集是生产环境的一部分。
为了开始,让我们使用以下命令关闭我们的mongod实例:
db.adminCommand({"shutdown":"1"})
通过在命令中使用 –repelSet
参数来指定你要使用的副本集,重新启动你的实例:
mongod --port 27017 – dbpath /var/lib/mongodb --replSet replicaSet1 --bind_ip localhost,<hostname(s)|ip address(es)>
你必须在命令中指定你的服务器的名称以及唯一的地址。
将shell与你的MongoDB实例连接,并使用initiate命令启动副本过程,并成功地将实例转换为副本集。你可以使用以下命令执行所有的基本操作,比如添加或删除一个实例:
rs.add(“<host_name:port>”)
rs.remove(“host-name”)
此外,你可以使用 rs.status()
和 rs.conf()
命令检查你的MongoDB副本集的状态。
方法四:MongoDB Atlas – 一个更简单的替代方案
副本和分片可以一起工作,形成一个叫做分片集群的东西。虽然设置和配置可能相当耗时,尽管很简单,但MongoDB Atlas是一个比前面提到的方法更好的选择。
它可以自动化你的副本集,使这个过程容易实现。它可以通过几次点击来部署全局分片副本集,实现灾难恢复,更容易管理,数据定位,以及多区域部署。
在MongoDB Atlas中,我们需要创建集群–它们可以是一个副本集,也可以是一个分片集群。对于一个特定的项目,其他地区的集群中的节点数量被限制在总共40个。
这不包括免费或共享的集群和相互通信的谷歌云区域。任何两个区域之间的节点总数必须满足这个约束。例如,如果有一个项目在其中:
- 区域A有15个节点。
- 区域B有25个节点
- 区域C有10个节点
我们只能再分配5个节点给区域C,因为:
- 区域A+区域B=40;满足40是允许的最大节点数的约束。
- 区域B+区域C=25+10+5(分配给C的额外节点)=40;满足40是允许的最大节点数的约束。
- 区域A+区域C=15+10+5(分配给C的额外节点)=30;满足40是允许的最大节点数的约束。
如果我们再分配10个节点给区域C,使区域C有20个节点,那么区域B+区域C=45个节点。这将超过给定的约束条件,所以你可能无法创建一个多区域集群。
当你创建一个集群时,Atlas会在项目中为云提供商创建一个网络容器,如果它之前不在那里。要在MongoDB Atlas中创建一个副本集集群,请在Atlas CLI中运行以下命令:
atlas clusters create [name] [options]
请确保你给出一个描述性的集群名称,因为在集群创建后它不能被改变。该参数可以包含ASCII字母、数字和连字符。
在MongoDB中,根据你的要求,有几个选项可用于创建集群。例如,如果你想为你的集群进行连续的云备份,请将 --backup
设置为 true。
处理副本延迟的问题
副本延迟可能相当令人脑瓜疼的事情。它是指在主服务器上的操作和从OPLOG到辅助服务器上的应用之间的延迟。如果你的业务是处理大型数据集,在一定的阈值内,延迟是可以预期的。然而,有时外部因素也可能造成并增加延迟。为了从最新的副本中获益,请确保:
- 你在一个稳定和足够的带宽中路由你的网络流量。网络延迟在影响你的副本方面起着巨大的作用,如果网络不足以满足复制过程的需要,那么在整个副本集中复制数据就会出现延迟。
- 你有足够的磁盘吞吐量。如果辅助节点上的文件系统和磁盘设备不能像主节点那样快速地将数据刷入磁盘,那么辅助节点将难以跟上。因此,次级节点处理写查询的速度比主节点慢。这是大多数多用户系统中的一个常见问题,包括虚拟化实例和大规模部署。
- 你在一个时间间隔后请求写确认写关注,以提供机会让次要节点赶上主节点,特别是当你想执行一个批量加载操作或数据摄取,需要大量写到主节点时。二级系统将无法快速读取OPLOG以跟上变化;特别是在未确认的写关注方面。
- 你确定正在运行的后台任务。某些任务如cron job、服务器更新和安全检查可能会对网络或磁盘的使用产生意想不到的影响,导致复制过程的延迟。
如果你不确定你的应用程序中是否存在副本滞后,不要着急–下一节讨论了故障排除策略!
诊断MongoDB副本集的故障
你已经成功地设置了你的副本集,但你注意到你的数据在服务器之间不一致。这对大型企业来说是非常令人震惊的,然而,通过快速的故障排除方法,你可能会找到原因,甚至纠正这个问题! 下面是一些常见的副本集部署的故障排除策略,可能会派上用场:
检查副本状态
我们可以通过在连接到副本集主站的mongosh会话中运行以下命令来检查副本集的当前状态和每个成员的状态。
rs.status()
检查副本滞
正如前面所讨论的,副本滞后可能是一个严重的问题,因为它使 “lagged” 的成员没有资格迅速成为主要成员,并增加了分布式读操作不一致的可能性。我们可以用下面的命令来检查副本日志的当前长度:
rs.printSecondaryReplicationInfo()
这将返回 syncedTo
值,该值是每个成员的最后一条OPLOG条目被写入二级数据库的时间。这里有一个例子来证明这一点:
source: m1.example.net:27017 syncedTo: Mon Oct 10 2022 10:19:35 GMT-0400 (EDT) 0 secs (0 hrs) behind the primary source: m2.example.net:27017 syncedTo: Mon Oct 10 2022 10:19:35 GMT-0400 (EDT) 0 secs (0 hrs) behind the primary
当主站的不活动期大于 members[n].secondaryDelaySecs
值时,一个延迟的成员可能显示为比主站晚0秒。
测试所有成员之间的连接
副本集的每个成员必须能够与其他每个成员连接。一定要确保验证两个方向的连接。大多数情况下,防火墙配置或网络拓扑结构会阻止正常和必要的连接,这可能会阻碍副本。
例如,让我们假设mongod实例同时绑定到localhost和与IP地址198.41.110.1相关的主机名’ExampleHostname’:
mongod --bind_ip localhost, ExampleHostname
要连接到这个实例,远程客户必须指定主机名或IP地址。
mongosh --host ExampleHostname mongosh --host 198.41.110.1
如果一个副本集由三个成员组成,即m1、m2和m3,使用默认端口27017,你应该按以下方式测试连接:
On m1:
mongosh --host m2 --port 27017 mongosh --host m3 --port 27017
On m2:
mongosh --host m1 --port 27017 mongosh --host m3 --port 27017
On m3:
mongosh --host m1 --port 27017 mongosh --host m2 --port 27017
如果任何方向的连接都失败了,你必须检查你的防火墙配置,并重新配置以允许连接。
用密钥文件认证确保安全通信
默认情况下,MongoDB中的密钥文件认证依赖于加盐挑战响应认证机制(SCRAM)。为了做到这一点,MongoDB必须读取并验证用户提供的凭证,其中包括特定MongoDB实例所知道的用户名、密码和认证数据库的组合。这正是用来验证连接数据库时提供密码的用户的机制。
当你在MongoDB中启用认证时,基于角色的访问控制(RBAC)会自动为副本集启用,用户被授予一个或多个角色,以决定他们对数据库资源的访问。当RBAC被启用时,意味着只有经过认证的有效Mongo用户,并具有相应的权限,才能够访问系统中的资源。
密钥文件的作用就像集群中每个成员的共享密码。这使得副本集中的每个mongod实例能够使用钥匙文件的内容作为共享密码,以验证部署中的其他成员。
只有那些拥有正确密钥文件的mongod实例才能加入副本集。一个密钥的长度必须在6到1024个字符之间,并且只能包含base64集的字符。请注意,MongoDB在读取密钥时,会删除空白字符。
你可以使用各种方法来生成一个密钥文件。在本教程中,我们使用 openssl
生成一个复杂的1024个随机字符的字符串,作为共享密码使用。然后,它使用 chmod
来改变文件权限,只为文件所有者提供阅读权限。避免将密钥文件存储在容易与托管mongod实例的硬件断开连接的存储介质上,如USB驱动器或网络连接的存储设备。下面是生成密钥文件的命令:
openssl rand -base64 756 > <path-to-keyfile> chmod 400 <path-to-keyfile>
接下来,将密钥文件复制到每个副本集成员。确保运行mongod实例的用户是该文件的所有者,可以访问该密钥文件。在你完成上述工作后,从第二层开始,关闭副本组的所有成员。一旦所有的辅助设备都离线,你就可以继续关闭主设备。必须遵循这个顺序,以防止潜在的回滚。现在通过运行以下命令关闭mongod实例:
use admin db.shutdownServer()
命令运行后,副本集的所有成员都将脱机。现在,重新启动副本集的每个成员,并启用访问控制。
对于副本集的每个成员,用 security.keyFile
配置文件设置或 --keyFile
命令行选项启动mongod实例。
如果你使用的是一个配置文件,请将
- security.keyFile为keyfile的路径,而
- replication.replSetName为副本集名称。
security: keyFile: <path-to-keyfile> replication: replSetName: <replicaSetName> net: bindIp: localhost,<hostname(s)|ip address(es)>
使用配置文件启动mongod实例:
mongod --config <path-to-config-file>
如果你使用的是命令行选项,请用以下选项启动mongod实例:
- -keyFile设置为keyfile的路径,和
- -replSet设置为副本集的名称。
mongod --keyFile <path-to-keyfile> --replSet <replicaSetName> --bind_ip localhost,<hostname(s)|ip address(es)>
你可以根据你的配置需要包括额外的选项。例如,如果你希望远程客户端连接到你的部署或你的部署成员在不同的主机上运行,指定-bind_ip。欲了解更多信息,请参见本地主机绑定兼容性变化。
接下来,通过 localhost 接口连接到副本集的一个成员。你必须在与mongod实例相同的物理机上运行mongosh。这个接口只有在没有为部署创建用户时才可用,并且在创建第一个用户后自动关闭。
然后我们启动副本集。在mongosh中,运行 rs.initiate()
方法:
rs.initiate( { _id: "myReplSet", members: [ { _id: 0, host: "mongo1:27017" }, { _id: 1, host: "mongo2:27017" }, { _id: 2, host: "mongo3:27017" } ] } )
正如之前所讨论的,这个方法会选择其中一个成员作为副本集的主要成员。要找到主要成员,请使用rs.status()
。在继续之前连接到主成员。
现在,创建用户管理员。你可以使用 db.createUser()
方法添加一个用户。确保该用户在管理数据库上至少要有 userAdminAnyDatabase
角色。
下面的例子创建了用户 “batman”,他在管理数据库上具有 userAdminAnyDatabase
的角色:
admin = db.getSiblingDB("admin") admin.createUser( { user: "batman", pwd: passwordPrompt(), // or cleartext password roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] } )
在提示时输入之前创建的密码。
接下来,你必须以管理员的身份进行认证。要做到这一点,使用 db.auth()
来验证。比如说
db.getSiblingDB(“admin”).auth(“batman”, passwordPrompt()) // 或者明文密码
另外,你可以使用 -u <username>
, -p <password>
和 --authenticationDatabase
参数将一个新的mongosh实例连接到主副本集成员。
mongosh -u "batman" -p --authenticationDatabase "admin"
即使你没有在 -p
命令行字段中指定密码,mongosh也会提示你输入密码。
最后,创建集群管理员。clusterAdmin
角色授予副本操作的权限,比如配置副本集。
让我们创建一个集群管理员用户,并在管理数据库中分配 clusterAdmin
角色:
db.getSiblingDB("admin").createUser( { "user": "robin", "pwd": passwordPrompt(), // or cleartext password roles: [ { "role" : "clusterAdmin", "db" : "admin" } ] } )
在提示时输入密码。
如果你愿意,你可以创建额外的用户,以允许客户与副本集进行互动。
然后就可以了! 你已经成功地启用了密钥文件认证!
小结
当涉及到数据库时,副本一直是一个基本要求,特别是当更多的企业扩大规模时。它广泛提高了系统的性能、数据安全性和可用性。说到性能,对你的WordPress数据库来说,监测性能问题并在关键时刻纠正它们是至关重要的,例如,Jetpack和Freshping就是其中之一。
副本有助于确保跨多个服务器的数据保护,并防止你的服务器遭受严重的停机(甚至更糟糕的是–完全失去你的数据)。在这篇文章中,我们介绍了副本集的创建和一些故障排除技巧,以及副本的重要性。你是否为你的业务使用MongoDB副本,它是否被证明对你有用?请在下面的评论区告诉我们!
评论留言