0.先说需求:
原先有一个线上的pg数据库,就叫它pg-1,现在需要需要将其复制到pg-2,复制完之后对pg-1的所有操作需要同步到pg-2(包括线上系统使用时发生的数据变更和手动修改),但对pg-2的操作不要同步到pg-1。
通过调查决定使用日志分析的方式,分析出pg-1的执行过的sql,然后再在pg-2上执行一遍。日志分析工具使用WalMiner
1.安装WalMiner
gitee上有完整的安装步骤,此处不再赘述,需要注意pg版本,WalMiner3.0之后不再支持9.*的pg
安装过程中可能会报头文件找不到的错误,需安装postgresql对应版本的dev包,并加入环境变量
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/pgsql-9.6/include
(dev包在centos上可能叫postgresql96-devel, ubuntu上可能叫postgresql-server-dev-9.6)
2.开启pg的wal日志归档功能
修改postgresql.conf配置文件
- wal_level = logical
pg10及以后的版本中,待选的值为minimal、replica、logical。
minimal --不能通过基础备份和wal日志恢复数据库。 replica = 9.6版本以前的
archive和hot_standby --该级别支持wal归档和复制。
logical --在replica级别的基础上添加了支持逻辑解码所需的信息。 - archive_mode = on
表示打开归档备份,可选的参数为on,off,always 默认值为off,所以要手动打开 - archive_command = \'test ! -f /home/archivedir/%f && cp %p /home/archivedir/%f\'
该参数的默认值是一个空字符串,他的值可以是一条shell命令或者一个复杂的shell脚本。在shell脚本或命令中可以用 “%p” 表示将要归档的wal文件包含完整路径的信息的文件名,用“%f” 代表不包含路径信息的wal文件的文件名 - archive_timeout=600s
wal日志10分钟切换一次,同时会触发日志归档。因为我们要实现的复制功能需要一定的时效性,10分钟触发一次归档比较合理。
3.同步脚本
#!/bin/bash
set -e
# 检查程序是否正在运行
pid_file="/var/run/transfer.pid"
if [ -e $pid_file ];then
pid=`cat $pid_file`
echo "$pid"
if [ `ps aux|awk '{print $2}'|grep -w $pid|wc -l` -gt 0 ]; then
echo "程序正在运行!"
exit
fi
fi
echo $$>$pid_file
# 用于存储sql的目录
sqlsdir="/home/TMIP/nas/sqls/"
# 用于解析的目录
archivedir="/home/archivedir/"
# 用于备份的目录
archivedir1="/home/TMIP/nas/archivedir/"
# 备份的wal保留十天
find $archivedir1 -type f -mtime +10 -exec rm -Rf {} \;
# 备份的sql保留十天
find $sqlsdir -type f -mtime +10 -exec rm -Rf {} \;
psql_cmd="psql -U postgres -h 127.0.0.1 -p 54340 -d tmip_c020 -c "
transfer_cmd="psql -U postgres -h 192.168.1.131 -p 54340 -d tmip_c020 -c "
# 记录上次解析的截止时间的文件
last_time_file="/root/last_time"
# 精确解析开始时间
start_time=`cat $last_time_file`
# 精确解析结束时间
end_time=`date --date='20 minute ago' "+%Y-%m-%d %H:%M:%S"`.$((10#`date +%N`/1000000))
btime=$(date "+%Y-%m-%d %H:%M:%S")
# 精确解析
sql="delete from walminer_contents;select walminer_wal_add('$archivedir');select wal2sql('$start_time','$end_time',true);"
#echo $sql
$psql_cmd "$sql"
# 测试连接是否通
$transfer_cmd "select 1;"
sql="update walminer_contents set op_text=op_text||';';select op_text from walminer_contents;"
#echo $sql
set +e
$psql_cmd "$sql"|grep ";"|while read line;do
echo "执行sql:${line}"
echo ${line} >> "$sqlsdir$start_time"
$transfer_cmd "$line"
done
# 计算此次同步花费多少时间
etime=$(date "+%Y-%m-%d %H:%M:%S")
duration=$(($(date +%M -d "${etime}")-$(date +%M -d "${btime}")));
mmin=$((60+$duration))
# 只保留(60分钟+同步花费的时间)之内的,其余的移到备份文件夹
find $archivedir -type f -mmin +$mmin -exec mv {} $archivedir1 \;
echo $end_time>$last_time_file
rm $pid_file
如果需要密码的话需要在脚本内加上
export PGPASSWORD=mypassword
加入定时器,每分钟执行一次
*/10 * * * * bash /home/ll/transfer.sh