Mongo副本集和PBM备份

Mongo副本集和PBM备份

数据库同步的备份场景主要有:

  1. 实时同步,主从同步,以实现读写分离和实时切换主从,提供性能和高可用
  2. 历史版本留存,将数据库的写操作延迟后写入延迟数据库,以达到恢复到可用时间点的效果
  3. 分片集群,用于快速扩容,适用于大规模数据。

数据库备份层面:

  • 逻辑备份
  • 物理备份
  • 增量备份
  • 快照备份

Mongo副本集实现主从同步

简单介绍:

实现效果:只需一个主节点、一个从节点、一个从节点PSS(或者一个仲裁节点PSA),在进行配置成功后,主节点若在宕机的情况下,一个从节点将会被选举成为新的主节点,从而继续工作。

仲裁节点的用处是添加一个票数,因为Mongo选举需要有2/3的票数,且需保证存活的结点是2/3,否则将复制集将不可用。

SpringBoot配置文件配置:spring.data.mongodb.uri=mongodb://admin:123456@172.16.60.1:27019,172.16.60.2:27019,172.16.60.3:27020/aaim-backend?authSource=admin&connect=replicaSet&readPreference=secondaryPreferred&replicaSet=rs0

第一步:安装docker和上传相关镜像(镜像包和docker安装包可从129服务器/home/uvi/docker目录获取)

#(@@)安装docker略

# 将和原服务器版本相同的mongo镜像包上传至/home/uvi/software下

mkdir -p /home/uvi/docker-image

cd /home/uvi/docker-image

#(@@)使用ssh工具或者跳板机上传文件

#将包转换为docker镜像

docker load -i xxx.tar

#查看镜像

docker images

第二步:生成相关前提文件和开启防火墙

#创建mongo挂在目录

mkdir -p /data/mongo-secondary

mkdir -p /data/mongo-arbiter

#(@@)从原服务器上复制一份密码的文件过来

#生成密钥文件

openssl rand -base64 741 > mongodb-keyfile

chmod 600 mongodb-keyfile

#(@@)创建的密钥文件拷贝到其他各节点的相同路径下,mongo5替换成对应mongo仓库的名字

mv mongodb-keyfile /data/mongo-secondary/keyfile/

mv mongodb-keyfile /data/mongo-arbiter/keyfile/

#开启防火墙 (Ubuntu使用ufw,Centos使用firewalld)

ufw allow 27017/tcp

ufw reload

ufw status verbose | grep 27017 查看端口开放情况

firewall-cmd --zone=public --add-port=27017/tcp --permanent

firewall-cmd --reload

firewall-cmd --list-ports | grep 27017

第三步:备份服务器docker-compose配置从节点和仲裁节点(主节点添加command和network_mode和 - /data/mongo-secondary/keyfile这一行)

#从原mongo的docker配置出粘贴一份docker-compose.yaml文件到新服务器处

#例如

version: '3'

services:

mongo-secondary:

image: mongo:5.0.21

restart: always

container_name: mongo-secondary

ports:

- "27019:27017" #端口自由配置

environment:

- MONGO_INITDB_ROOT_USERNAME=admin

- MONGO_INITDB_ROOT_PASSWORD_FILE=/run/secrets/mongo_password

- TZ=Asia/Shanghai

command: mongod --keyFile /opt/keyfile/mongodb-keyfile --bind_ip_all --replSet rs0

# Mount database file

volumes:

- /data/mongo-secondary:/data/db

- /data/mongo-secondary/keyfile:/opt/keyfile

logging:

driver: json-file

options:

max-size: 100m

max-file: '5'

network_mode: bridge

secrets:

- mongo_password

mongo-arbiter:

image: mongo:5.0.21

restart: always

container_name: mongo-arbiter

ports:

- "27020:27017" #端口自由配置

environment:

- MONGO_INITDB_ROOT_USERNAME=admin

- MONGO_INITDB_ROOT_PASSWORD_FILE=/run/secrets/mongo_password

- TZ=Asia/Shanghai

command: mongod --keyFile /opt/keyfile/mongodb-keyfile --bind_ip_all --replSet rs0

# Mount database file

volumes:

- /data/mongo-arbiter:/data/db

- /data/mongo-arbiter/keyfile:/opt/keyfile

network_mode: bridge

logging:

driver: json-file

options:

max-size: 100m

max-file: '5'

secrets:

- mongo_password

# MONGODB PASSWORD CONFIG

secrets:

mongo_password:

file: ./mongo_password.txt

第四步:重启Mongo并配置副本集

