什么是副本集:

  • 是一组维护相同数据集的mongod进程
  • 提供冗余,自动故障转移和高可用性
  • 提供读取可伸缩性
  • 内部概念或多或少与MySQL的概念相似
    • PRIMARY概念与MySQL复制中的MASTER大致相同
    • SECONDARY概念与MySQL复制中的SLAVE大致相同。
    • 数据复制是异步的,就像在MySQL中一样。我们不确定辅助设备是否与主设备保持同步。但是在MongoDB中,我们可以在写操作上定义“写问题”来定义需要什么类型的确认。例如,我们可以定义一个写入需要确认是否至少有一个辅助节点已经应用了该文档,或者我们甚至可以要求所有辅助节点都需要是最新的。
    • 在读取oplog的节点之间复制数据,这是一个包含修改和插入文档的特殊上限集合。这个概念类似于MySQL binlog,但它们的工作方式不同。oplog的一个特点是它内部的每个操作都是幂等的。这意味着即使应用一次或多次,oplog操作也会产生相同的结果。例如,您不能删除两次。如果您再次应用相同的删除操作,那将是一个无操作。插入和更新也是如此。
    • 由于oplog是数据库中的集合,我们可以轻松地查询它。oplog的内容是在系统的每个集合上插入或更新的文档。由于oplog是一个上限集合,因此它具有固定且可配置的大小。因此,oplog的大小也表示我们过去可以为事件花多长时间。作为一个粗略的例子:如果我们的数据库每天总共1GB插入,更新或删除文档,拥有3GB的oplog意味着我们可以存储或多或少三天的事件。

副本集的工作原理

下图显示了应用程序查询三节点副本集的典型环境。

在正常操作期间,副本集只有一个节点作为PRIMARY而所有其他节点都是SECONDARY。PRIMARY成员是唯一接收写入的成员。它更新其本地集合和文档以及oplog。然后,oplog事件通过复制通道发送到所有SECONDARY节点。每个SECONDARY节点在本地和异步上应用对本地数据和oplog的相同修改。

下图在内部显示了副本集的工作原理。每个节点都连接到所有其他节点,并且有一个心跳机制来ping任何其他节点。心跳具有用于ping节点的可配置时间,默认值为10秒。

如果所有节点都响应心跳确认,则群集继续工作。如果其中一个节点崩溃,例如PRIMARY(最坏的情况),则发生涉及剩余节点的选举

当SECONDARY在配置的超时后没有收到对心跳的响应时,它会要求进行选举。仍然存活的节点投票支持新的PRIMARY。选举阶段通常不需要很长时间,选举算法足够复杂,让他们选择最佳的次要成为新的主要。让我们说这是次要的,与死亡的初级主要是最新的。

除了主要崩溃之外,还有一些节点要求进行选举的情况:将节点添加到副本集时,在“启动副本集”期间或在某些维护活动期间。这种选举不是本文的目的。

副本集在选举成功完成之前无法处理写入操作,但如果将此类查询配置为在辅助节点上运行,则可以继续提供读取查询(稍后我们将对此进行讨论)。选举正确完成后,群集将恢复正常操作。

要正常工作,副本集需要具有奇数个成员。在网络分裂的情况下,只有奇数个成员确保我们在其中一个子集中拥有大多数投票。在具有大多数节点的子集中选择新的PRIMARY。

因此,三个是副本集的最小节点数,以确保高可用性。

仲裁节点

由于每个节点都需要拥有完整的数据副本,因此如果您拥有庞大的数据库,则需要提供至少三台具有大量磁盘,内存和CPU资源的计算机。这可能很昂贵。

幸运的是,您可以将其中一个节点配置为Arbiter,这是一个不复制数据的特殊成员。它是空的,但它可以在选举期间投票。

使用仲裁节点是维持奇数成员的一个很好的解决方案,而不需要花费很多钱来使第三个节点像其他节点一样强大。仲裁节点不能被选为新主节点,因为它没有数据。

环境

ip 主机名 系统
172.18.11.142 nodejs1 Centos 7.6
172.18.11.143 nodejs2 Centos 7.6
172.18.11.144 nodejs3 Centos 7.6

安装

