Thủ tục Failover/Switchover Streaming Replication trên PostgreSQL

 

Tình huống 1: Failover

Đây là tình huống khi database master gặp trục trặc, không thể hoạt động tiếp được. Chúng ta cần phải kích hoạt database slave (dự phòng) lên thành database master mới.

Tình huống 2: Switchover

Đây là tình huống, chúng ta sẽ chuyển đổi vai trò giữa database master và database slave cho nhau (master thành slave, slave thành master). Tình huống này thường gặp khi chúng ta cần kiểm thử slave có đủ sẵn sàng trong trường hợp master bị hỏng hay không, hoặc khi chúng ta cần bảo dưỡng master, trong khi ứng dụng vẫn có thể kết nối với slave và làm việc bình thường.

2. Mô hình triển khai

Mô hình mà tôi sử dụng để thực hiện bài lab này như sau

Thông tin Master:

  • IP: 192.168.56.10
  • OS: Oracle Linux 7.9
  • Version PostgreSQL: 13

Thông tin Slave

  • IP: 192.168.56.11
  • OS: Oracle Linux 7.9
  • Version PostgreSQL: 13

3. Quy trình Failover

1. Bài toán đặt ra

Giả sử server master của tôi bị trục trặc và hiện đã không thể khởi động lên được. Như các bạn đã biết, dữ liệu trên database slave giống y hệt với database master, tuy nhiên slave chỉ cho phép đọc thôi, không ghi được. Tôi cần cấu hình database slave có thể đọc/ghi được, để cho ứng dụng kết nối vào slave, thay thế tạm thời cho master.

2. Thực hiện trên master

Để giả lập tình huống database master bị lỗi, tôi sẽ stop database master đi

$ pg_ctl stop
waiting for server to shut down.... done
server stopped

3. Thực hiện trên Slave

Kiểm tra thư mục lưu archive log đã có hay chưa

show archive_command ;
archive_command
----------------------------------------------------------
test ! -f /backup/archive/%f && cp %p /backup/archive/%f
ls -l /backup/archive

 

Thực hiện promote database slave thành master

pg_ctl promote
waiting for server to promote.... done
server promoted

 

Kiểm tra trong log

2021-08-07 10:11:54.443 +07 [12591] LOG: received promote request
2021-08-07 10:11:54.443 +07 [12591] LOG: redo done at 0/4000028
2021-08-07 10:11:54.443 +07 [12591] LOG: last completed transaction was at log time 2021-08-07 10:09:49.032965+07
2021-08-07 10:11:54.449 +07 [12591] LOG: selected new timeline ID: 2
2021-08-07 10:11:55.216 +07 [12591] LOG: archive recovery complete
2021-08-07 10:11:55.238 +07 [12587] LOG: database system is ready to accept connections

 

Sau khi promote, bạn sẽ thấy file standby.signal cũng biến mất

File này không còn có nghĩa là PostgreSQL đã coi slave là 1 database độc lập, có thể đọc ghi được rồi. Thử kiểm tra lại nhé

4. Kiểm tra lại:

$ psql

 

Tạo thử dữ liệu

postgres=# create table test123(id int4);
CREATE TABLE
postgres=#
postgres=#
postgres=# insert into test123 values (1);
INSERT 0 1
postgres=# insert into test123 values (2);
INSERT 0 1
postgres=# insert into test123 values (3);
INSERT 0 1
postgres=# insert into test123 values (4);
INSERT 0 1
postgres=# select * from test123;
id
----
1
2
3
4
(4 rows)

 

Các bạn thấy đó, database slave giờ đã đọc/ghi được và ứng dụng có thể kết nối vào đó được rồi.

4. Quy trình Switchover

1. Bài toán đặt ra

Hiện tại, bạn kiểm tra thì database slave vẫn đang đồng bộ bình thường với database master. Tuy nhiên, bạn vẫn lăn tăn việc, nếu như có sự cố trên master thực sự xảy ra, liệu slave có đủ sẵn sàng để hoạt động thay thế không

Lúc này, bạn cần thử diễn tập switchover (tráo đổi vai trò) database, để đưa slave thành master và ngược lại. Sau khi switchover, bạn sẽ cho ứng dụng kết nối vào slave (lúc này là master mới), và kiểm tra toàn bộ nghiệp vụ xem slave có đáp ứng được hay không.

2. Kiểm tra Slave:

Việc đầu tiên bạn cần làm là kiểm tra xem Standby đã đồng bộ realtime với master hay chưa

select * from pg_stat_wal_receiver;
select pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn(), pg_last_xact_replay_timestamp();

3. Thực hiện trên Master

Sau khi đã chắc chắn là database slave đang đồng bộ realtime với master, các bạn hãy tắt database master đi

$ pg_ctl stop

 

Backup lại file postgresql.conf

cd $PGDATA
cp postgresql.conf postgresql.conf.old

4. Tiến hành promote Slave

Kiểm tra thư mục lưu archive log đã có hay chưa

show archive_command ;
archive_command
----------------------------------------------------------
test ! -f /backup/archive/%f && cp %p /backup/archive/%f
ls -l /backup/archive

 

Kiểm tra lần cuối xem slave đã đọc đến WAL record cuối cùng được master gửi sang hay chưa. Bước này quan trọng nè.