配置前重要数据的备份:cp -r /{各医院mongo容器对应的数据挂载目录} /{各医院mongo容器对应的数据挂载目录的父目录}/bak1/

数据恢复:

mv /{各医院mongo容器对应的数据挂载目录} /{各医院mongo容器对应的数据挂载目录的父目录}/bak2/

mv /{各医院mongo容器对应的数据挂载目录} /{各医院mongo容器对应的数据挂载目录的父目录}/bak1/

mv /{各医院mongo容器对应的数据挂载目录的父目录}/bak1/ /{各医院mongo容器对应的数据挂载目录}

副本集初始化没问题则删除多余备份文件:

rm -rf /{各医院mongo容器对应的数据挂载目录的父目录}/bak1/

恢复没问题则删除多余备份文件:

rm -rf /{各医院mongo容器对应的数据挂载目录的父目录}/bak2/

rm -rf /{各医院mongo容器对应的数据挂载目录的父目录}/bak1/

#启动从节点和仲裁节点

docker compose up -d mongo-secondary

docker compose up -d mongo-arbiter

#在从节点和仲裁节点以及主节点上互相使用(包括自己ping自己,因为可能会出现容器内无法访问宿主机的问题)下面的命令进行测试连接

#(!!!)在重启主节点前务必先检验在各个结点上能否连接通其余结点,否则重启后,复制集不生效,甚至原库也不能访问

docker exec mongo-secondary mongosh -u admin -p 123456 --eval 'db.runCommand({ ping: 1 })' "mongodb://{ip}:{port}"

#重启容器(旧版本的docker compose使用docker-compose,新的使用docker compose)

docker rm -f mongo5

docker compose up -d mongo5

#进入主节点(原数据库)容器内数据库

docker exec -it mongo5 mongosh admin

>db.auth("admin", "123456")

#执行副本集初始化,一定要等待其初始化完毕

>rs.initiate({

_id: "rs0",

members: [

{ _id: 0, host: "172.16.60.1:27019", priority: 2 },

{ _id: 1, host: "172.16.60.2:27019", priority: 1 },

{ _id: 2, host: "172.16.60.3:27020", priority: 0, arbiterOnly: true }

]

})

#初始化完毕后查看副本集状态

>rs.status()

#当看到主库变为PRIMARY状态时即初始化副本集成功,从节点状态为STARTUP或STARTUP2状态时,表示该从节点正在同步主库,可能需要半小时到1小时的时间,才会变为SECONDARY状态

第五步:重启后端服务

docker restart xxx-backend

附:意外情况处理

#当备份服务器宕机后,两个节点都会挂掉,此时复制集和主节点也不可用

#恢复办法是去掉command这一行,重新启动mongo,让其以单节点方式启动。

command: mongod --keyFile /opt/keyfile/mongodb-keyfile --bind_ip_all --replSet rs0

PBM实现历史版本留存

第一步:在备份服务器上传相关镜像并生成相关文件

#(@@)将镜像包上传至/home/uvi/software

#将包转换为docker镜像

docker load -i xxx.tar

#创建备份文件目录和日志目录

mkdir -p /data/backups/data

mkdir /data/backups/logs

chmod -R 777 /data/backups/data

chmod -R 777 /data/backups/logs

#这里有点迷(建议先跳过,后面权限不够再来),0是root用户,不授权也成功了,999是docker组Id,下面这个授权也不对,权限不足的时候再试试其他授权,或者把目录删了,重新建

chown -R 0:0 /data/backups/data

chown -R 1000:999 /data/backups/logs

第二步:创建用于备份和恢复的用户

>db.getSiblingDB("admin").createRole({ "role": "pbmadminRole",

"privileges": [

{ "resource": { "anyResource": true },

"actions": [ "anyAction" ]

}

],

"roles": []

})

>db.getSiblingDB("admin").createUser({user: "pbmadmin",

"pwd": "uvi_admin",

"roles" : [

{ "db" : "admin", "role" : "readWrite", "collection": "" },

{ "db" : "admin", "role" : "backup" },

{ "db" : "admin", "role" : "clusterMonitor" },

{ "db" : "admin", "role" : "restore" },

{ "db" : "admin", "role" : "pbmadminRole" }

]

});

第三步:docker-compose添加pbm容器配置(一个结点需要配备一个pbm,最好分别在两台服务器上部署一个pbm,分开的话secondary就去掉,都叫pbm了)

-secondary pbm:

image: percona/percona-backup-mongodb:latest

container_name: pbm

restart: always

