MongoDB复制集
1)什么是复制集 Replica Set
MongDB 像MySQL一样,支持类似的主从复制架构,但无法实现自动故障转移,所以官方推荐使用复制集 MongoDB复制集是将数据同步在多个服务器的过程 复制集提供了数据的冗余备份,并在多个服务器上存储数据副本,保证数据的安全性 复制集还允许从硬件故障和服务中断中恢复数据。当故障时,会自动选举新master节点,实现集群的高可用
复制集功能
-
数据高可用性
-
异地容灾,实现灾难恢复
-
无需停机维护(如备份,重建索引,压缩)
-
分布式读取数据,读操作的负载均衡
1.1)复制集架构
主节点记录在其上的所有操作oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一客户端写入数据到主节点时, 主节点与从节点进行数据交互保障数据的一致性
复制集特征:
-
N 个奇数节点的集群
-
基于选举机制,任何节点可作为主节点
-
所有写入操作都在主节点上,所以增加节点不会提高系统写性能,可以提升读性能
-
主节点故障时,会自动选举出新节点代替,自动故障转移
多个节点数据同步的实现
-
当一个修改操作,无论是插入、更新或删除,到达主节点时,它对数据的操作将被记录下来(经过一些必要的转换)这些记录称为opl0g
-
从节点通过在主节点上打开一个talable游标不断获取新进入主节点的oplog,并在自己的数据上回放,以此保持跟主节点的数据一致
2)复制集实现(7.0.17版本)
2.1)复制集环境规划
复制集要求三个以上的 MongoDB节点或者实例
192.168.139.161 主 192.168.139.162 从 192.168.139.163 从
2.2)三个主机安装 mongodb
root@mongdb-1:~# systemctl is-active mongod.service
active
root@mongdb-2:~# systemctl is-active mongod.service
active
root@mongdb-3:~# systemctl is-active mongod.service
active
2.3)修改配置文件
三个节点都要配置
# vim /mongodb/conf/mongo.conf
...
replication:
replSetName: myrepl # 指定复制集名称
# systemctl restart mongod.service
# wget https://downloads.mongodb.com/compass/mongosh-2.4.0-linux-x64.tgz
# tar xf mongosh-2.4.0-linux-x64.tgz -C /
2.4)配置复制集: 1主2从
其中一个节点执行即可
root@mongdb-1:~# /mongosh-2.4.0-linux-x64/bin/mongosh
test> config = { _id: 'myrepl', members: [
{_id: 0, host: '192.168.139.161:27017'},
{_id: 1, host: '192.168.139.162:27017'} ,
{_id: 2, host: '192.168.139.163:27017'}]
}
test> rs.initiate(config)
myrepl [direct: secondary] test> # 配置成功
# 验证master
myrepl [direct: secondary] test> rs.isMaster()
{
topologyVersion: {
processId: ObjectId('67c703f7477d36a6a40833e5'),
counter: Long('6')
},
hosts: [
'192.168.139.161:27017',
'192.168.139.162:27017',
'192.168.139.163:27017'
],
setName: 'myrepl',
setVersion: 1,
ismaster: true,
secondary: false,
primary: '192.168.139.161:27017',
.....
注意:如果是低版本 从节点默认不通过读能力需要在从节点执行下面命令
> rs.secondaryOk()
2.5)验证数据同步
root@mongdb-1:~# apt install python3-pip
root@mongdb-1:~# pip3 install pymongo
root@mongdb-1:~# cat test_mongodb.py
from pymongo import MongoClient
# 客户端连接
client = MongoClient('mongodb://127.0.0.1:27017')
# 指定数据库 # Database类
db = client['test']
# 集合 # Collection类
students = db['students']
for i in range(10):
student = {'id':i, 'name':'tang' + str(i), 'age':20}
result = students.insert_one(student)
print(result)
client.close()
root@mongdb-1:~# chmod +x test_mongodb.py
root@mongdb-1:~# ./test_mongodb.py
# 主节点验证数据
myrepl [direct: primary] test> db.students.estimatedDocumentCount()
10
myrepl [direct: primary] test> db.students.find().limit(1)
[
{
_id: ObjectId('67c7089e1e6458ed9a071a3f'),
id: 0,
name: 'tang0',
age: 20
}
]
# 从节点验证数据
myrepl [direct: secondary] test> use test
already on db test
myrepl [direct: secondary] test> db.students.estimatedDocumentCount()
10
myrepl [direct: secondary] test> db.students.find().limit(1)
[
{
_id: ObjectId('67c7089e1e6458ed9a071a3f'),
id: 0,
name: 'tang0',
age: 20
}
]
2.6)模拟主节点损坏
root@mongdb-1:~# systemctl stop mongod.service
# 随便找一个好的节点验证主切换
myrepl [direct: secondary] test> rs.isMaster()
{
topologyVersion: {
processId: ObjectId('67c703eafecf0b18aaa446c7'),
counter: Long('5')
},
hosts: [
'192.168.139.161:27017',
'192.168.139.162:27017',
'192.168.139.163:27017'
],
setName: 'myrepl',
setVersion: 1,
ismaster: false,
secondary: true,
primary: '192.168.139.162:27017', # 发现主切换为了 192.168.139.162
# 登录新主插入数据
yrepl [direct: primary] test> for(i=0;i<1000;i++){db.teacher.insert({uid:i, name: "tang"+i, "age":18, "date": new Date() })}
# 验证数据
myrepl [direct: primary] test> db.teacher.estimatedDocumentCount()
1000
myrepl [direct: primary] test> db.teacher.find().limit(2)
[
{
_id: ObjectId('67c70c7c3ecde7a40851e944'),
uid: 0,
name: 'tang0',
age: 18,
date: ISODate('2025-03-04T14:21:48.810Z')
},
{
_id: ObjectId('67c70c7c3ecde7a40851e945'),
uid: 1,
name: 'tang1',
age: 18,
date: ISODate('2025-03-04T14:21:48.836Z')
}
]
# 从节点验证数据
myrepl [direct: secondary] test> db.teacher.find().limit(2)
[
{
_id: ObjectId('67c70c7c3ecde7a40851e944'),
uid: 0,
name: 'tang0',
age: 18,
date: ISODate('2025-03-04T14:21:48.810Z')
},
{
_id: ObjectId('67c70c7c3ecde7a40851e945'),
uid: 1,
name: 'tang1',
age: 18,
date: ISODate('2025-03-04T14:21:48.836Z')
}
]
# 启动之前手动停止的主节点
root@mongdb-1:~# systemctl start mongod.service
root@mongdb-1:~# /mongosh-2.4.0-linux-x64/bin/mongosh
# 查询数据 # 这个主已经变为了从
myrepl [direct: secondary] test> db.teacher.find().limit(2)
[
{
_id: ObjectId('67c70c7c3ecde7a40851e944'),
uid: 0,
name: 'tang0',
age: 18,
date: ISODate('2025-03-04T14:21:48.810Z')
},
{
_id: ObjectId('67c70c7c3ecde7a40851e946'),
uid: 2,
name: 'tang2',
age: 18,
date: ISODate('2025-03-04T14:21:48.842Z')
}
] # 可以看出 节点恢复 数据又自动同步
2.7) 在新加一个从节点
192.168.139.164
# 在 192.168.139.164 安装mongodb
root@mongdb-4:~# systemctl is-active mongod.service
active
root@mongdb-4:~# vim /mongodb/conf/mongo.conf
# 修改配置文件
...
replication:
replSetName: myrepl # 指定复制集名称 需要和加入复制集的节点配置一致
root@mongdb-4:~# systemctl restart mongod.service
#### 在 primary 节点添加新从节点
myrepl [direct: primary] test> rs.add("192.168.139.164:27017")
{
ok: 1,
....
#### 验证节点是否加入
myrepl [direct: primary] test> rs.isMaster()
{
topologyVersion: {
processId: ObjectId('67c703ef69f6b34927fa5a7d'),
counter: Long('9')
},
hosts: [
'192.168.139.161:27017',
'192.168.139.162:27017',
'192.168.139.163:27017',
'192.168.139.164:27017'
],
setName: 'myrepl',
setVersion: 3,
ismaster: true,
secondary: false,
primary: '192.168.139.162:27017',
....
#### 在 192.168.139.164 主机验证数据是否复制到新节点
myrepl [direct: secondary] test> db.teacher.find().limit(2)
[
{
_id: ObjectId('67c70c7c3ecde7a40851e944'),
uid: 0,
name: 'tang0',
age: 18,
date: ISODate('2025-03-04T14:21:48.810Z')
},
{
_id: ObjectId('67c70c7c3ecde7a40851e945'),
uid: 1,
name: 'tang1',
age: 18,
date: ISODate('2025-03-04T14:21:48.836Z')
}
] # 数据已经复制
2.8)删除节点
# 在 primary 节点执行
myrepl [direct: primary] test> rs.remove("192.168.139.164:27017")
{
ok: 1,
...
myrepl [direct: primary] test> rs.isMaster()
{
topologyVersion: {
processId: ObjectId('67c703ef69f6b34927fa5a7d'),
counter: Long('10')
},
hosts: [
'192.168.139.161:27017',
'192.168.139.162:27017',
'192.168.139.163:27017'
],
setName: 'myrepl',
setVersion: 4,
ismaster: true,
secondary: false,
primary: '192.168.139.162:27017',
...
3)配置复制集:1主1从1Arbiter
3.1)复制集环境规划
192.168.139.161 主
192.168.139.162 从
192.168.139.163 Arbiter (仲裁节点)
3.2)三个主机安装 mongodb
root@mongdb-1:~# systemctl is-active mongod.service
active
root@mongdb-2:~# systemctl is-active mongod.service
active
root@mongdb-3:~# systemctl is-active mongod.service
active
3.3)修改配置文件
三个节点都要配置
# vim /mongodb/conf/mongo.conf
...
replication:
replSetName: myrepl # 指定复制集名称
# systemctl restart mongod.service
# wget https://downloads.mongodb.com/compass/mongosh-2.4.0-linux-x64.tgz
# tar xf mongosh-2.4.0-linux-x64.tgz -C /
3.4)配置复制集: 1主1从1Arbiter
其中一个节点执行即可
root@mongdb-1:~# /mongosh-2.4.0-linux-x64/bin/mongosh
test> config = { _id: 'myrepl', members: [
{_id: 0, host: '192.168.139.161:27017'},
{_id: 1, host: '192.168.139.162:27017'} ,
{_id: 2, host: '192.168.139.163:27017',"arbiterOnly": true}]
}
test> rs.initiate(config)
myrepl [direct: secondary] test> # 配置成功
# 验证master
myrepl [direct: secondary] test> rs.isMaster()
{
topologyVersion: {
processId: ObjectId('67c71566ad8426acd52cd14a'),
counter: Long('3')
},
hosts: [ '192.168.139.161:27017', '192.168.139.162:27017' ],
arbiters: [ '192.168.139.163:27017' ], # 仲裁节点
setName: 'myrepl',
setVersion: 1,
ismaster: false,
secondary: true,
me: '192.168.139.161:27017',
.....
注意:如果是低版本 从节点默认不通过读能力需要在从节点执行下面命令
> rs.secondaryOk()
3.5)特殊从节点管理
arbiter节点:主要负责选主过程中的投票,但是不存储任何数据,也不提供任何服务
hidden节点:隐藏节点,不参与选主,也不对外提供服务。
delay节点:延时节点,数据落后于主库一段时间,因为数据是延时的,也不应该提供服务或参与选主,所以通常会配合hidden(隐藏),可用于防止逻辑删除,一股情况下会将delay+hidden一起配置使用,配置延时节点(一般延时节点也配置成hidden)
优先级为0的节点的特点
此节点丧失了当选Primary的机会。永远不会上位
此节点虽然不能当选Primary但是却可以投票
此节点正常参与Primary产生的oplog的读取,进行数据备份和命令执行
此节点正常参与客户端对于数据的读取,进行担当负载均衡的工作
范例:实现特殊节点功能
#在主节点执行下面操作配置特殊节点并保存
config=rs.conf() #定义变量
config.members[3].hidden=true #设置hidden,3表示第4个成员,从0开始表示第1个,是rs.confO)显示的顺序,不是_id的值
config.members[3l.priority=0 #优先级0表示不参选master,但可以投票,值越大优先级越高
config.members[3l.arbiterOnly=true #也可将延时节点配置为arbiter节点
config.members[3].slaveDelay=120 #延时时长,以秒为单位,生产可延时3-6小时
config.members[3].votes=0 #持有票数为0
rs.reconfig(config) #加载配罚
文章评论