1. 主库配置
1.1. 创建访问用户
1.2. 修改主库配置文件pg_hba.conf
在pg_hba.conf
配置文件中添加从库网段和流复制权限
第一行表示允许所有用户连接所有db,第二行表示只允许repl用户连接replication(特指流复制)。
后面的scram-sha-256表示密码加密验证的算法,推荐用这个,比md5安全。
1.3. 修改主库配置文件postgresql.conf
- 过滤默认 postgresql.conf 配置文件中的注释内容
grep -Ev '^$|^\s*#' postgresql.conf
- 备份原始配置文件到 postgresql.conf.bak
mv postgresql.conf postgresql.conf.bak
- 创建新的同名空文件
postgresql.conf
,并进行如下修改
vim postgresql.conf
listen_addresses = '*'
#最大连接数,从库的max_connections必须要大于主库的
max_connections = 100
# 添加如下配置项
# 设置主pgsql为生成wal的主机,9.6开始没有hot_standby(热备模式)
wal_level = replica
max_wal_senders = 32 # 同步最大的进程数量
wal_sender_timeout = 60s # 流复制主机发送数据的超时时间
# 默认值为“80MB”,该值通常太小,很容易导致备库失效,也需要设置得大一些
min_wal_size = 800MB
主库配置完成,pg_ctl restart 重启。
2. 从库配置
2.1. 从库同步主库数据
从库无需初始化(无需执行initdb),通过从主库同步数据
-h 启动的主库数据库地址
-p 主库数据库端口
-U 流复制用户
-W 使用密码验证,要用repl的密码 pg_basebackup 的 -W 使用密码验证;小写 -w 是免密登陆,主库的 pg_hba.conf 中流复制 METHOD 选择 trust
-Fp 备份输出正常的数据库目录
-Xs 使用流复制的方式进行复制
-Pv 输出复制过程的详细信息
-R 为备库创建recovery.conf文件。但是pgsql 10以后的新版本的pgsql不需要这个文件了。-R则是用于创建用于replication的配置文件,其实就是生成$PGDATA/standby.signal文件。如果执行pg_basebackup的时候忘记加-R这个参数了,可以手动在备库的$PGDATA下touch standby.signal
同时在postgresql.auto.conf中生成对应的primary_conninfo参数信息
-D 指定创建的备库的数据库目录
完成:
2.2. 修改从库配置文件postgresql.conf
从库同步了主库的数据,包括配置文件,需要修改
2.3. 创建standby.signal
创建 standby.signal 文件,声明从库。该文件只是一个标识文件,它的存在就是告诉数据库,当我们执行pg_ctl start启动的时候,当前库的角色是standby,不是primary角色。
vim $PGDATA/standby.signal
# 写入
# 声明从库
standby_mode = on
确认数据目录权限,避免踩坑。
chown -R postgres.postgres $PGDATA
3. 确认主从同步效果
- 主库查看
sync_state字段:
async:异步流复制
sync:同步流复制
- 从库查看
ps aux | grep receiver
# 返回结果
postgres: walreceiver streaming 0/3000148
4. 将异步转为同步
按上述配置流复制的过程,就已经是异步流复制了
4.1. 修改从库配置文件postgresql.conf
在 primary_conninfo 字段信息加上 application_name=slave ,其 中 slave 是为从库起的应用名称
修改完配置后重启从库
pg_ctl restart
4.2. 修改主库配置文件postgresql.conf
配置 synchronous_standby_names = 'slave' 属性,其中 slave 与上述从库配置中 primary_conninfo 的 application_name 一致即可。也可以使用 '*' 代替具体应用名 称,设置所有从库为同步模式。
vim $PGDATA/postgresql.conf
# 添加下面语句
synchronous_standby_names = 'slave'
修改完配置后重启主库
pg_ctl restart
4.3. 查看主从库状态,遇到未成功转为同步流复制的问题
- 主库查看
select pid,application_name,state,client_addr,sync_priority,sync_state from pg_stat_replication;
问题: 可以看到上述配置修改并没有将主从流复制模式从异步改为同步 ,sync_state
仍然是async
,application_name
仍然是walreceiver
而不是slave。
- 从库查看
select conninfo from pg_stat_wal_receiver;
# 返回结果
user=repl password=******** dbname=replication host=10.0.0.2 port=5432 fallback_application_name=walreceiver sslmode=disable sslcompression=0 gssencmode=disable krbsrvname=postgres targe
t_session_attrs=any
可以看到从库状态中conninfo
字段中并没有application_name
字段内容。
- 解决方法
(1) 忽略从库定义的application_name=slave
直接将主库的synchronous_standby_names
字段值设置为 '*'
。完成修改之后重启主库并查询主库状 态可以看到流复制模式已经修改为了 sync 的同步模式。
synchronous_standby_names = '*'
代表匹配任意主机,也就是任意主机返回就可以提交
(2) 通过 psql 修改备库的系统设置,新值为上一步保存的conninfo
字段信息加上application_name=slave
pg 启动会先加载postgresql.auto.conf
中的配置项,仅修改postgresql.conf
会出现修改失效情况。
alter system set primary_conninfo = 'application_name=slave host=10.0.0.2 port=5432 user=repl password=***********'
也可以在postgresql.auto.conf文件中的primary_conninfo的值里添加以下语句:
application_name=slave
使用此方法,主库仍配置synchronous_standby_names = 'slave'
,推荐使用这个方法,synchronous_standby_names这个参数可以有更多自定义的方式实现主备同步的不同状态。
从库retart,主库reload, 查询状态,完成。
5. 同步流复制的问题(实验)
同步流复制模式中,由于主库提交事务时需等待至少一个备库接收WAL并返回确认信息后主库才向客户端返回成功,一方面保障了数据的完整性,另一方面对于一主一备的同步流复制环境存在一个典型的问题,具体表现为如果备库宕机,主库上的写操作将处于等待状态。
将备库停掉模拟备库故障,在主库上查询数据不受影响:
postgres=#SELECT * FROM test_sr LIMIT 1;
id
--------
1
(1 row)
在主库上尝试插入一条记录,命令被阻塞:
postgres=# INSERT INTO test_sr (id)VALUES (5);
--注意这里命令被阻塞。
这时主库上的INSERT语句一直处于等待状态,也就是说同步备库宕机后,主库上的读操作不受影响,写操作将处于阻塞状态,因为主库上的事务需收到至少一个备库接收WAL后的返回信息才会向客户端返回成功,而此时备库已经停掉了,主库上收不到备库发来的确认信息。
通常一主一备的情况下不会采用同步复制方式,因为备库宕机后同样对生产系统造成严重影响。
解决方案:
- 一主多备,提高系统可用性
PostgreSQL支持一主多从的流复制架构,比如一主两从,将其中一个备库设为同步备库,另一个备库设为异步备库,当同步备库宕机后异步备库升级为同步备库,同时主库上的读写操作不受影响。
- 出现这个问题后,改同步为异步。
-- 将参数synchronous_standby_names = 'slave' 的值设置为空字符串
synchronous_standby_names = ' '
-- 重新加载pg
-- 这个操作不会影响连接的客户端。主库继续进行事务处理
-- 会保持客户端与相应的后端进程之间的所有会话。
pg_ctl reload