# 下载安装包并安装
mkdir -p /opt/mongodb/
cat <<EOF > /opt/mongodb/mongodb_down.sh
cd /opt/mongodb/
wget https://www.percona.com/downloads/percona-server-mongodb-LATEST/percona-server-mongodb-4.0.9-4/binary/redhat/7/x86_64/percona-server-mongodb-shell-4.0.9-4.el7.x86_64.rpm
wget https://www.percona.com/downloads/percona-server-mongodb-LATEST/percona-server-mongodb-4.0.9-4/binary/redhat/7/x86_64/percona-server-mongodb-mongos-4.0.9-4.el7.x86_64.rpm
wget https://www.percona.com/downloads/percona-server-mongodb-LATEST/percona-server-mongodb-4.0.9-4/binary/redhat/7/x86_64/percona-server-mongodb-tools-4.0.9-4.el7.x86_64.rpm
wget https://www.percona.com/downloads/percona-server-mongodb-LATEST/percona-server-mongodb-4.0.9-4/binary/redhat/7/x86_64/percona-server-mongodb-server-4.0.9-4.el7.x86_64.rpm
wget https://www.percona.com/downloads/percona-server-mongodb-LATEST/percona-server-mongodb-4.0.9-4/binary/redhat/7/x86_64/percona-server-mongodb-4.0.9-4.el7.x86_64.rpm
EOF bash -x /opt/mongodb/mongodb_down.sh
yum localinstall /opt/mongodb/*.rpm -y
systemctl enable mongod

主机名

cat <<EOF >> /etc/hosts
192.168.0.249 k8s-m1
192.168.0.250 k8s-n1
192.168.0.251 k8s-n2
EOF

配置文件

cat <<EOF > /etc/mongod.conf
storage:
dbPath: /var/lib/mongo
journal:
enabled: true
systemLog:
destination: file
logAppend: true
path: /var/log/mongo/mongod.log
processManagement:
fork: true
pidFilePath: /var/run/mongod.pid
net:
port: 27017
bindIp: 0.0.0.0
EOF

启动

systemctl start mongod

副本集的名称

副本集的名称这里使用 rs-smy,将副本集名称放置于每一台主机的 /etc/mongod.conf

replication:
replSetName: "rs-smy"

重启所有服务器

systemctl restart mongod

初始化集群

随便连接到一个节点,发出 rs.initiate() 让副本集直到有哪些成员

rs.initiate( {
_id: "rs-smy",
members: [
{ _id: 0, host: "172.18.11.142:27017" },
{ _id: 1, host: "172.18.11.143:27017" },
{ _id: 2, host: "172.18.11.144:27017" }
] })

发出命令后,MongoDB使用默认配置启动复制过程。选择PRIMARY节点,现在将创建的所有文档将在SECONDARY节点上异步复制。

我们可以通过查看mongo shell提示符来验证复制是否正常。一旦副本集启动并运行,提示应该在PRIMARY节点上如下:

rs-smy:PRIMARY>

在SECONDARY节点上这样:

rs-test:SECONDARY>

一些有用的命令

有几个命令可以调查并在副本集上执行一些管理任务。这里有几个。

要调查副本集配置,您可以在任何节点上发出rs.conf()

rs-smy:SECONDARY> rs.conf()
{
"_id" : "rs-smy",
"version" : 1,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 0,
"host" : "172.18.11.142:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : { },
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "172.18.11.143:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : { },
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "172.18.11.144: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("5ce54845de4f73c1e97ea042")
}
}

我们可以看到有关已配置节点的信息,无论是仲裁还是隐藏,优先级以及有关心跳过程的其他详细信息。

要调查副本集状态,您可以在任何节点上发出rs.status()

s-smy:SECONDARY> rs.status()
{
"set" : "rs-smy",
"date" : ISODate("2019-05-23T10:12:44.663Z"),
"myState" : 2,
"term" : NumberLong(7),
"syncingTo" : "172.18.11.144:27017",
"syncSourceHost" : "172.18.11.144:27017",
"syncSourceId" : 2,
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1558606360, 1),
"t" : NumberLong(7)
},
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1558606360, 1),
"t" : NumberLong(7)
},
"appliedOpTime" : {
"ts" : Timestamp(1558606360, 1),
"t" : NumberLong(7)
},
"durableOpTime" : {
"ts" : Timestamp(1558606360, 1),
"t" : NumberLong(7)
}
},
"lastStableCheckpointTimestamp" : Timestamp(1558606350, 1),
"members" : [
{
"_id" : 0,
"name" : "172.18.11.142:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 24733,
"optime" : {
"ts" : Timestamp(1558606360, 1),
"t" : NumberLong(7)
},
"optimeDate" : ISODate("2019-05-23T10:12:40Z"),
"syncingTo" : "172.18.11.144:27017",
"syncSourceHost" : "172.18.11.144:27017",
"syncSourceId" : 2,
"infoMessage" : "",
"configVersion" : 1,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "172.18.11.143:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 24523,
"optime" : {
"ts" : Timestamp(1558606360, 1),
"t" : NumberLong(7)
},
"optimeDurable" : {
"ts" : Timestamp(1558606360, 1),
"t" : NumberLong(7)
},
"optimeDate" : ISODate("2019-05-23T10:12:40Z"),
"optimeDurableDate" : ISODate("2019-05-23T10:12:40Z"),
"lastHeartbeat" : ISODate("2019-05-23T10:12:44.463Z"),
"lastHeartbeatRecv" : ISODate("2019-05-23T10:12:44.448Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "172.18.11.144:27017",
"syncSourceHost" : "172.18.11.144:27017",
"syncSourceId" : 2,
"infoMessage" : "",
"configVersion" : 1
},
{
"_id" : 2,
"name" : "172.18.11.144:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 24519,
"optime" : {
"ts" : Timestamp(1558606360, 1),
"t" : NumberLong(7)
},
"optimeDurable" : {
"ts" : Timestamp(1558606360, 1),
"t" : NumberLong(7)
},
"optimeDate" : ISODate("2019-05-23T10:12:40Z"),
"optimeDurableDate" : ISODate("2019-05-23T10:12:40Z"),
"lastHeartbeat" : ISODate("2019-05-23T10:12:44.464Z"),
"lastHeartbeatRecv" : ISODate("2019-05-23T10:12:44.433Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1558594808, 1),
"electionDate" : ISODate("2019-05-23T07:00:08Z"),
"configVersion" : 1
}
],
"ok" : 1,
"operationTime" : Timestamp(1558606360, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1558606360, 1),
"signature" : {
"hash" : BinData(0,"eo6zfAdAzzCTw/rQj+OWbd7Vots="),
"keyId" : NumberLong("6693835933885661186")
}
}
}

可以看到哪个是PRIMARY,哪个是SECONDARY

测试复制

连接到PRIMARY节点并创建例子:

rs-smy:PRIMARY> use test
switched to db test
rs-test:PRIMARY> db.foo.insert( {name:"Bruce", surname:"Dickinson"} )
WriteResult({ "nInserted" : 1 })
rs-smy:PRIMARY> db.foo.find().pretty()
{
"_id" : ObjectId("5ae05ac27e6680071caf94b7")
"name" : "Bruce"
"surname" : "Dickinson"
}

然后连接到SECONDARY节点并查找相同的文档。

请记住,您无法连接到SECONDARY节点以读取数据。默认情况下,只允许在PRIMARY上进行读写操作。因此,如果要读取SECONDARY节点上的数据,首先需要发出rs.slaveOK()命令。如果您不这样做,您将收到错误。

rs-test:SECONDARY> rs.slaveOK()
rs-test:SECONDARY> show collections
local
<strong>foo</strong>
rs-test:SECONDARY> db.foo.find().pretty()
{
"_id" : ObjectId("5ae05ac27e6680071caf94b7")
"name" : "Bruce"
"surname" : "Dickinson"
}

SECONDARY节点已经复制了集合foo和插入文档的创建。

Percona MongoDB 4 搭建副本集的更多相关文章

  1. MongoDB集群搭建-副本集

    MongoDB集群搭建-副本集 概念性的知识,可以参考本人博客地址: 一.Master-Slave方案: 主从: 二.Replica Set方案: 副本集: 步骤:(只要按步骤操作,100%成功) 1 ...

  2. MongoDB 搭建副本集

    副本集(Replica Set)是一组MongoDB实例组成的集群,由一个主(Primary)服务器和多个备份(Secondary)服务器构成.通过Replication,将数据的更新由Primary ...

  3. MongoDB主从复制和副本集

    MongoDB有主从复制和副本集两种主从复制模式,主从复制最大的问题就是无法自动故障转移,MongoDB副本集解决了主从模式无法自动故障转义的特点,因此是复制的首选.对于简单的主从复制无法自动故障转移 ...

  4. MongoDB-3.4搭建副本集

    搭建副本集 1:首先创建3台虚拟机作为配置环境 IP1:192.168.101.175 IP2:192.168.101.176 IP3:192.168.101.177 2.下载MongoDB 3.4版 ...

  5. 【六】MongoDB管理之副本集

    一.复制介绍 所谓的复制就是在多个主机之间同步数据的过程. 1.数据冗余及可用性 复制技术提供数据冗余及可用性,在不同的数据库服务器上使用多个数据副本,复制技术防止单个数据库服务器出现数据故障而出现数 ...

  6. MongoDB 复制(副本集)学习

    MongoDB 复制(副本集)学习 replication set复制集,复制集,多台服务器维护相同的数据副本,提高服务器的可用性.MongoDB复制是将数据同步在多个服务器的过程.复制提供了数据的冗 ...

  7. mongodb 4.0副本集搭建

    近期有同学问mongodb副本集难不难部署,我的回答是不难,很快,几分钟搞定,比mysql MHA简单的不止一点半点. 那么到底如何部署呢?请看下文. 1.  准备工作 1.1 下载软件 选择版本并下 ...

  8. mongodb安装及副本集搭建

    mongodb下载地址:https://www.mongodb.com/dr/fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel62-3.2.7.tg ...

  9. MongoDB 副本集搭建 & 副本集扩容

    副本集的搭建 创建多实例目录 [root@redis03 ~]# mkdir /server/mongodb/2801{7,8,9}/{conf,logs,pid,data} -p 编辑多实例配置文件 ...

随机推荐

  1. 中crontab定时器里的"2>&1"含义解释

    */1 * * * * /usr/local/php/bin/php posts.php >> /data/logs/audit_bbsposts.log 2>&1 & ...

  2. 为lumen添加session支持

    为lumen添加session支持,同时配置全局函数csrf_token可用 首先laravel和lumen框架的版本要一致,我这里版本都是5.4 1.复制laravel框架config目录下的ses ...

  3. Gitlab-Runner基础教程

    一.Intro jenkins和runner,作为主流自动化运维工具来说,两者的大思路其实是一样的,就是将我们提交到代码仓库的代码拉到jenkins或者runner运行的机器里,然后执行一系列的命令( ...

  4. 最近忙科研立项 & 对博客的优化

    最近一直在忙科研立项.... 立项书 & 答辩 ... 接下来,将对博客进行优化... (1) 依据书来学习的[需要大量截图],将用微软的 OneNote 写笔记,然后打包成pdf,上传到我的 ...

  5. linux 自定义函数

    用别人的车子出行,总感觉别扭,那怎么自定义自己的车轮子呢? 通过上面的求两个参数的和例子,我们可以学到定义一个函数基本的步骤, function getSum(){  SUM=$[$n1+$n2]  ...

  6. CrawlerRunner没有Log输出

    官网log说明:https://docs.scrapy.org/en/latest/topics/logging.html#scrapy.utils.log.configure_logging 这里记 ...

  7. T100——作业单身网格消失,查询时单身无法输入

    增加代码:

  8. Mysql-Sqlalchemy-ORM-many_to_many

    orm_m2m.py from sqlalchemy import Table,Column,Integer,String,DATE, ForeignKey from sqlalchemy.orm i ...

  9. [IOI2005]Riv河流

    题目链接:洛谷,BZOJ 前置知识:莫得 题解 直接考虑dp.首先想法是设状态 \(dp[u][i]\) 表示u的子树内建 \(i\) 个伐木场且子树内木头都运到某个伐木场的最小花费.发现这样的状态是 ...

  10. 微信小程序上传图片及本地测试

    前端(.wxml) <view id="view1"> <view id="btns"> <image id="ima1 ...