command: pbm-agent -f /etc/pbm-config.yaml

environment:

- PBM_MONGODB_URI=mongodb://pbmadmin:123456@172.16.60.1:27019/?authSource=admin&replicaSet=rs0&readConcernLevel=local&w=1

volumes:

- /data/backups/data:/backups # 持久化备份文件

- /data/logs:/logs

- /home/uvi/db-deploy/pbm-config.yaml:/etc/pbm-config.yaml # 配置文件

network_mode: bridge

pbm-secondary:

image: percona/percona-backup-mongodb:latest

container_name: pbm-secondary

restart: always

command: pbm-agent -f /etc/pbm-secondary-config.yaml

environment:

- PBM_MONGODB_URI=mongodb://pbmadmin:123456@172.16.60.1:27019/?authSource=admin&replicaSet=rs0&readConcernLevel=local&w=1

volumes:

- /data/backups/data:/backups # 持久化备份文件

- /data/backups/logs:/logs

- /home/uvi/db-deploy/pbm-secondary-config.yaml:/etc/pbm-secondary-config.yaml # 配置文件

network_mode: bridge

第四步:配置pbm-agent

mongodb-uri: mongodb://pbmadmin:123456@172.16.60.1:27019/?authSource=admin&replicaSet=rs0&readConcernLevel=local&w=1

storage:

type: filesystem

filesystem:

path: /backups

backup:

priority: #选择备份结点的优先级

- "172.16.60.1:27019": "2"

- "172.16.60.2:27020": "1"

- "172.16.60.3:27020": "0"

# compression: s2 # 备份压缩类型,s2 是默认的压缩方式

timeouts:

startingStatus: 30 #半分钟的等待备份时间,默认33秒

oplogSpanMin: 10 #备份的oplog切片大小,默认10,若高负载情况下,可适当减小该值,以减轻DB的负载,但这会总在备份

# numParallelCollections: #并行的集合数,默认是CPU核心的一半

pitr: #时间点恢复

enabled: true

oplogSpanMin: 1 #增量时间,默认10分钟

# compression: s2 #默认s2,速度快压缩少,gzip速度慢,压缩大,snappy,lz4,pgzip,zstd

# compressionLevel: 1 压缩等级

oplogOnly: true #是否启动只保存opLog,而不完全base backup(完全备份)

priority: #拉取opLog结点的优先级

- "172.16.60.1:27019": "2"

- "172.16.60.2:27020": "1"

- "172.16.60.3:27020": "0"

#restore:

# batchSize: 500 #缓存的文档大小,默认500,默入工作者的数量

# numParallelCollections: #并行的集合数,默认是CPU核心的一半

# numDownloadWorkers: # 存储块请求数据的工作者数量,默认CPU的核心数

# maxDownloadBufferMb: #请求备份数据的缓存大小,默认 numDownloadWorkers * downloadChunkMb * 16

# downloadChunkMb: 32 # 请求备份数据块的大小

# numInsertionWorkers: 10 #每个集合并发的

# mongodLocation: #物理恢复时使用的 mongod 二进制文件的路径

# mongodLocationMap: mongo在每个结点上的mongod路径

log:

path: "/logs/pbm.json"

level: "I"

json: true

mongodb-uri: mongodb://pbmadmin:123456@172.16.60.1:27019/?authSource=admin&replicaSet=rs0&readConcernLevel=local&w=1

storage:

type: filesystem

filesystem:

path: /backups

backup:

priority: #选择备份结点的优先级

- "172.16.60.1:27019": "2"

- "172.16.60.2:27020": "1"

- "172.16.60.3:27020": "0"

# compression: s2 # 备份压缩类型,s2 是默认的压缩方式

timeouts:

startingStatus: 30 #半分钟的等待备份时间,默认33秒

oplogSpanMin: 10 #备份的oplog切片大小,默认10,若高负载情况下,可适当减小该值,以减轻DB的负载,但这会总在备份

# numParallelCollections: #并行的集合数,默认是CPU核心的一半

pitr: #时间点恢复

enabled: true

oplogSpanMin: 1 #增量时间,默认10分钟

# compression: s2 #默认s2,速度快压缩少,gzip速度慢,压缩大,snappy,lz4,pgzip,zstd

# compressionLevel: 1 压缩等级

oplogOnly: true #是否启动只保存opLog,而不完全base backup(完全备份)

priority: #拉取opLog结点的优先级

- "172.16.60.1:27019": "2"

- "172.16.60.2:27020": "1"

- "172.16.60.3:27020": "0"

