作者
digoal
日期
2020-03-21
标签
PostgreSQL , 闪回 , zfs
背景
阿里云 rds pg 12为例, 创建RDS PG 的秒级 flashback闪回实例, 实时容灾实例.
技术点:
zfs - snapshot - clone - postgresql stream standby - compress
例子
1、申请ecs
规格, 可用区, vpc, vswitch 建议与RDS PG相同
存储根据主库的读写压力配置, 能满足容灾库的恢复效率就可以
如果需要将容灾实例设置在跨region的机房, 建议 VPC网络打通
2、部署系统, 建议centos 7 x64
配置sysctl, limits等配置参考:
https://github.com/digoal/blog/blob/master/202002/20200229_01.md
3、部署zfs, 开启压缩
```
cat /etc/redhat-release
CentOS Linux release 7.7.1908 (Core)
```
https://github.com/openzfs/zfs/wiki/RHEL-and-CentOS
```
wget http://download.zfsonlinux.org/epel/zfs-release.el7_7.noarch.rpm
rpm -ivh zfs-release.el7_7.noarch.rpm
yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
yum install -y "kernel-devel-uname-r == $(uname -r)" zfs
```
查看日志,是否有报错,正常情况下没有报错
4、测试zfs是否可用
配置系统启动时自动加载zfs
vi /etc/rc.local
/sbin/modprobe zfs
chmod +x /etc/rc.local
测试zfs是否正常
```
modprobe zfs
zpool list
no pools available
reboot
```
5、安装pg 12
https://www.postgresql.org/download/linux/redhat/
```
yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
yum install postgresql12*
su - postgres
配置环境变量
vi ~/.bash_profile
追加
export PS1="$USER@/bin/hostname -s-> "
export LANG=en_US.utf8
export PGHOME=/usr/pgsql-12
export LD_LIBRARY_PATH=$PGHOME/lib:/lib64:/usr/lib64:/usr/local/lib64:/lib:/usr/lib:/usr/local/lib:$LD_LIBRARY_PATH
export DATE=date +"%Y%m%d%H%M"
export PATH=$PGHOME/bin:$PATH:.
export MANPATH=$PGHOME/share/man:$MANPATH
alias rm='rm -i'
alias ll='ls -lh'
unalias vi
```
6、插件安装(根据你在RDS里面使用的插件安装, 有些插件可能是RDS独有的, 那么目前在容灾端将无法调用这些插件, 但是不影响容灾恢复)
7、配置zpool, zfs
假设/dev/vdc是新增的云盘, 如果你的云盘不是vdc请更换, zfs也支持管多快云盘, 请自行查阅zfs手册不再赘述.
```
parted -a optimal -s /dev/vdc mklabel gpt mkpart primary 1MiB 100%FREE
zpool create zp1 -f -o ashift=13 vdc1
zfs set canmount=off zp1
```
8、创建存放数据文件的目录
zfs create -o mountpoint=/zpdata01 -o recordsize=8K -o atime=off -o primarycache=metadata -o logbias=throughput -o secondarycache=none zp1/zpdata01
9、创建存放wal归档文件的目录
```
zfs create -o mountpoint=/zpdata02 -o recordsize=8K -o atime=off -o primarycache=metadata -o logbias=throughput -o secondarycache=none -o compression=on zp1/zpdata02
zfs set compression=on zp1/zpdata02
zfs list
NAME USED AVAIL REFER MOUNTPOINT
zp1 1.29M 1.42T 192K /zp1
zp1/zpdata01 192K 1.42T 192K /zpdata01
zp1/zpdata02 192K 1.42T 192K /zpdata02
```
10、创建rds实例rds_superuser用户
```
在控制台可创建:
user: rep
pwd: xxxxxx
```
11、配置rds白名单
允许该ecs连接
12、创建rds pg 12从库
```
mkdir /zpdata01/pg12_1921_data
mkdir /zpdata02/pg12_1921_wal
chown -R postgres:postgres /zpdata01/pg12_1921_data
chown -R postgres:postgres /zpdata02/pg12_1921_wal
```
```
su - postgres
export PGPASSWORD=pwd
nohup pg_basebackup -D /zpdata01/pg12_1921_data -F p -R -c fast -X stream -h pgm-bp1wv687i955y998129390.pg.rds.aliyuncs.com -p 1433 -U rep >./bak.log 2>&1 &
```
13、配置从库, 包括application_name、开启归档等
su - postgres
cd /zpdata01/pg12_1921_data
注视postgresql.conf如下配置
```
grep "^#" postgresql.conf
Fri Mar 13 09:55:03 CST 2020
ssl_key_file='server.key'
huge_pages=try
auto_explain.sample_rate=1
zhparser.multi_zall=off
shared_preload_libraries='pg_stat_statements,auth_delay,auto_explain,zhparser,timescaledb,pg_pathman'
promote_trigger_file='/data/postgresql.trigger'
ssl=off
rds_max_log_files=20
pg_pathman.enable_auto_partition=on
shared_buffers=32768MB
zhparser.punctuation_ignore=off
pg_pathman.override_copy=on
port=1922
pg_stat_statements.max=5000
auth_delay.milliseconds=3s
auto_explain.log_nested_statements=off
track_io_timing=on
zhparser.multi_zmain=off
auto_explain.log_analyze=off
archive_mode=on
ssl_cert_file='server.crt'
zhparser.multi_short=off
zhparser.dict_in_memory=off
auto_explain.log_format=text
auto_explain.log_min_duration=-1
rds.rds_max_non_super_conns=12800
pg_pathman.enable=on
archive_command='/bin/date'
auto_explain.log_verbose=off
log_line_prefix='\1\n\t%p\t%r\t%u\t%d\t%t\t%e\t%T\t%S\t%U\t%E\t\t'
pg_pathman.enable_runtimemergeappend=on
zhparser.extra_dicts='dict_extra.xdb'
auto_explain.log_buffers=off
pg_stat_statements.track=top
jit_provider='llvmjit'
pg_pathman.enable_partitionrouter=off
pg_stat_statements.track_utility=off
pg_stat_statements.save=off
zhparser.dicts_type='EXTRA'
auto_explain.log_timing=on
pg_pathman.enable_runtimeappend=on
zhparser.seg_with_duality=off
rds.rds_max_super_conns=100
pg_pathman.enable_partitionfilter=on
log_destination='stderr,csvlog'
zhparser.multi_duality=off
pg_pathman.insert_into_fdw='postgres'
pg_pathman.enable_bounds_cache=on
rds.rds_max_non_super_wal_snd=32
auto_explain.log_triggers=off
rds_sync_replication_timeout=0
```
修改配置参数如下(如果没有则新增这个文件)
```
su - postgres
cd /zpdata01/pg12_1921_data
vi postgresql.auto.conf
primary_conninfo = 'user=rep password=''pwd'' host=''pgm-bp1wv687i955y998129390.pg.rds.aliyuncs.com'' port=1433 application_name=hello_rds_pg12'
port=1922
shared_buffers=32GB
log_destination='csvlog'
archive_mode=always
archive_command='test ! -f /zpdata02/pg12_1921_wal/%f && cp %p /zpdata02/pg12_1921_wal/%f'
```
14、改一下目录权限
chmod 700 /zpdata02/pg12_1921_wal
chmod 700 /zpdata01/pg12_1921_data
15、启动从库
pg_ctl start -D /zpdata01/pg12_1921_data
16、配置自动启动从库
vi /etc/rc.local
su - postgres -c "pg_ctl start -D /zpdata01/pg12_1921_data"
17、配置数据文件目录自动快照(归档目录不需要快照)
创建脚本, 配置执行权限
``
vi /etc/snap.sh
STIME=date +%F%T`
/usr/sbin/zfs snapshot zp1/zpdata01@$STIME
chmod 500 /etc/snap.sh
```
测试快照是否正常
```
/etc/snap.sh
zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
zp1/zpdata01@2020-03-2117:06:47 144K - 770M -
```
自动启动crond配置
```
systemctl start crond
systemctl enable crond
systemctl status crond
● crond.service - Command Scheduler
Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2020-03-21 16:16:08 CST; 53min ago
Main PID: 2526 (crond)
CGroup: /system.slice/crond.service
└─2526 /usr/sbin/crond -n
Mar 21 16:16:08 iZbp135pwcjjoxqgfpw9k1Z systemd[1]: Started Command Scheduler.
Mar 21 16:16:09 iZbp135pwcjjoxqgfpw9k1Z crond[2526]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 85% if used.)
Mar 21 16:16:09 iZbp135pwcjjoxqgfpw9k1Z crond[2526]: (CRON) INFO (running with inotify support)
```
配置crontab自动任务, 例如每天1点1分打快照, 你可以根据实际需求自己配置.
```
crontab -e
1 1 * * * /etc/snap.sh
crontab -l -u root
1 1 * * * /etc/snap.sh
```
18、配置自动清理快照
略, 手工执行清理的例子如下
```
[root@iZbp135pwcjjoxqgfpw9k1Z pg12_1921_data]# zfs list -t snapshot
zNAME USED AVAIL REFER MOUNTPOINT
zp1/zpdata01@2020-03-2117:06:47 144K - 770M -
zp1/zpdata01@2020-03-2117:17:01 0B - 786M -
[root@iZbp135pwcjjoxqgfpw9k1Z pg12_1921_data]# zfs destroy zp1/zpdata01@2020-03-2117:06:47
[root@iZbp135pwcjjoxqgfpw9k1Z pg12_1921_data]# zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
zp1/zpdata01@2020-03-2117:17:01 0B - 786M -
```
19、配置自动清理归档
略
[root@iZbp135pwcjjoxqgfpw9k1Z pg12_1921_data]# cd /zpdata02/pg12_1921_wal/
[root@iZbp135pwcjjoxqgfpw9k1Z pg12_1921_wal]# ll
total 49
-rw------- 1 postgres postgres 16777216 Mar 21 17:06 000000010000011D00000097
手工执行例子如下, 删除7天前的wal归档文件例子
find /zpdata02/pg12_1921_wal/ -type f -mtime +7 -exec rm -f {} \;
自动化方法:
创建脚本, 配置脚本执行权限
略
配置crontab
略
20、校验备份集可用性, 参考:
https://github.com/digoal/blog/blob/master/201608/20160823_06.md
21、检测主从延迟 (primary, standby)
查询主库即可
```
postgres=> select pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_flush_lsn(),sent_lsn)) as sent_delay,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_flush_lsn(),replay_lsn)) as replay_dealy,*
from pg_stat_replication ;
-[ RECORD 1 ]----+------------------------------
sent_delay | 0 bytes
replay_dealy | 0 bytes
pid | 84098
usesysid | 886185
usename | rep
application_name | hello_rds_pg12
client_addr | 192.168.0.173
client_hostname |
client_port | 60402
backend_start | 2020-03-21 16:59:01.890775+08
backend_xmin |
state | streaming
sent_lsn | 11D/97002068
write_lsn | 11D/97002068
flush_lsn | 11D/97002068
replay_lsn | 11D/97002068
write_lag |
flush_lag |
replay_lag |
sync_priority | 0
sync_state | async
reply_time | 2020-03-21 17:01:17.198139+08
```
闪回例子
1、列出快照, 注意快照的时间点
```
zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
zp1/zpdata01@2020-03-2117:17:01 312K - 786M -
```
2、选出需要恢复的目标时间点之前的一个快照, 最好选离恢复时间最近的(但是一定要之前的, 如果你选择的快照不够前(至少距离一个checkpoint检查点), 则重新选择更前的).
基于快照克隆一个zfs文件系统
```
zfs clone -o mountpoint=/test_recovery zp1/zpdata01@2020-03-2117:17:01 zp1/zpdata_test
[root@iZbp135pwcjjoxqgfpw9k1Z pg12_1921_wal]# cd /test_recovery
[root@iZbp135pwcjjoxqgfpw9k1Z test_recovery]# ll
total 17
drwx------ 20 postgres postgres 35 Mar 21 16:59 pg12_1921_data
```
3、配置, 包括端口, 恢复目标recovery_target_time等
```
su - postgres
cd /test_recovery/pg12_1921_data
vi postgresql.auto.conf
port=1923
shared_buffers=32GB
log_destination='csvlog'
recovery_end_command = 'cp /zpdata02/pg12_1921_wal/%f %p'
recovery_target_time = '2020-03-21 17:28:37.670338+08'
recovery_target_timeline = 'latest'
recovery_target_action = 'pause'
```
如果你的服务器内存不足, 可以设置较小的shared_buffer
4、删除克隆文件系统中的socket, pid等文件
rm -f /test_recovery/pg12_1921_data/.s.*
rm /test_recovery/pg12_1921_data/postmaster.pid
5、启动恢复
pg_ctl start -D /test_recovery/pg12_1921_data
6、打开恢复库
```
psql -h /test_recovery/pg12_1921_data -p 1923 -U rep postgres
psql (12.1)
Type "help" for help.
postgres=> \dt
List of relations
Schema | Name | Type | Owner
--------+------------------+-------+--------
public | pgbench_branches | table | digoal
public | pgbench_history | table | digoal
public | pgbench_tellers | table | digoal
(3 rows)
```
克隆库用完后, 停库, 清理克隆的test_recovery文件系统即可。
```
su - postgres
pg_ctl stop -m fast -D /test_recovery/pg12_1921_data
sudo
zfs destroy zp1/zpdata_test
```
小结
使用这个方法, 在zfs文件系统中创建了一个实时standby, 使用cron定期打快照(不管多少数据量, 秒级快照), 恢复时找到最近的快照, 可以快速恢复.
zfs是个不错的文件系统, 支持快照, 压缩等功能, 非常棒.
参考
https://github.com/openzfs/zfs/wiki/FAQ
https://github.com/digoal/blog/blob/master/201809/20180919_01.md
PostgreSQL 许愿链接
您的愿望将传达给PG kernel hacker、数据库厂商等, 帮助提高数据库产品质量和功能, 说不定下一个PG版本就有您提出的功能点. 针对非常好的提议,奖励限量版PG文化衫、纪念品、贴纸、PG热门书籍等,奖品丰富,快来许愿。开不开森.
9.9元购买3个月阿里云RDS PostgreSQL实例
PostgreSQL 解决方案集合
德哥 / digoal's github - 公益是一辈子的事.