postgres=# select pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn(), pg_last_xact_replay_timestamp();
-[ RECORD 1 ]-----------------+------------------------------
pg_last_wal_receive_lsn       | 0/301B510
pg_last_wal_replay_lsn        | 0/301B510
pg_last_xact_replay_timestamp | 2021-08-07 10:06:55.438858+07

 

Các bạn thấy 2 chỉ số pg_last_wal_receive_lsn và pg_last_wal_replay_lsn  bằng nhau là được.

 

Cuối cùng là tiến hành đưa standby lên thành master mới

$ pg_ctl promote
waiting for server to promote.... done 
server promoted

 

Kiểm tra trong log

2021-08-07 10:11:51.621 +07 [13378] FATAL: could not connect to the primary server: could not connect to server: Connection refused
Is the server running on host "192.168.56.10" and accepting
TCP/IP connections on port 5432?
2021-08-07 10:11:54.443 +07 [12591] LOG: received promote request
2021-08-07 10:11:54.443 +07 [12591] LOG: redo done at 0/4000028
2021-08-07 10:11:54.443 +07 [12591] LOG: last completed transaction was at log time 2021-08-07 10:09:49.032965+07
2021-08-07 10:11:54.449 +07 [12591] LOG: selected new timeline ID: 2
2021-08-07 10:11:55.216 +07 [12591] LOG: archive recovery complete
2021-08-07 10:11:55.238 +07 [12587] LOG: database system is ready to accept connections

Như vậy là database slave đã thành master mới rồi đó. Tuy nhiên bây giờ mà bạn start master cũ lên thì sẽ có 2 con master chạy cùng lúc đấy. Vậy việc tiếp theo là phải cấu hình để master cũ thành slave mới.

5. Đưa Master thành Slave

Sửa lại file postgresql.conf, bạn thêm vào dòng sau

primary_conninfo = 'user=replication password=Abcd1234 channel_binding=prefer host=192.168.56.11 port=5432 sslmode=prefer sslcompression=0 ssl_min_protocol_version=TLSv1.2 gssencmode=prefer krbsrvname=postgres target_session_attrs=any'

 

Trong đó, host=192.168.56.11 chính là IP của slave cũ (hay master mới).

 

Tạo file standby.signal

touch standby.signal

File này để báo hiệu cho biết đây là 1 database slave khi khởi động.

 

Bây giờ bạn có thể khởi động slave mới (hay master cũ) được rồi đấy

$ pg_ctl start
waiting for server to start....2021-08-07 10:26:25.005 +07 [12043] LOG:  redirecting log output to logging collector process
2021-08-07 10:26:25.005 +07 [12043] HINT:  Future log output will appear in directory "log".
 done
server started

 

Trong log sẽ thấy như sau:

2021-08-07 10:26:25.006 +07 [12043] LOG: starting PostgreSQL 13.3 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44), 64-bit
2021-08-07 10:26:25.006 +07 [12043] LOG: listening on IPv4 address "0.0.0.0", port 5432
2021-08-07 10:26:25.006 +07 [12043] LOG: listening on IPv6 address "::", port 5432
2021-08-07 10:26:25.008 +07 [12043] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2021-08-07 10:26:25.012 +07 [12043] LOG: listening on Unix socket "/tmp/.s.PGSQL.5432"
2021-08-07 10:26:25.015 +07 [12045] LOG: database system was shut down at 2021-08-07 10:10:56 +07
2021-08-07 10:26:25.015 +07 [12045] LOG: entering standby mode
2021-08-07 10:26:25.017 +07 [12045] LOG: consistent recovery state reached at 0/40000A0
2021-08-07 10:26:25.017 +07 [12045] LOG: invalid record length at 0/40000A0: wanted 24, got 0
2021-08-07 10:26:25.018 +07 [12043] LOG: database system is ready to accept read only connections
2021-08-07 10:26:55.095 +07 [12083] LOG: fetching timeline history file for timeline 2 from primary server
2021-08-07 10:26:55.117 +07 [12083] LOG: started streaming WAL from primary at 0/4000000 on timeline 1
2021-08-07 10:26:55.117 +07 [12083] LOG: replication terminated by primary server
2021-08-07 10:26:55.117 +07 [12083] DETAIL: End of WAL reached on timeline 1 at 0/40000A0.
2021-08-07 10:26:55.118 +07 [12045] LOG: new target timeline is 2
2021-08-07 10:26:55.118 +07 [12083] LOG: restarted WAL streaming at 0/4000000 on timeline 2
2021-08-07 10:26:55.874 +07 [12045] LOG: redo starts at 0/40000A0

6. Kiểm tra lại

Thực hiện insert dữ liệu trên master mới (slave cũ)

postgres=# create table test1234(id int4);
CREATE TABLE
postgres=#
postgres=#
postgres=# insert into test1234 values (1);
INSERT 0 1
postgres=# insert into test1234 values (2);
INSERT 0 1
postgres=# insert into test1234 values (3);
INSERT 0 1
postgres=# insert into test1234 values (4);
INSERT 0 1

 

Kiểm tra dữ liệu xem đã có trên slave mới (master cũ) hay chưa

postgres=# select * from test1234;
 id
----
  1
  2
  3
  4
(4 rows)

 

Related posts

Perform Manual Failover & Switchover with repmgr in PostgreSQL

Configure automatic failover with repmgrd in PostgreSQL

Monitor Streaming Replication trong PostgreSQL