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
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)