#restore:

# batchSize: 500 #缓存的文档大小,默认500,默入工作者的数量

# numParallelCollections: #并行的集合数,默认是CPU核心的一半

# numDownloadWorkers: # 存储块请求数据的工作者数量,默认CPU的核心数

# maxDownloadBufferMb: #请求备份数据的缓存大小,默认 numDownloadWorkers * downloadChunkMb * 16

# downloadChunkMb: 32 # 请求备份数据块的大小

# numInsertionWorkers: 10 #每个集合并发的

# mongodLocation: #物理恢复时使用的 mongod 二进制文件的路径

# mongodLocationMap: mongo在每个结点上的mongod路径

log:

path: "/logs/pbm.json"

level: "I"

json: true

第五步:启动pbm

#启动pbm

docker compose up -d pbm pbm-secondary

#查看pbm是否正常启动,如果没出现restarting的状态说明启动成功

docker ps | grep pbm

#若未正常启动,可查看日志

docker logs pbm --tail 10

#启动成功后,可查看pbm状态

docker exec pbm pbm status

#进行一次全量备份(逻辑备份,物理备份只支持Percona Server for Mongodb,Mongo社区版和企业版均不支持)

docker exec pbm pbm backup

#查看pbm日志

tail -f /data/backup/logs/pbm.json

第六步:PBM单体不提供自动备份功能,可通过crond脚本之类的或者Percona Operator for MongoDB.

由于Percon Operator for MongoDB需要Kubernates环境,所以建议使用crond调度(只需在一台服务器上就可以了)

# 创建调度文件

touch /home/uvi/db-deploy/backup.sh

# 编辑脚本内容

# 授权

chmod +x /home/uvi/db-deploy/backup.sh

# 创建调度任务

crontab -e

#输入调度时间和调度脚本,每两天执行一次

0 3 */2 * * /home/uvi/db-deploy/backup.sh

#所有工作完成

#!/bin/bash

# 设置日志文件路径

LOG_FILE="/data/backups/auto_backup.log"

# 获取当前日期,格式为 yyyy-mm-dd

CURRENT_DATE=$(date +%F)

# 获取当前时间,格式为 yyyy-mm-dd HH:MM:SS

CURRENT_TIME=$(date +"%Y-%m-%d %H:%M:%S")

# 将执行时间写入日志

echo "[$CURRENT_TIME] 开始执行pbm全量备份..." >> $LOG_FILE

# 进行pbm全量备份

echo "[$CURRENT_TIME] 执行pbm全量备份" >> $LOG_FILE

docker exec pbm pbm backup --wait >> $LOG_FILE 2>&1

# 记录备份完成的时间

CURRENT_TIME=$(date +"%Y-%m-%d %H:%M:%S")

echo "[$CURRENT_TIME] pbm全量备份完成" >> $LOG_FILE

# 清理超过5天的备份

echo "[$CURRENT_TIME] 开始执行pbm清理,删除超过5天的备份..." >> $LOG_FILE

docker exec pbm pbm cleanup --older-than=5d -y --wait >> $LOG_FILE 2>&1

# 记录清理完成的时间

CURRENT_TIME=$(date +"%Y-%m-%d %H:%M:%S")

echo "[$CURRENT_TIME] 过时备份清理完成" >> $LOG_FILE

# 完成日志

echo "[$CURRENT_TIME] 备份和清理过程完成" >> $LOG_FILE

读写分离

介绍:SpringData的框架自动实现了读写分离。

注意:主库到从库的同步会有延迟,在手麻系统中,应该尽量避免读到过时数据,mongo提供了写操作的相关设置:

通过writeConcern指定REPLICA_ACKNOWLEDGED(2,2000),2台节点全部写确认成功后才返回,设置了2秒的等待超时,可以根据复制集群数来指定节点数和等待超时时间。

相关命令

  1. 4.4.22版本的登录mongo使用docker exec -it mongo mongo admin,5.0.21版本使用docker exec -it mongo mongosh admin
  2. pbm list 查看备份历史列表
  3. pbm backup 手动备份(无选项默认逻辑备份)

-t physical 物理全备

-t logical 逻辑备份

-t incremental --base 增量备份

  1. pbm cleanup 删除过时备份

--older-than=TIMESTAMP 删除早于这个时间的

-w 阻塞命令行直到完成

-y 不用询问

  1. pbm delete-backup 删除指定备份(用法跟pbm cleanup 差不多,多一个--type指定类型)
  2. pbm delete-pitr 删除时间点恢复

