共计 13032 个字符,预计需要花费 33 分钟才能阅读完成。
自动写代码机器人,免费开通
这篇文章给大家介绍 MongoDB 中复制集集群的原理是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
复制集介绍
MongoDB 中的复制集 (也被称为副本) 是一组维护相同数据集的 mongod 进程。副本集提供冗余性及和高可用,是所有生产部署的基础。简单来说,复制集有多台 MongoDB 组成的一个集群,集群中有一个主节点 (Primary) 和 N 个副本节点 (Secondary) 等,它们有相同的数据库,假如主 MongoDB 服务器或者 MongoDB 实例 Down 机之后,其它的副本服务器可以继续提供服务,实现数据的高可用及可靠性。
复制集群架构
术语介绍:
术语类型描述 Primary 主节点负责整个集群的读写操作,包含了所有改变操作的日志 Secondary 备节点同步主服务器所有的数据,负责集群的读取请求,主服务器宕机可以称为主节点 Arbiter 仲裁者在主节点宕机后只进行投票,不参与选举,不同步主节点数据
此架构由一个 Primary 节点和两个 Secondary 节点组成
1)Primary 节点为主节点,所有的写操作或者更改操作都只能从 Primary 节点中操作(复制集内的所有成员都可以接收读操作,但是,默认情况下,应用程序将其读操作指向主成员),主节点上所有的更改及写操作都会记录到 oplog 日志中。
2)两台 Secondary 节点复制 Primary 节点的 oplog 日志,通过异步的方式去执行 oplog 日志中的记录来和 Primary 节点达到数据一致性。
3)oplog 作用主要是记录主节点的写入操作,充当复制源。
4)如果 Primary 节点无故 Down 机之后,复制集集群会通过投票机制在两台 Secondary 中选举一台升级为 Primary 节点。
投票选举机制
MongoDB 节点之间维护心跳检查,主节点选举由心跳触发。
心跳检查 MongoDB 复制集成员会向自己之外的所有成员发送心跳并处理响应信息,因此每个节点都维护着该节点看到的其它所有节点的状态信息,节点根据自己的集群状态判断是否需要更新新的 Primary。在实现的时候主要由两个异步的过程分别处理心跳响应和超时,每个复制集成员都会在后台运行与复制集所有节点的心跳线程,在以下几种情况下会触发状态检测过程:
bull;Secondary 节点权重 (Priority) 比 Primary 节点高时,发起替换选举;
bull;Secondary 节点发现集群中没有 Primary 时,发起选举;
bull;Primary 节点不能访问到大部分成员时主动降级,降级操作会断开连接,终止用户请求等;
bull; 复制集成员心跳检测结果发生变化,比如某个节点挂了或者新增节点,发起重新投票选举规则;
bull; 超过 4s 没有执行状态检测过程,发起替换选举;
选举发起 发起选举的节点首先需要做一些条件判断,维护主节点的有 N 个备用节点,备用节点中的所有节点都可能被选举成为主节点,成为主节点前每个备节点都会检测自身以及全局条件是否满足,检测条件如下:
1. 是否看见复制集中是否有 Majority 在线
2. 自身 Priority 是否大于 0
3. 自身不为 arbiter
4. 自身 opTime 不能落后于最新节点 10s 以上
5. 自身存储的集群程序按信息为最新
如果所有条件满足,则将自身添加到主节点的备用列表中,否则,将自身从列表中移除
自身检测
bull;MongoDB 选举需要获得大多数投票才能通过,如果没有节点投反对票,且获得成票数超过有权投票节点总数的 1 /2,则能成为 Primary。否则进入下一轮选举。为避免陷入无限重复选举,MongoDB 建议复制集的成员个数为奇数,当 Secondary 为双数时,可以增加一个 Arbiter 节点。
bull; 选举过程中,复制集没有主节点,所有成员都是只读状态
bull; 选举过程很复杂,一般情况下需要 5s 左右进行选主。
bull; 如果新选择的主节点立刻挂掉,至少需要 30s 时间重新选主。
大多数的定义 假设复制集内投票成员数量为 N,则大多数 = N/2 + 1,当复制集内存活成员数量不足大多数时,整个复制集将无法选举出 Primary,复制集将无法提供写服务,处于只读状态。我们按照上面的架构来举例,三台 MongoDB,一台 Primary,两台 Secondary,主节点挂了之后,只有两台 Secondary 可以投票,根据公式我们来算“2/2 + 1 = 2”,也就是算大多数等于 2,但是当复制集内存活的成员数量不足大多数时,我们的大多数为 2,集群成员也为 2,所以这两台集群成员会发起选举投票机制,如果两台 Secondary 节点自身条件都满足的情况下,则先发起选举节点的成员成为 Primary 节点
投票成员数大多数容忍失效数 110220321431532642743
复制集群成员说明
Secondary 正常情况下,复制集的 Seconary 会参与 Primary 选举(自身也可能会被选为 Primary),并从 Primary 同步最新写入的数据,以保证与 Primary 存储相同的数据。Secondary 可以提供读服务,增加 Secondary 节点可以提供复制集的读服务能力,同时提升复制集的可用性。另外,Mongodb 支持对复制集的 Secondary 节点进行灵活的配置,以适应多种场景的需求。
Arbiter Arbiter 节点只参与投票,不能被选为 Primary,并且不从 Primary 同步数据。比如你部署了一个 2 个节点的复制集,1 个 Primary,1 个 Secondary,任意节点宕机,复制集将不能提供服务了(无法选出 Primary),这时可以给复制集添加一个 Arbiter 节点,即使有节点宕机,仍能选出 Primary。Arbiter 本身不存储数据,是非常轻量级的服务,当复制集成员为偶数时,最好加入一个 Arbiter 节点,以提升复制集可用性。
Priority0 Priority0 节点的选举优先级为 0,不会被选举为 Primary。比如你跨机房 A、B 部署了一个复制集,并且想指定 Primary 必须在 A 机房,这时可以将 B 机房的复制集成员 Priority 设置为 0,这样 Primary 就一定会是 A 机房的成员。(注意:如果这样部署,最好将『大多数』节点部署在 A 机房,否则网络分区时可能无法选出 Primary)
Vote0 Mongodb 3.0 里,复制集成员最多 50 个,参与 Primary 选举投票的成员最多 7 个,其他成员(Vote0)的 vote 属性必须设置为 0,即不参与投票。
Hidden Hidden 节点不能被选为主(Priority 为 0),并且对 Driver 不可见。因 Hidden 节点不会接受 Driver 的请求,可使用 Hidden 节点做一些数据备份、离线计算的任务,不会影响复制集的服务。
Delayed Delayed 节点必须是 Hidden 节点,并且其数据落后与 Primary 一段时间(可配置,比如 1 个小时)。因 Delayed 节点的数据比 Primary 落后一段时间,当错误或者无效的数据写入 Primary 时,可通过 Delayed 节点的数据来恢复到之前的时间点。
优先级为 0 复制集成员
此架构由一个 Primary 节点和两个 Secondary 节点组成
1)此架构由一台 Primary 主节点和两台 Secondary 备节点组成,其原理就是主从复制架构的原理,两台 Secondary 节点同样通过 oplog 日志来与 Primary 主节点达成数据一致
2)与其不同的是在 Data Center2 节点上的 Secondary 备用节点的实例优先级 priority 为 0,则不参与选举,也不可能会成为 Primary 节点,将其优先级配置为 0,主要是防止它成为主节点,这在多数据中心的部署特别有用。
3)优先级值范围为 0-100(0 表示不参与选举),在复制集群中,优先级高的优先成为主节点,假如我们原来集群中有三台节点,主节点优先级为 2,其它两台备节点优先级为 1,当我们新加入到集群一台 MongoDB 实例,给它优先级设置为 4,则该实例在加入集群后就会自动抢夺 Primary 到本机。
仲裁节点架构
上图中,三个成员组成复制集群
一个主库:负责整个集群的所有写、更改操作
一个从库:通过 oplog 日志来与主节点数据达成一致
一个 Airbiter 节点,在选举中,只进行投票,不能成为主库,而且不复制 Primary 的任何数据,因此这个架构中只能提供一个完成的副本 Secondary,Arbiter 只需要很少的资源,代价是有限的冗余和容错,当 Primary 节点故障后,Aribiter 将票数头给 Secondary,使其成为 Primary 节点,如果 Primary 节点再次故障后,集群将不可用,Arbiter 节点也未存储任何数据。
集群中还有其它的节点成员,但是我们用的比较少,所以此文章中没有提到。可以自行查阅官方文档:https://docs.mongodb.com/manual/core/replica-set-members/
复制集集群环境部署
环境说明
本次使用一台设备多实例进行,如果你准备在多台设备上部署,你需要考虑的如下:1)时钟是否一致 2)网络是否通畅 3)SElinux 是否关闭或者策略放通 4)环境是否一致
[root@MongoDB ~]# lsb_release -a LSB Version: :core-4.1-amd64:core-4.1-noarch:cxx-4.1-amd64:cxx-4.1-noarch:desktop-4.1-amd64:desktop-4.1-noarch:languages-4.1-amd64:languages-4.1-noarch:printing-4.1-amd64:printing-4.1-noarch Distributor ID: CentOS Description: CentOS Linux release 7.6.1810 (Core) Release: 7.6.1810 Codename: Core [root@MongoDB ~]# hostname -I 10.211.55.12 192.168.0.100 fdb2:2c26:f4e4:0:21c:42ff:fedf:4d85
前期准备
# 创建用户组 useradd mongod echo abcdef | passwd --stdin mongod #下载 MongoDB wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.2.0.tgz # 添加文件打开数和 mongod 用户进程连接数 cat /etc/security/limits.conf EOF * soft nofile 65536 * hard nofile 65536 mongod soft nproc 32768 mongod hard nproc 32768 EOF # 使下面两个文件修改为 never echo never /sys/kernel/mm/transparent_hugepage/enabled echo never /sys/kernel/mm/transparent_hugepage/defrag # 开机自动修改 cat /etc/rc.local EOF if test -f /sys/kernel/mm/transparent_hugepage/enabled;then echo never /sys/kernel/mm/transparent_hugepage/enabled fi if test -f /sys/kernel/mm/transparent_hugepage/defrag;then echo never /sys/kernel/mm/transparent_hugepage/defrag fi EOF 此步骤完成后 #官方给出 MongoDB 需要以下两个库的依赖 yum install libcurl openssl -y #解压并复制程序文件到 bin 目录 mkdir /usr/local/mongodb tar xf mongodb-linux-x86_64-rhel70-4.2.0.tgz cp -rf mongodb-linux-x86_64-rhel70-4.2.0/bin/ /usr/local/mongodb/ chown -Rf mongod.mongod /usr/local/moongodb/ # 添加程序环境 cat /etc/profile EOF export MONGODB_HOME=/usr/local/mongodb export PATH=\$MONGODB/bin:\$PATH EOF source /etc/profile
环境配置
1)接下来使用 mongod 用户来操作
su mongod
2)创建文件目录
#!/bin/bash for i in 27017 27018 27019 do mkdir -p /usr/local/mongodb/$i/{conf,data,logs,run} done
配置文件
编辑一台配置文件,然后复制到其它实例,配置文件为 yaml 语法 关于以下配置文件详解,请参考:”https://abcops.cn/mongodb-conf/“
cat mongod.conf EOF systemLog: destination: file path: /usr/local/mongodb/27017/logs/mongodb.log logAppend: true verbosity: 0 logRotate: rename storage: journal: enabled: true dbPath: /usr/local/mongodb/27017/data directoryPerDB: true engine: wiredTiger wiredTiger: engineConfig: cacheSizeGB: 1 directoryForIndexes: true journalCompressor: zlib collectionConfig: blockCompressor: zlib indexConfig: prefixCompression: true processManagement: fork: true pidFilePath: /usr/local/mongodb/27017/run/mongod.pid net: port: 27017 bindIp: 10.211.55.12 maxIncomingConnections: 65536 wireObjectCheck: true ipv6: false replication: oplogSizeMB: 4096 replSetName: abcops_repl setParameter: connPoolMaxShardedConnsPerHost: 200 connPoolMaxConnsPerHost: 200 EOF
复制配置文件到目录中,并修改其端口及目录位置
#!/bin/bash for i in 27017 27018 27019 do \cp /home/mongod/mongod.conf /usr/local/mongodb/$i/conf sed -i s/27017/$i/g /usr/local/mongodb/$i/conf/mongod.conf done
启动 MongoDB 实例
启动脚本如下
#!/bin/bash for i in 27017 27018 27019 do /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/$i/conf/mongod.conf done
关闭脚本如下
#!/bin/bash for i in 27017 27018 27019 do /usr/local/mongodb/bin/mongod --shutdown -f /usr/local/mongodb/$i/conf/mongod.conf done
三个实例启动后,不代表复制集已经搭建成功了,还需要进行复制集初始化
配置复制集
连接任何一个实例都可以进行配置
这是我连接 27017 的实例 /usr/local/mongodb/bin/mongo --host 10.211.55.12 --port 27017
use admin config={ _id: abcops_repl , members:[ {_id: 0, host: 10.211.55.12:27017 ,priority:2}, {_id: 1, host: 10.211.55.12:27018 ,priority:1}, {_id: 2, host: 10.211.55.12:27019 ,arbiterOnly:true}, ] } rs.initiate(config) # 以上参数解析 use admin:进入 admin 数据库 config:配置复制集 _id: abcops_repl:指定复制集组名称,与配置文件中的 replSetName 参数需要保持一致 members:规定的函数,不能更改 _id:设置组成员的 ID 编号,可以自定义,我这里为 0、1、2 host:指定加入复制集成员的 IP 地址及端口,我们在配置文件中指定了 bindIp 为 10.211.55.12,这里就不能写 127.0.0.1, 必须写为 bind_Ip 指定的地址 priority:指定优先级 0 -100,优先级最高的成为 Primary 节点,优先级为可选选项,如果不指定默认都为 1 arbiterOnly:是否开启仲裁节点 true/false rs.initiate(config):初始化复制集配置
以上参数图示如下,给你提供下参照
图中开始为 SECONDARY, 代表复制集集群正在进行选举 Primary 节点,大概 5s 左右,根据选举机制选举成功后,成为主节点的 SECONDARY 状态变为 PRIMARY
复制集常用命令
1)查看谁是主节点
abcops_repl:PRIMARY db.isMaster()
2)查看当前复制集集群中成员的配置
abcops_repl:PRIMARY rs.conf()
3)查看复制集集群成员状态
abcops_repl:PRIMARY rs.status()
4)新增节点到复制集 新增节点之前,该实例的配置中的 replSetName 复制集名称,必须和集群一致
abcops_repl:PRIMARY rs.add(10.211.55.12:27020)
5)新增仲裁节点
abcops_repl:PRIMARY rs.addArb(10.211.55.12:27020)
6)从复制集内删除节点
abcops_repl:PRIMARY rs.remove(10.211.55.12:27020)
7)检查 oplog 日志时间和大小
abcops_repl:PRIMARY rs.printReplicationInfo() configured oplog size: 4096MB log length start to end: 2422secs (0.67hrs) oplog first event time: Wed Sep 11 2019 12:22:13 GMT+0800 (CST) oplog last event time: Wed Sep 11 2019 13:02:35 GMT+0800 (CST) now: Wed Sep 11 2019 13:02:37 GMT+0800 (CST)
8)降级服务器 此操作只能在 PRIMARY 上操作 通过执行 rs.stepDown 命令将当前主服务器主动降级为备用节点,120 单位为 s,为 120 秒内这个实力不能把自己选为 PRIMARY 角色,120 秒后由于它本身的优先级较高,所以会重新抢占 PRIMARY 节点。
abcops_repl:PRIMARY rs.stepDown(120)
9)允许在 Secondary 节点可以进行查询 在副本节点上操作
rs.slaveOk()
10)查看当前连接
db.getMongo()
修改优先级
修改 27018 的优先级为 3,使其优先级超过 27017 实例,夺得 PRIMARY 角色,此操作需在 PRIMARY 上执行
abcops_repl:PRIMARY config=rs.conf() abcops_repl:PRIMARY config.members[1].priority=3 3 abcops_repl:PRIMARY rs.reconfig(config) { ok : 1, $clusterTime : { clusterTime : Timestamp(1568179129, 1), signature : { hash : BinData(0, AAAAAAAAAAAAAAAAAAAAAAAAAAA=), keyId : NumberLong(0) } }, operationTime : Timestamp(1568179129, 1) } abcops_repl:PRIMARY rs.conf()
abcops_repl:SECONDARY db.isMaster() # 以上参数解析 config=rs.conf():将现有的配置读取到变量中进行存储 config.members[1].priority=3:修改变量中的值,1 是指执行 rs.conf()中看到节点的顺序,不是 ID 号哦,rs.conf()看到的顺序是从 0 开始排序,三个副本集排序就是 0 -3 rs.reconfig(config):将修改后的数据同步到配置,使修改生效 rs.conf():查看当前配置,可以看到优先级哦 db.isMaster():查看谁是 Primary 节点
复制测试
1)插入数据
#连接当前 Primary 节点 /usr/local/mongodb/bin/mongo --host 10.211.55.12 --port 27018 # 进入 abcops 数据库,在 documents 文档中插入以下 JSON 格式的数据 abcops_repl:PRIMARY use abcops abcops_repl:PRIMARY db.documents.insert( {name: xuweiliang , age: 25, Job: DevOps} ) # 查看 documents 文档中的数据 abcops_repl:PRIMARY db.documents.find() { _id : ObjectId( 5d78863768fbf9eac4704232), name : xuweiliang , age : 25, Job : DevOps } # 查看复制节点状态 abcops_repl:PRIMARY rs.printSlaveReplicationInfo() source: 10.211.55.12:27017 syncedTo: Wed Sep 11 2019 13:30:42 GMT+0800 (CST) 0 secs (0 hrs) behind the primary
2)登录 Secondary 节点查看
/usr/local/mongodb/bin/mongo --host 10.211.55.12 --port 27017 abcops_repl:SECONDARY rs.slaveOk()
# 运行副本节点可进行查询 abcops_repl:SECONDARY show dbs # 查看当前节点的数据库 abcops 0.000GB admin 0.000GB config 0.000GB local 0.000GB abcops_repl:SECONDARY use abcops #abcops 数据库已经从主节点同步至此 switched to db abcops abcops_repl:SECONDARY db.getCollectionNames() # 以下连续三个命令都是查看进入到 abcops 库中的文档命令 [ documents ] abcops_repl:SECONDARY show collections documents abcops_repl:SECONDARY show tables documents abcops_repl:SECONDARY db.documents.find() # 查看文档中的内容 { _id : ObjectId( 5d78863768fbf9eac4704232), name : xuweiliang , age : 25, Job : DevOps }
创建复制集中的账户
1)连接到主节点,创建用户 以下创建的用户及权限和角色请参考下面用户权限说明
/usr/local/mongodb/bin/mongo --host 10.211.55.12 --port 27018 abcops_repl:PRIMARY use admin abcops_repl:PRIMARY db.createUser( { user: abcops , pwd: 123456 , roles:[ { role: root , db: admin } ] } ) Successfully added user: { user : abcops , roles : [ { role : root , db : admin } ] } # 查看所有创建的用户信息 abcops_repl:PRIMARY show users
用户中权限的说明
权限说明 Read 允许用户读取指定数据库 readWrite 允许用户读写指定数据库 dbAdmin 允许用户在指定数据库中指定管理函数,如(索引创建、删除、查看统计访问 system.profile)userAdmin 允许用户向 system.users 集合写入,可以找指定数据里面创建、删除和管理用户 clusterAdmin 只在 admin 数据库中可用,赋予用户所有分片和复制集相关函数的管理权限 readAnyDatabase 只在 admin 数据库中可用,赋予用户所有数据库的读权限 readWriteAnyDatabase 只在 admin 数据库中可用,赋予用户所有数据库的读写权限 userWriteAnyDatabase 只在 admin 数据库中可用,赋予用户所有数据库的 userAdmin 权限 dbAdminAnyDatabase 只在 admin 数据库中可用,赋予用户所有数据库的 dbAdmin 权限 root 只在 admin 数据库中可用,超级管理员
为复制集集群添加权限认证
复制集我们这里采用 keyfile 文件实现权限认证,并且副本集中的所有成员使用的 keyfile 必须一样
添加安全认证配置
三台实例必须都要配置
cat /usr/local/mongodb/27017/conf/mongod.conf EOF security: authorization: enabled clusterAuthMode: keyFile keyFile: /usr/local/mongodb/27017/conf/keyfile javascriptEnabled: true EOF cat /usr/local/mongodb/27018/conf/mongod.conf EOF security: authorization: enabled clusterAuthMode: keyFile keyFile: /usr/local/mongodb/27018/conf/keyfile javascriptEnabled: true EOF cat /usr/local/mongodb/27019/conf/mongod.conf EOF security: authorization: enabled clusterAuthMode: keyFile keyFile: /usr/local/mongodb/27019/conf/keyfile javascriptEnabled: true EOF
keyfile 文件操作
1)生产 keyfile 文件
openssl rand -base64 90 ./keyfile
2)复制 keyfile 文件到其它实例中
#!/bin/bash for i in 27017 27018 27019 do \cp /home/mongod/keyfile /usr/local/mongodb/$i/conf/ done
3)修改 keyfile 权限 keyfile 文件权限必须为 X00,不能给 group 和 other 成员分配任何权限,否则实例无法启动
#!/bin/bash for i in 27017 27018 27019 do chmod 400 /usr/local/mongodb/$i/conf/keyfile done
4)重启所有实例
#!/bin/bash for i in 27017 27018 27019 do /usr/local/mongodb/bin/mongod --shutdown -f /usr/local/mongodb/$i/conf/mongod.conf sleep 3s /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/$i/conf/mongod.conf done
认证验证
登录验证可以在连接的时候指定用户名和密码,也可以先连接到数据库后再进行认证
1)登录指定用户密码
/usr/local/mongodb/bin/mongo --host 10.211.55.12 --port 27018 --username abcops -p 123456 abcops_repl:PRIMARY show dbs abcops 0.000GB admin 0.000GB config 0.000GB local 0.000GB
2)先登录,后验证
abcops_repl:PRIMARY use admin # 必须要先切换到 admin 库中才可以进行进行验证 switched to db admin abcops_repl:PRIMARY db.auth( abcops , 123456 ) # 认证用户名及密码,认证成功返回 1,否则返回 0 1 abcops_repl:PRIMARY show dbs abcops 0.000GB admin 0.000GB config 0.000GB local 0.000GB abcops_repl:PRIMARY db admin
3)在备库进行验证 备库只能进行查询,勿要在备库上进行任何操作
/usr/local/mongodb/bin/mongo --host 10.211.55.12 --port 27017 abcops_repl:SECONDARY rs.slaveOk()
abcops_repl:SECONDARY use admin switched to db admin abcops_repl:SECONDARY db.auth(abcops , 123456) 1
客户端验证
我们可以找一台 SQL 管理工具来连接该库
可以看到我创建的 abcops 库和一个文档及三个字段
关于 MongoDB 中复制集集群的原理是什么就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
向 AI 问一下细节