数据库备份和恢复
概述
利用 barman 实现数据备份和恢复,AntDB 团队对 barman 做了部分优化,增强了 barman 的功能。
可实现的功能包括:
- 归档管理
- 全量备份
- 增量备份
- 设置备份策略
- 本地备份
- 远程备份
- 压缩备份
- 全局一致性恢复
- 远程恢复
使用的时候需要确认:
- barman 所在主机到需要备份节点所在主机 ssh 免密
- 需要备份节点所在主机到 barman 所在主机 ssh 免密
- 各个节点的归档模式需要打开
- 各个节点的
wal log
需要归档到 barman 所在主机,并由 barman 管理。
barman的官方文档:http://docs.pgbarman.org/release/2.11/
创建 barrier
在集群版中,AntDB 通过 barrier 技术来实现全局一致性的恢复,因此需要定期在集群中创建 barrier,以便恢复的时候可以选择 barrier id 进行恢复。 建议通过 crontab 的方式,在集群中每分钟创建一个 barrier,创建 barrier 的操作不会对集群造成任何压力,放心使用。
连接 coordinator
或者 gtmcoord
创建 barrier:
antdb=# CRRATE BARRIER '20200831';
CLUSTER BARRIER 20200831
创建 barrier 的定时脚本,每分钟执行一次:
#!/bin/bash
# * * * * * sh create_barrier.sh >> /data/antdb/hostmon/log/create_barrier.log 2>&1
source /home/antdb/.bashrc
barrier_id=`date "+%Y_%m_%d_%H_%M" `
coordhost="10.1.226.201"
coordport="17322"
dbname="postgres"
psqlconn="psql -d $dbname -h $coordhost -p $coordport"
$psqlconn -c "create barrier '$barrier_id';"
if [ `echo $?` -eq 0 ]; then
echo `date "+%Y-%m-%d %H:%M:%S" ` "create barrier $barrier_id succuessed"
else
echo `date "+%Y-%m-%d %H:%M:%S" ` "create barrier $barrier_id failed"
fi
- 在可连接外网的主机上通过 pip 下载 barman 的依赖到本地文件夹并打包:
pip download -d /tmp/barman barman
pip download -d /tmp/barman argcomplete
tar zcvf barman.tar.gz barman
-
将 pip、setuptools、barman 的打包文件上传到离线环境,解压后安装:
源码安装 pip、setuptools
tar zxvf barman.tar.gz
tar zxvf pip-19.3.1.tar.gz
unzip setuptools-42.0.2.zip
cd pip-19.3.1 && sudo python setup.py install
cd ..
cd setuptools-42.0.2 && sudo python setup.py install
cd ..
- 通过 pip 离线安装 barman 的依赖:
sudo pip install --no-index --ignore-installed --find-links=barman barman
sudo pip install --no-index --ignore-installed --find-links=barman argcomplete
--find-links
指定 barman 打包文件解压后的路径。
源码安装 adb-barman
安装 barman 到当前用户:
unzip adb-barman-master.zip
cd adb-barman-master
./setup.py install --user
...
Installing barman script to /home/antdb/.local/bin
...
配置环境变量:
将 $HOME/.local/bin
加载到 $PATH
环境变量中。
export PATH=$ADBHOME/bin:$HOME/.local/bin$PATH:$HOME/bin:
检查 barma n的路径:
[antdb@localhost1 ~/barman]$ which barman
~/.local/bin/barman
barman 配置
barman 的配置文件分为两个:
- 一个是全局的: 全局相关一些参数可以在这个文件中配置,路径为:
~/.barman.conf
- 一个是节点的 节点相关的个性化参数可以在这个文件中配置,路径在全局配置的参数目录中。
在 barman 所在主机上规划好 barman 使用的目录,示例中假设备份数据存放挂载点为 /backup
。
创建相关目录
mkdir -p /backup/antdb/barman/{bin,conf,log,data}
- conf 存放每个备份节点的配置文件
- data 存放备份的数据
- log 存放备份日志
- bin 存放备份恢复用到的脚本
全局配置文件
配置文件的详细参数说明可以参考源码目录中的
adb-barma-master/doc/barman.conf
文件说明。
vi ~/.barman.conf
[barman]
barman_user = antdb
configuration_files_directory = /backup/antdb/barman/conf/
barman_home = /backup/antdb/barman/data/
log_file = /backup/antdb/barman/log/barman.log
compression = gzip
parallel_jobs =3
minimum_redundancy = 1
retention_policy = RECOVERY WINDOW OF 1 WEEKS
reuse_backup = link
需要根据实际情况修改如下参数:
- barman_user barman 程序的运行用户
- configuration_files_directory 节点配置文件的存放目录
- barman_home 节点备份数据的存放目录
- log_file barman 程序运行的主日志文件
- minimum_redundancy 最小保留的备份数量
- retention_policy 备份数据的保留策略
备份节点的配置文件
通常情况下,需要对集群中的 coordinator master
、gtmcoord master
、datanode maste
节点进行备份,配置文件示例如下:
[antdb@antdb06 conf]$ cat datanode_225m.conf
[datanode_225m]
description = "datanode master datanode_225m"
ssh_command = ssh antdb@134.78.9.256 -q
conninfo = host=134.78.9.256 port=24330 user=antdb dbname=postgres
backup_method = rsync
backup_options = exclusive_backup
parallel_jobs = 3
archiver = on
archiver_batch_size = 50
建议配置文件的文件名
、文件内容中的[]
标识、adbmgr 中的 nodename
均保持一致,方便识别。
- 如果使用集群版本,因节点较多,本节后面提供了脚本来批量生成
master
节点的配置文件。 - 如果使用单机版本,则直接编辑节点配置文件即可。
- 相同的参数,节点配置会覆盖全局配置。
检查节点配置
通过 barman check nodename
检查节点的配置文件后,会在 barman 的数据目录下生产以节点名称命名的文件夹:
[antdb@kpantdb06 data]$ barman check datanode_225m
Server datanode_225m:
PostgreSQL: OK
is_superuser: OK
wal_level: OK
directories: OK
retention policy settings: OK
backup maximum age: OK (no last_backup_maximum_age provided)
compression settings: OK
failed backups: OK (there are 0 failed backups)
minimum redundancy requirements: FAILED (have 0 backups, expected at least 1)
ssh: OK (PostgreSQL server)
not in recovery: OK
archive_mode: OK
archive_command: OK
continuous archiving: OK
archiver errors: OK
[antdb@kpantdb06 data]$ ll datanode_225m
total 192
drwxrwxr-x 2 antdb antdb 10 Dec 24 21:14 base
drwxrwxr-x 2 antdb antdb 10 Dec 24 21:14 errors
drwxrwxr-x 2 antdb antdb 135168 Dec 25 10:41 incoming
drwxrwxr-x 2 antdb antdb 10 Dec 24 21:14 streaming
drwxrwxr-x 3 antdb antdb 57 Dec 24 21:24 wals
[antdb@kpantdb06 data]$
集群版本中,节点较多,可以用 barman check all
进行全部节点的检查。
设置归档命令
增量备份需要使用归档文件,使用 barman
进行备份管理的话,就需要将各个节点的归档文件交给 barman
管理。
- 先获取节点的 incoming 目录:
[antdb@antdb06 conf]$ barman show-server datanode_225m |grep incoming_wals_directory
incoming_wals_directory: /backup/antdb/barman/data//datanode_225m/incoming
- 设置节点的归档命令
在设置归档命令之前,先确保节点的归档模式已经打开。
- 单机版本 管理员用户登录数据库,执行如下命令:
ALTER system SET archive_command='rsync -a %p antdb@kpantdb06:/backup/antdb/barman/data/datanode_225m/incoming/%f';
SELECT pg_reload_conf();
- 集群版本 登录
adbmgr
修改archive_command
:
SET DATANODE MASTER datanode_225m(archive_command='rsync -a %p antdb@kpantdb06:/backup/antdb/barman/data/datanode_225m/incoming/%f');
按照上面的步骤继续配置其他节点。
如果使用集群版本,因节点较多,本节后面提供了脚本来批量设置节点的归档命令。
检查节点的归档命令:
antdb=# SHOW param datanode_225m archive_command;
type | status | message
-------------------------------+--------+---------------------------------------------------------------------------------------------------
datanode master datanode_225m | t | archive_command = rsync -a %p antdb@kpantdb06:/backup/antdb/barman/data/datanode_225m/incoming/%f
datanode slave datanode_225s | t | archive_command = rsync -a %p antdb@kpantdb06:/backup/antdb/barman/data/datanode_225s/incoming/%f
(2 rows)
生成所有 master 节点配置文件
配置好脚本中的相关参数后,执行 sh barman-operate.sh generate_config
生成所有 master 节点的配置文件。执行完成后,到配置文件目录检查。
设置所有 master 节点的归档命令
配置文件检查无误后,执行 sh barman-operate.sh set_archive_cmd
设置所有 master 节点的归档命令。执行完成后,登录 adbmgr,执行 show param nodename archive_command
检查节点的归档命令设置是否正确。
强制日志切换
配置完成后,通过 barman 执行一次切换日志操作,确保节点可以正确归档:
barman switch-xlog --force --archive datanode_225m
集群版本中,节点较多,可以用 barman switch-xlog --force --archive all
进行全部节点的日志切换。
barman 配置脚本
#!/bin/bash
#sh barman_operate.sh generate_config|set_archive_cmd|backup_all
trans_nodetype(){
nodetype=$1
if [ "$nodetype" = "g" ]; then
echo "gtmcoord master"
elif [ "$nodetype" = "p" ]; then
echo "gtmcoord slave"
elif [ "$nodetype" = "c" ]; then
echo "coordinator master"
elif [ "$nodetype" = "d" ]; then
echo "datanode master"
elif [ "$nodetype" = "b" ]; then
echo "datanode slave"
fi
}
##只备份master节点,所以只给master节点生产配置文件。
generate_config(){
echo "将根据当前集群的最新结构生成master节点的配置文件"
sleep 3
for m_node in ${masternodes[@]}
do
hostuser=`echo $m_node |cut -f 1 -d '|'`
hostaddr=`echo $m_node |cut -f 2 -d '|'`
hostname=`echo $m_node |cut -f 3 -d '|'`
nodetype=`echo $m_node |cut -f 4 -d '|'`
nodetype=`trans_nodetype $nodetype `
nodename=`echo $m_node |cut -f 5 -d '|'`
nodeport=`echo $m_node |cut -f 6 -d '|'`
echo "$hostuser,$hostaddr,$hostname,$nodetype,$nodename,$nodeport"
cat > ${barman_home}/conf/${nodename}.conf << EOF
[${nodename}]
description = "$nodetype $nodename"
ssh_command = ssh ${hostuser}@${hostaddr} -q
conninfo = host=${hostaddr} port=${nodeport} user=${hostuser} dbname=postgres
backup_method = rsync
backup_options = exclusive_backup
parallel_jobs = 3
archiver = on
archiver_batch_size = 50
EOF
done
}
##为了防止节点切换后,new master 没来得及设置归档命令导致部分wal log丢失,所以在最开始就把所有节点的归档命令设置好。
set_archive_cmd(){
echo "将设置所有节点的归档命令到 barman 所在主机"
sleep 3
for node in ${nodes[@]}
do
nodename=`echo $node |cut -f 5 -d '|'`
nodetype=`echo $node |cut -f 4 -d '|'`
nodetype=`trans_nodetype $nodetype`
#echo "$nodename,$nodetype"
#echo "set $nodetype $nodename(archive_command = 'rsync -a %p $barman_user@$barman_host:$barman_home/data/$nodename/incoming/%f');"
psql -h $mgrhost -p $mgrport -d postgres << EOF
set $nodetype $nodename(archive_mode = on);
set $nodetype $nodename(archive_command = 'rsync -a %p $barman_user@$barman_host:$barman_home/data/$nodename/incoming/%f');
EOF
done
}
barman_backup_node(){
for m_node in ${masternodes[@]}
do
hostuser=`echo $m_node |cut -f 1 -d '|'`
hostaddr=`echo $m_node |cut -f 2 -d '|'`
hostname=`echo $m_node |cut -f 3 -d '|'`
nodetype=`echo $m_node |cut -f 4 -d '|'`
nodetype=`trans_nodetype $nodetype `
nodename=`echo $m_node |cut -f 5 -d '|'`
nodeport=`echo $m_node |cut -f 6 -d '|'`
logfile=${barman_home}/log/barman_backup_${nodename}.log
barman switch-xlog --force --archive $nodename
nohup barman backup --immediate-checkpoint $nodename >> $logfile 2>&1 &
done
}
barman_replay_resume(){
for m_node in ${masternodes[@]}
do
hostuser=`echo $m_node |cut -f 1 -d '|'`
hostaddr=`echo $m_node |cut -f 2 -d '|'`
hostname=`echo $m_node |cut -f 3 -d '|'`
nodetype=`echo $m_node |cut -f 4 -d '|'`
nodetype=`trans_nodetype $nodetype `
nodename=`echo $m_node |cut -f 5 -d '|'`
nodeport=`echo $m_node |cut -f 6 -d '|'`
echo "execute pg_wal_replay_resume on $nodetype $nodename"
psql -h $hostaddr -p $nodeport -d postgres -U $hostuser << EOF
select pg_wal_replay_resume();
EOF
done
}
usage(){
echo " usage:"
echo " sh $0 generate_config|set_archive_cmd|backup_all"
echo " generate_config : 生成 barman 配置文件"
echo " set_archive_cmd : 设置所有节点的归档命令"
echo " backup_all : 备份所有节点的数据"
echo " replay_resume : 恢复后在master节点上执行pg_wal_replay_resume()"
}
# var
barman_home="/backup/antdb/barman"
barman_host="server3"
barman_user="antdb"
mgrhost="server3"
mgrport=16655
alias mgrsql='psql "port=$mgrport host=$mgrhost dbname=postgres options='\''-c command_mode=sql'\''"'
nodesql="select host.hostuser||'|'||host.hostaddr||'|'||host.hostname||'|'||node.nodetype||'|'||node.nodename||'|'||node.nodeport from pg_catalog.mgr_node node, pg_catalog.mgr_host host where 1=1 and node.nodehost=host.oid order by node.nodename;"
nodes=`mgrsql -q -t -c "$nodesql"`
masternodesql="select host.hostuser||'|'||host.hostaddr||'|'||host.hostname||'|'||node.nodetype||'|'||node.nodename||'|'||node.nodeport from pg_catalog.mgr_node node, pg_catalog.mgr_host host where 1=1 and node.nodehost=host.oid and node.nodetype in ('g','d','c') order by node.nodename;"
masternodes=`mgrsql -q -t -c "$masternodesql"`
operate=$1
if [ "x"$operate == "xgenerate_config" ];then
generate_config
elif [ "x"$operate == "xset_archive_cmd" ];then
set_archive_cmd
elif [ "x"$operate == "xbackup_all" ];then
barman_backup_node
elif [ "x"$operate == "xreplay_resume" ];then
barman_replay_resume
else
echo " option is invalid"
usage
fi
注意修改脚本中的如下变量:
- barman_home
- barman_host
- barman_user
- mgrhost
- mgrport
数据备份
备份一个 datanode
如果有多个 datanode 需要备份,则需要分别执行这个命令。如果用户想要后期基于 barrier 点恢复,则需要在备份前,先登录到任意一个 coordinator 上,创建 barraier。
[antdb@localhost1 ~/barman]$ barman backup dm0
Starting backup using rsync-exclusive method for server dm0 in /home/antdb/barman/data/dm0/base/20190129T150740
Backup start at LSN: 0/1C000060 (000000010000000000000007, 00000060)
This is the first backup for server dm0
WAL segments preceding the current backup have been found:
000000010000000000000005 from server dm0 has been removed
Starting backup copy via rsync/SSH for 20190129T150740 (3 jobs)
Copy done (time: 2 seconds)
This is the first backup for server dm0
Asking PostgreSQL server to finalize the backup.
Backup size: 207.2 MiB. Actual size on disk: 207.2 MiB (-0.00% deduplication ratio).
Backup end at LSN: 0/1C000130 (000000010000000000000007, 00000130)
Backup completed (start time: 2019-01-29 15:07:41.584111, elapsed time: 3 seconds)
Processing xlog segments from file archival for dm0
000000010000000000000006
000000010000000000000007
000000010000000000000007.00000060.backup
查看某一节点所有备份数据
[antdb@localhost1 ~/barman]$ barman list-backup dm0
dm0 20190129T150740 mode: rsync-exclusive tar:None - Tue Jan 29 15:16:29 2019 - Size: 207.3 MiB - WAL Size: 0 B
查看某一个备份的详细信息,其中,20190129T150740 是 backup_id。
[antdb@localhost1 ~/barman]$ barman show-backup dm0 20190129T150740
Backup 20190129T150740:
Server Name : dm0
Status : DONE
PostgreSQL Version : 100004
PGDATA directory : /home/antdb/pgdata_xc/datanode/0
Base backup information:
Disk usage : 207.2 MiB (207.3 MiB with WALs)
Incremental size : 207.2 MiB (-0.00%)
Timeline : 1
Begin WAL : 000000010000000000000007
End WAL : 000000010000000000000007
WAL number : 1
WAL compression ratio: 99.89%
Begin time : 2019-01-29 15:16:25.814768+08:00
End time : 2019-01-29 15:16:29.837834+08:00
Copy time : 2 seconds
Estimated throughput : 86.0 MiB/s (3 jobs)
Begin Offset : 96
End Offset : 304
Begin LSN : 0/1C000060
End LSN : 0/1C000130
WAL information:
No of files : 0
Disk usage : 0 B
Last available : 000000010000000000000007
Catalog information:
Retention Policy : VALID
Previous Backup : - (this is the oldest base backup)
Next Backup : - (this is the latest base backup)
删除备份
命令:
barman cron
该命令会根据配置文件中的备份保留策略,删除过期、多余的备份。
例子:
[antdb@localhost1 ~]$ barman list-backup db1
db1 20170926T172835 - Tue Sep 26 17:30:07 2017 - Size: 410.6 MiB - WAL Size: 0 B
db1 20170926T172728 - Tue Sep 26 17:27:23 2017 - Size: 408.0 MiB - WAL Size: 3.0 MiB
db1 20170926T172446 - Tue Sep 26 17:24:23 2017 - Size: 411.1 MiB - WAL Size: 1.8 MiB - OBSOLETE
db1 20170926T172350 - Tue Sep 26 17:23:31 2017 - Size: 411.1 MiB - WAL Size: 1.3 MiB - OBSOLETE
[antdb@localhost1 ~]$ barman cron
Starting WAL archiving for server db1
Enforcing retention policy: removing backup 20170926T172350 for server db1
Deleting backup 20170926T172350 for server db1
Delete associated WAL segments:
0000000A0000000000000046
0000000A0000000000000046.00000028.backup
0000000A0000000000000047
00000001000000000000002B
00000002000000000000002B
Deleted backup 20170926T172350 (start time: Tue Sep 26 17:32:43 2017, elapsed time: less than one second)
Enforcing retention policy: removing backup 20170926T172446 for server db1
Deleting backup 20170926T172446 for server db1
Delete associated WAL segments:
0000000A0000000000000048
0000000A0000000000000048.00000028.backup
0000000A0000000000000049
Deleted backup 20170926T172446 (start time: Tue Sep 26 17:32:43 2017, elapsed time: less than one second)
[dang22@localhost1 ~]$ barman list-backup db1
db1 20170926T172835 - Tue Sep 26 17:30:07 2017 - Size: 410.6 MiB - WAL Size: 0 B
db1 20170926T172728 - Tue Sep 26 17:27:23 2017 - Size: 408.0 MiB - WAL Size: 3.0 MiB
删除某一个备份
命令:
barman delete server_name backup_id
例子:
[antdb@localhost1 ~/barman/conf]$ barman delete db1 20190104T033001
Deleting backup 20190104T033001 for server db1
Delete associated WAL segments:
000000010000000000000014
...
备份所有节点
集群中涉及到的节点较多,建议通过提供的 barman-operate.sh
脚本操作。
执行 sh barman-operate.sh backup_all
会对所有的master节点发起备份操作。 coordinator
和 gtmcoord
相对小一些,备份耗时也会较短,datanode
相对耗时会长一些。 通过 barman 的日志查看节点的备份进度。
数据恢复
恢复到某一个备份 id
命令:
barman recover server_name backup_id destination_directory
想了解具体参数意义,可以参考:barman recover --help
例子:
[antdb@localhost1 ~]$ barman recover dm0 20190129T152916 /home/antdb/pgdata/datanode/0 --remote-ssh-command='ssh antdb@10.1.226.201'
Starting remote restore for server dm0 using backup 20190129T152916
Destination directory: /home/antdb/pgdata_xc/datanode/0
Copying the base backup.
Copying required WAL segments.
Generating archive status files
Identify dangerous settings in destination directory.
IMPORTANT
These settings have been modified to prevent data losses
postgresql.conf line 747: archive_command = false
Your PostgreSQL server has been successfully prepared for recovery!
要注意最后的提示,恢复完成后,节点的归档命令被关闭了,需要在所有节点恢复完成,数据确认无误,集群开始正式运行后,把所有节点的归档命令重新设置好。
基于时间点的恢复
基于时间点恢复,如果 datanode 所在主机的时间不一致,容易导致恢复的点不一致。如果可以确定能恢复到同一个时间点,可以在命令中配置参数 --target-time
。
例子:
[antdb@localhost1 ~]$ barman recover db1 20170928T163937 /home/antdb/adb/data/db1_barman --target-time '2017-09-28 16:40:00'
Starting local restore for server db1 using backup 20170928T163937
Destination directory: /home/antdb/adb/data/db1_barman
Doing PITR. Recovery target time: '2017-09-28 16:40:00'
Copying the base backup.
Copying required WAL segments.
Generating recovery.conf
Identify dangerous settings in destination directory.
IMPORTANT
These settings have been modified to prevent data losses
postgresql.conf line 687: archive_command = false
Your PostgreSQL server has been successfully prepared for recovery!
基于 barrier 点的恢复
集群版本中,想要各个节点能够恢复到一致的状态,建议使用 AntDB 提供的 barrier
技术。
每个节点都恢复到同一个 barrier 点,才能真正实现全局一致时间点的恢复。
- 此功能需要在备份前,创建 barrier,在 coordinator 上执行如下命令
CRRATE BARRIER 'bar1';
- 恢复的时候加上参数
--target-barrier=barrier_name
barman recover dm0 20181227T110223 /home/antdb/pgdata_xc/datanode/0 --remote-ssh-command='ssh antdb@10.1.226.201' --target-barrier='bar1'
下面以一个集群为例,实际操作备份和恢复:
- 备份前创建一个 barrier,执行一次日志切换,然后备份:
CRRATE BARRIER 'bar1';
barman switch-xlog --force --archive dm0
barman switch-xlog --force --archive dm1
barman switch-xlog --force --archive coord0
barman switch-xlog --force --archive gtmcoord
barman backup dm0
barman backup dm1
barman backup coord0
barman backup gtmcoord
- 当需要恢复数据的时候,查询备份列表,恢复数据
barman list-backup dm0
barman list-backup dm1
barman list-backup coord0
barman list-backup gtmcoord
barman recover dm0 backup_id /home/antdb/pgdata/datanode/0 --remote-ssh-command='ssh antdb@10.1.226.201' --target-barrier='bar1'
barman recover dm1 backup_id /home/antdb/pgdata/datanode/1 --remote-ssh-command='ssh antdb@10.1.226.201' --target-barrier='bar1'
barman recover coord0 backup_id /home/antdb/pgdata/coord/0 --remote-ssh-command='ssh antdb@10.1.226.201' --target-barrier='bar1'
barman recover gtmcoord backup_id /home/antdb/pgdata/gtmcoord/1 --remote-ssh-command='ssh antdb@10.1.226.203' --target-barrier='bar1'
完成恢复后,启动集群。 各个节点启动完成后,为了保护恢复后的集群数据,节点都还处于恢复状态,无法写入数据,登录节点执行 pg_is_in_recovery
,返回 t
,说明节点处于恢复状态。此时,需要在各个节点上执行 select pg_wal_replay_resume();
以便节点可以接受读写请求。 barman_operate.sh
脚本中也提供了在所有 master 节点执行该命令的操作:sh barman_operate.sh replay_resume
。
注意事项:
- 恢复后,原来的 slave 节点数据与 master 不一致,需要重新 append slave 节点。
- 如果集群运行过程中 master 节点发生过切换,则 barman 的配置文件需要重新生成,以便与集群最新的结构相对应。