-a 删除所有

--older-than=TIMESTAMP 删除早于这个时间的

  1. pbm restore 恢复数据

--external 恢复其他的pbm的备份数据

--time=TIME 恢复数据到指定时间点

-w 阻塞等待完成

--wait-time 等待恢复的时间

--base-snapshot 指定基准备份,新版本pbm如果需要从物理方式恢复备份,则需要指定这个选项,否则会默认从最近的一个备份恢复

--replset-remapping 当恢复时,如果想要改变副本集的名称,或者从不同的副本集恢复数据时,可以使用此选项进行映射。

--ns=<database.collection> 恢复备份时,你可以选择只恢复某些特定的数据库或集合。

--with-users-and-roles 恢复用户和角色

-c 指定mongod.fonf路径

--ns-from="database.collection" 恢复集合原始名称

--ns-to="database.collection" 恢复集合的新名称

意外情况

  1. 启动pbm时日志产生如下报错

解决方法:降版本至2.8版本,将pbm-config.yaml删减为以下内容,docker-compose.yml修改为以下内容

storage:

type: filesystem

filesystem:

path: /backups

pitr: #时间点恢复

enabled: true

oplogSpanMin: 1 #增量时间,默认10分钟

oplogOnly: true #是否启动只保存opLog,而不完全base backup(完全备份)

version: '3'

services:

pbm:

image: percona/percona-backup-mongodb:2.8.0

container_name: pbm

restart: always

command:

- /bin/bash

- -c

- |

pbm config --file=/etc/pbm-config.yaml

pbm-agent

environment:

- PBM_MONGODB_URI=mongodb://pbmadmin:uvi_admin@172.17.249.124:27017/?authSource=admin&replicaSet=rs0&readConcernLevel=local&w=1

- LOG_LEVEL=I

- LOG_JSON=1

- LOG_PATH=/logs/pbm.json

volumes:

- /data/backups/data:/backups # 持久化备份文件

- /data/backups/logs:/logs

- /home/uvi/db-deploy/pbm-config.yaml:/etc/pbm-config.yaml # 配置文件

network_mode: bridge

验证主从复制

第一步对比数据库统计信息。分别在主节点和从节点上连接到要查看的数据库后,执行db.stats()命令,它会返回当前数据库的详细统计信息,包括数据库的大小(以字节为单位),对比主节点和从节点的数据是否一致。

#选择数据库

use uc-dayuan

#返回当前数据库的详细统计信息

db.stats()

这个 db.stats() 命令的输出结果提供了关于 uc-dayuan 数据库的很多有用信息,以下是对各字段的详细解释:

db:表示当前操作的数据库名称,这里是 "uc-dayuan"。

collections:数据库中集合的数量,这里有 28 个集合。

views:数据库中视图的数量,此数据库中视图数量为 0。

objects:数据库中所有集合中文档的总数,这里是 242258 个文档。

avgObjSize:平均每个文档的大小(以字节为单位),这里平均每个文档大小约为 14683.216144 字节。

dataSize:数据库中所有文档占用的数据总大小(以字节为单位),这里是 3555658255 字节。

storageSize:数据库在磁盘上占用的存储总大小(以字节为单位),为 902742016 字节。

indexes:数据库中所有集合上索引的总数,这里有 28 个索引。

indexSize:所有索引占用的总大小(以字节为单位),是 6193152 字节。

totalSize:数据库的总大小,包括数据和索引,这里是 908935168 字节。

scaleFactor:存储引擎使用的比例因子,这里是 1。

fsUsedSize:数据库所在文件系统已使用的大小(以字节为单位),这里是 79447347200 字节。

第二步:抽样对比数据。如使用MongoDB Compass连接工具进行界面操作抽样对比数据,

1、抽样检查主节点与从节点集合中数据一致性(主要针对从节点第一次全量拷贝主节点数据时是否保证数据一致),设置抽样条件时,要确保抽取的数据能够代表整个数据集的特征,以提高发现潜在数据不一致问题的概率。

2数据差异情况:​

  • 新增数据:在对比结果中,若某行数据仅在主节点存在,而从节点不存在,该行会标记为 “Inserted in source”。​
  • 删除数据:若某行数据仅在从节点存在,而主节点不存在,该行会标记为 “Deleted in source”。​
  • 数据修改:若某行数据在主从节点都存在,但字段值不同,该行会标记为 “Updated in source”,并详细显示字段的新旧值对比。
posted @ 2025-07-18 14:08  炸天帮达令  阅读(28)  评论(0)    收藏  举报