Postgresql的流复制是异步的,异步的缺点是Standby上的数据落后于主库上的数据,如果使用Hot Standby做读写分离,就会存在数据一致性的问题,对于一些一致性高的应用来说是不可接受的。所以PG从9.1之后提供了同步流复制的架构。同步复制要求在数据写入Standby数据后,事务的commit才返回,所以Standby库出现问题时,会导致主库被Hang住。解决这个问题的方法是启动两个standby数据库,这两个Standby数据库只有有一个是正常的,就不会让主库Hang住。所以在实际应用中,同步流复制,总是有一个主库和2个以上的Standby库。
实现同步复制功能主要是在主库上配置参数”synchronous_standby_names",这个参数指定多个Standby的名称,各个名称之间通过逗号分隔,而Standby名称是在Standby连接到主库时,由连接参数“application_name"指定的。要使用同步复制,在Standby数据库中,recovery.conf里的primary_conninfo一定要指定连接参数”application_name"。
1、配置环境:
示例环境 |
|||||
主机名 |
IP地址 |
角色 |
系统版本 |
数据目录 |
pg版本 |
pg-1 |
10.0.2.60 |
主库 |
RedHat6.4 |
/usr/local/postgresql-9.4.4/data |
9.4 |
pg-2 |
10.0.2.61 |
standby |
RedHat6.4 |
/usr/local/postgresql-9.4.4/data |
9.4 |
pg-3 |
10.0.2.62 |
standby |
RedHat6.4 |
/usr/local/postgresql-9.4.4/data |
9.4 |
2、1)在主库上修改pg_hba.conf:
host replication postgre 10.0.2.0/24 md5
2)修改postgresql.conf :
max_wal_senders = 4
wal_level = hot_standby
hot_standby = on
不设置此项不能访问,如下:
[postgre@pg-2 postgresql-9.4.4]$ psql postgres
psql: FATAL: the database system is starting up
3)指定同步复制的Standby的名称,修改postgresql.conf:
synchronous_standby_names ='standby01,standby02'
注:此处设置的'standby01,standby02'就是在Standby数据库中配置连接参数“application_name”。
3、在备库pg-2上配置:
1)修改recovery.conf:
[postgre@pg-2 data]$ vi recovery.conf
standby_mode = 'on'
primary_conninfo = 'application_name=standby01 user=postgre password=postgre host=10.0.2.60 port=5432sslmode=disable sslcompression=1'
启动standby:
[postgre@pg-2 postgresql-9.4.4]$ pg_ctl start -D/usr/local/postgresql-9.4.4/data -l logfile
在pg-3上配置:
[postgre@pg-3 data]$ cat recovery.conf
standby_mode = 'on'
primary_conninfo = 'application_name=standby02 user=postgre password=postgre host=10.0.2.60 port=5432sslmode=disable sslcompression=1'
启动standby:
[postgre@pg-3 data]$ pg_ctl start -D/usr/local/postgresql-9.4.4/data -l logfile
4、在主库上启动同步复制:
[postgre@pg-1 data]$ pg_ctl reload -D/usr/local/postgresql-9.4.4/data
server signaled
5、测试:
主库上插入数据:
[postgre@pg-1 data]$ psql postgres
psql (9.4.4)
Type "help" for help.
postgres=# insert into hotstandby values (3,'003');
INSERT 0 1
postgres=# insert into hotstandby values (4,'004');
INSERT 0 1
postgres=# insert into hotstandby values (5,'005');
INSERT 0 1
postgres=# insert into hotstandby values (6,'006');
INSERT 0 1
postgres=# insert into hotstandby values (7,'007');
INSERT 0 1
postgres=# select * from hotstandby ;
id | name
----+------
1 | 001
2 | 002
3 | 003
4 | 004
5 | 005
6 | 006
7 | 007
(7 rows)
备库:
pg-2:
postgres=# select * from hotstandby ;
id | name
----+------
1 | 001
2 | 002
3 | 003
4 | 004
5 | 005
6 | 006
7 | 007
(7 rows)
pg-3:
postgres=# select * from hotstandby;
id | name
----+------
1 | 001
2 | 002
3 | 003
4 | 004
5 | 005
6 | 006
7 | 007
(7 rows)
6、故障模拟:
1)关掉一台备库,看主库是否正常工作:
关掉pg-2:
[postgre@pg-2 postgresql-9.4.4]$ pg_ctl stop -D /usr/local/postgresql-9.4.4/data
waiting for server to shut down.... done
server stopped
主库:
postgres=# insert into hotstandby values (9,'009');
INSERT 0 1
postgres=#
pg-3:
postgres=# select * from hotstandby;
id | name
----+------
1 | 001
2 | 002
3 | 003
4 | 004
5 | 005
6 | 006
7 | 007
8 | 008
9 | 009
(9 rows)
重启pg-2后:
[postgre@pg-2 postgresql-9.4.4]$ psql postgres
psql (9.4.4)
Type "help" for help.
postgres=# select * from hotstandby ;
id | name
----+------
1 | 001
2 | 002
3 | 003
4 | 004
5 | 005
6 | 006
7 | 007
8 | 008
9 | 009
(9 rows)
可见,当一台standby损坏时,主库是不受影响的。
2)同时关掉两台standby:
[postgre@pg-2 postgresql-9.4.4]$ pg_ctl stop
waiting for server to shut down.... done
server stopped
[postgre@pg-3 data]$ pg_ctl stop
waiting for server to shut down.... done
server stopped
在主库操作:
postgres=# select * from hotstandby;
id | name
----+------
1 | 001
2 | 002
3 | 003
4 | 004
5 | 005
6 | 006
7 | 007
8 | 008
9 | 009
(9 rows)
postgres=# insert into hotstandby values (10,'010');
非跟新操作都是正常的,但更新操作就不hang住了。此时启动一台standby
[postgre@pg-2 postgresql-9.4.4]$ pg_ctl start
server starting
原本hang住的可以继续了:
postgres=# insert into hotstandby values (10,'010');
INSERT 0 1
7、检查同步流复制的情况:
postgres=# select pid,state,client_addr,sync_priority,sync_state frompg_stat_replication;
pid | state | client_addr | sync_priority |sync_state
-------+-----------+-------------+---------------+------------
11143 | streaming | 10.0.2.61 | 1 | sync
11179 | streaming | 10.0.2.62 | 2 | potential
(2 rows)
由上面可知pg-2的优先级是1,pg-3的优先级是2,这个优先级是由synchronous_standby_names的参数顺序决定的。目前主数据库与pg-2是处于同步"SYNC",而pg-3的状态为“potential",表示它是一个潜在的同步standby,当pg-2损坏时,pg-3会切换到同步状态。
[postgre@pg-2 pg_log]$ pg_ctl stop
waiting for server to shut down.... done
server stopped
postgres=# select pid,state,client_addr,sync_priority,sync_state frompg_stat_replication;
pid | state | client_addr | sync_priority |sync_state
-------+-----------+-------------+---------------+------------
11179 | streaming | 10.0.2.62 | 2 | sync
(1 row)
再次启动pg-2:
[postgre@pg-2 pg_log]$ pg_ctl start -D/usr/local/postgresql-9.4.4/data
server starting
postgres=# select pid,state,client_addr,sync_priority,sync_state frompg_stat_replication;
pid | state | client_addr | sync_priority |sync_state
-------+-----------+-------------+---------------+------------
11213 | streaming | 10.0.2.61 | 1 | sync
11179 | streaming | 10.0.2.62 | 2 | potential
(2 rows)