一、PostgreSQL通过WAL日志构建高可靠性原理:
PostgrepSQL在数据目录的子目录pg_xlog子目录中维护了一个WAL日志文件,可以把WAL日志备份到另外一台备份服务器,通过重做WAL日志的方式在备服务器上恢复数据(类似Oracle的redo日志)。
WAL日志复制到另外一台备份服务器可以有两种方式:
1、 WAL日志文件复制
此种方式是写完一个WAL日志后,才把WAL日志文件拷贝到备份数据库中。这样通常备份会落后主库一个WAL日志文件,当主数据库发生故障时,主数据库的WAL文件并没有填充完毕未传输(默认16MB)、或者时延等原因导致WAL文件没有传输完毕,会导致被数据库可能存在一定的数据丢失。此种方式是postgreSQL9.0前版本主要提供的WAL日志复制机制。
采用此方式的WAL复制,需要:
- 主数据库的wal_level配置为archive或以上。
- PostgreSQL 9.1之后提供了一个很方便的工具pg_basebackup,使用完成一次基础备份到备数据库。
- 后续产生WAL文件,可以通过archive_command参数调度命令传输至备机。
2、流复制(Streaming Replication)
流复制是PostgreSQL 9.0之后才提供的新的传递WAL日志的方法。通过流复制,备库不断的从主库同步相应的数据,并在备库apply每个WAL record,这里的流复制每次传输单位是WAL日志的record。它的好处是只要主库一产生日志,就会马上传递到备库,同WAL日志文件相比有更低同步延迟。
同时PostgreSQL9.0之后提供了Hot Standby能力,备库在应用WAL record的同时也能够提供只读服务。
PostgreSQL的流复制最多支持1主8备、支持级联复制(主->备1,备1->备2)。
PostgreSQL流复制的核心部分由walsender,walreceiver和startup三个进程组成:
walreceiver启动后通过recovery.conf文件中的primary_conninfo参数信息连向主库,主库通过连接参数replication=true启动walsender进程。
walreceiver执行identify_system命令,获取主库systemid/timeline/xlogpos等信息,执行TIMELINE_HISTORY命令拉取history文件。
执行wal_startstreaming开始启动流复制,通过walrcv_receive获取WAL日志,期间也会回应主库发过来的心跳信息(接收位点、flush位点、apply位点),向主库发送feedback信息(最老的事务id),避免vacuum删掉备库正在使用的记录。
执行walrcv_endstreaming结束流复制,等待startup进程更新receiveStart和receiveStartTLI,一旦更新,重新进入2/3/4步骤。
WAL流复制支持同步、异步方式:
- 异步流复制模式中,主库提交的事务不会等待备库接收WAL日志流并返回确认信息,因此异步流复制模式下主库与备库的数据版本上会存在一定的处理延迟,延迟的时间主要受主库压力、备库主机性能、网络带宽等影响,当正常情况下,主备的延迟通常在毫秒级的范围内,当主库宕机,这个延迟就主要受到故障发现与切换时间的影响而拉长,不过虽然如此,这些数据延迟的问题,可以从架构或相关自动化运维手段不断优化设置。
- 同步流复制模式中,要求主库把WAL日志写入磁盘,同时等待WAL日志记录复制到备库、并且WAL日志记录在任何一个备库写入磁盘后,才能向应用返回Commit结果。一旦所有备库故障,在主库的应用操作则会被挂起,所以此方式建议起码是1主2备。
二、搭建主备流复制环境
pgsql源码安装: https://blog.csdn.net/KillerXie/article/details/109463585.
主库搭建
- 创建复制的用户
#也可登陆后创建
/usr/local/pgsql/bin/psql -p 5543 "user=postgres password=postgres dbname=postgres" -c "CREATE ROLE vdccopy REPLICATION LOGIN ENCRYPTED PASSWORD 'vdccopy';"
- 配置postgresql.conf
#开启ssl 证书自己可以用自签名证书 自签名的证书生成请百度 下面的是在data 目录下
#开启ssl需要在源码编译的时候加入--with-opensll 模块,不需要或没加的的同学可省略下面三行配置
ssl = on
ssl_cert_file = 'server.crt'
ssl_key_file = 'server.key'
archive_mode = off #开启归档模式
wal_level = hot_standby #热备模式
max_wal_senders = 50 #最多有1个流复制连接
wal_log_hints = on
wal_sender_timeout = 60s #流复制超时时间
max_connections = 100 #最大连接时间,必须要小于从库的配置
hot_standby = on #说明这台机器不仅用于数据归档,还可以用于数据查询
max_standby_streaming_delay = 30s #流备份的最大延迟时间
wal_receiver_status_interval = 10s #向主机汇报本机状态的间隔时间
hot_standby_feedback = on #r出现错误复制,向主机反馈
- 配置流复制权限
# "local" is for Unix domain socket connections only
local all all trust
# IPv4 local connections:
host all all 0.0.0.0/0 md5
# IPv6 local connections:
host all all ::1/128 md5
# Allow replication connections from localhost, by a user with the
# replication privilege.
local replication all trust
host replication all 0.0.0.0/0 md5
host replication all ::1/128 md5
- 启动
/usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data start
备库搭建
- 停止备库
/usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data stop -m fast
- 删除备库的data
rm -rf /usr/local/pgsql/data
- 生成备库
#PGPASSWORD是上面生成的vdccopy 的密码
#${destination_address}是主库的ip
PGPASSWORD=vdccopy /home/vdc/pgsql/bin/pg_backebackup -D /home/vdc/pgsql/data -Fp -Xstream -R -c fast -v -P -h ${destination_address} -U vdccopy -p 5543 -w)
- 编辑recovery.conf
vim /usr/local/pgsql/data/recovery.conf
#destination_address是主库的ip
standby_mode = 'on'
primary_conninfo = 'user=vdccopy password=vdccopy host=destination_address port=5543 sslmode=prefer sslcompression=1 target_session_attrs=any'
recovery_target_timeline='latest'
- 启动备库
/usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data start
测试
可以在主库上插入后在备库上查看,具体不截图了
有问题可以百度,大部分可考虑下 搭建过程,配置参数,防火墙是否开放端口等是否正确
三、主备切换
- 关闭原主库(原主库执行)
/usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data stop -m fast
- 将从节点升级为主节点(原备库执行)
/home/vdc/pgsql/bin/pg_ctl promote -D /home/vdc/pgsql/data
#PostgreSQL数据库已经从备节点转换成了主节点。同时,recovery.conf 文件也变为了 recovery.done 文件,表示此节点不再做为从节点进行数据复制。
- 将原主库降级为备库(原主库执行)
可以再次删除data数据在使用pg_backebackup 执行,但对于大数据量的时间比较久,可用pg_rewind
#执行pg_rewind需要wal_log_hints 设置成 on 或者 PG 在初始化时开启 checksums 功能(请看上面postgresql.conf)
#${destination_address}原备库的ip
/usr/local/pgsql/bin/pg_rewind --target-pgdata=/usr/local/pgsql/data --source-server="host=${destination_address} port=5543 user=postgres dbname=postgres password=postgres")
然后在data下创建recovery.conf
vim /usr/local/pgsql/data/recovery.conf
#destination_address是主库的ip
standby_mode = 'on'
primary_conninfo = 'user=vdccopy password=vdccopy host=destination_address port=5543 sslmode=prefer sslcompression=1 target_session_attrs=any'
recovery_target_timeline='latest'
最后启动
/usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data start