Bạn cần tạo một standby server để backup dữ liệu, load balance trên nhiều node để giảm tải tăng performance?, ... Chức năng replication sẽ đáp ứng nhu cầu đó của bạn.
Replication là một trong chức năng không thể thiếu của một số RDBMS nói chung và PostgreSQL(Streaming Replication) nói riêng. Ở PostgreSQL bạn có thể liên kiết với một số cluster soft như Pacemaker, hay pgpool-II để triển khai hệ thống High Availablity cho môi trường của bạn. Nguyên lý Streaming Replication của PostgreSQL dựa trên việc chuyển WAL (Transaction log) từ node Master tới Standby, sau đó Standby phản ánh lại nội dung WAL vào dữ liệu.
Chức năng replication của PostgreSQL đầu tiên được thêm vào ở phiên bản 9.0. Sau nhiều cải tiến qua các phiên bản. Hiện tại replication nổi bật với chức năng logical replication trên phiên bản sắp tới PostgreSQL-10. Quá trình phát triển chức năng replication tới phiên bản PostgreSQL 10 được tóm tắt như bên dưới.
Phải nói thêm là cũng ở phiên bản 9.0 này PostgreSQL có thêm chức năng hot_standby. Chức năng này cho phép tham chiếu dữ liệu ở phía Standby. Nếu chức năng này không hoạt động bạn không thể tham chiếu dữ liệu hay đơn giản là kết nối tới Standby server. Chức năng này gọi là thiếu đồng bộ. Vì dữ liệu cập nhật ở phía Master không được cập nhật tức thì ở Standby. Về nguyên lý thì bạn có thể tham khảo hình bên dưới.
Tiến bộ hơn chức năng Asynchronous, ở chế độ Synchronous Standby Server gửi thông điệp thành công tới Master Server sau khi xác nhận đã nhận được thông tin WAL(Transaction log). Sau khi nhận được được thông điệp từ Standby Server, Master kết thúc xử lý cập nhật dữ liệu. Như vậy sau khi cập nhật dữ liệu ở Master Sever, phải chờ một chút thời gian (thường thì khoảng vài micro giây) để Standby phản ánh (recovery) dữ liệu đó từ WAL vừa nhận được. Lưu ý rằng PostgreSQL chỉ support 1 node là Synchronous. Nếu bạn lập nhiều Standby Server node đầu tiên chỉ định trong tham số synchronous_standby_names.
Chức năng này cho phép bạn thiết lập một hoặc nhiều Standby Sever dựa vào một Standby Server chứ không phải Master Server như trước đây. Ở Cascade Replication mặc định chỉ sử dụng Asynchronous.
Standby Server dựa vào WAL cung cấp từ Master Server để đồng bộ dữ liệu. Nhưng WAL này cũng có thể bị mất theo cơ chế sử dụng lại WAL của PostgreSQL. Khi WAL chưa được đồng bộ (chuyển tới) ở Standby mà bị mất ở Master Server. Standby này sẽ không thể đồng bộ với Master đó nữa, bạn phải thiết lập lại Standby Server trong trường hợp này.
Chức năng replication slot cho phép tạo một slot tới Master Server, yêu cầu Master Server giữ lại WAL cần thiết cho Standby đó.
Số lượng WAL thông thường phụ thuộc vào tham số max_wal_size (Hay checkpoint_segments ở phiên bản trước 9.5). Bạn cũng có thể chỉnh số lượng WAL giữ lại cho standby server qua tham số wal_keep_segments.
Chức năng Logical Decoding cho phép sử dụng plugin bên ngoài decoding được nội dung WAL thành các câu lệnh SQL. Chức năng này kết hợp với chức năng Replication Slot là nền tảng chính của chức năng Logical Replication trong phiên bản PostgreSQL 10.
Mình sử dụng chữ Full vì ở chế độ này, sau khi kết thúc câu lệnh cập nhật dữ liệu ở Master Server, có thể đảm bảo là dữ liệu sẽ chắc chắn đã được cập nhật ở Standby Server.
Chức năng này đang được phát triển ở phiên bản PostgreSQL 10. Master Server public WAL, Standby Server nhận WAL giải mã thành các câu lệnh SQL rồi chạy các câu lệnh đó trên Standby Server. Điều này cho phép PostgreSQL có thể Replication giữa các phiên bản khác nhau, hoặc có thể kỳ vọng là replication với các RDBMS khác.
Các phiên bản PostgreSQL trước phiên bản 10, dữ liệu trên WAL không đủ chi tiết để giải mã thành các câu lệnh SQL. Và phía Server và Client phải nhất quán về phiên bản.
Thiết lập paramters cho từng level Asynchronous, Syncrhonous, Full Synchronous, Logical Replication có thể tóm tắt như bên dưới.
Parameters | Asynchronous | Syncrhonous | Full Synchronous | Logical Replication |
---|---|---|---|---|
wal_level | lớn hơn minimal | lớn hơn minimal | lớn hơn minimal |
logical |
synchronous_standby_names | '' | 'tên Standby hoặc *' | 'tên Standby hoặc *' | |
synchronous_commit |
remote_apply |
|||
max_wal_senders | số lượng Standby | số lượng Standby | số lượng Standby | số lượng Standby |
hot_standby | on nếu muốn tham chiếu Standby | on nếu muốn tham chiếu Standby | on nếu muốn tham chiếu Standby | on nếu muốn tham chiếu Standby |
Ngoài ra nếu bạn muốn archive WAL (lưu lại WAL phục vụ cho mục đích backup), bạn cần archive_mode=on và archive_command='comand để lưu WAL mỗi khi update xong 1 file WAL'
Rất đơn giản để tạo 1 Standby Server trên PostgreSQL. Bạn dùng câu lệnh pg_basebackup để tạo một basebackup chỉnh sửa tham số nếu cần thiết và khởi động là xong.
Bocap-no-MacBook-Pro:~ bocap$ env | grep PG
PGPORT=9100
PGUSER=postgres
PGPASSWORD=postgres
PGDATABASE=postgres
PGDATA=/usr/local/pgsql/pg1000/data
Bocap-no-MacBook-Pro:~ bocap$ psql
psql (10beta1)
Type "help" for help.
postgres=# show synchronous_standby_names;
synchronous_standby_names
---------------------------
(1 row)
postgres=# \q
Không quên setting authentication cho kết nối replication. Ở đây mình đặt trust(không yêu cầu password) cho kết nối nội bộ.
Bocap-no-MacBook-Pro:~ bocap$ grep "replication all" $PGDATA/pg_hba.conf
local replication all trust
host replication all 127.0.0.1/32 trust
host replication all ::1/128 trust
Kiểm tra trạng thái replication tại Master Server(chưa có kết nối nào).
Bocap-no-MacBook-Pro:~ bocap$ psql
psql (10beta1)
Type "help" for help.
postgres=# \x
Expanded display is on.
postgres=# select * from pg_stat_replication;
(0 rows)
postgres=# \q
Thực hiện sao chép dữ liệu cho Standby Server. Và khởi động Standby Server. 11111 là port cho Standby
dang-no-MacBoook-Pro:~ bocap$ pg_basebackup -R -D ${PGDATA}.standby
Bocap-no-MacBook-Pro:~ bocap$ echo port=11111 >> ${PGDATA}.standby/postgresql.conf
Bocap-no-MacBook-Pro:~ bocap$ pg_ctl start -D ${PGDATA}.standby
waiting for server to start....2017-07-16 03:01:28.912 JST [79722] LOG: listening on IPv6 address "::1", port 11111
2017-07-16 03:01:28.912 JST [79722] LOG: listening on IPv6 address "fe80::1%lo0", port 11111
2017-07-16 03:01:28.912 JST [79722] LOG: listening on IPv4 address "127.0.0.1", port 11111
2017-07-16 03:01:28.921 JST [79722] LOG: listening on Unix socket "/tmp/.s.PGSQL.11111"
2017-07-16 03:01:28.941 JST [79723] LOG: database system was interrupted; last known up at 2017-07-16 03:00:38 JST
2017-07-16 03:01:29.126 JST [79723] LOG: entering standby mode
2017-07-16 03:01:29.134 JST [79723] LOG: redo starts at 0/2000028
2017-07-16 03:01:29.135 JST [79723] LOG: consistent recovery state reached at 0/20000F8
2017-07-16 03:01:29.135 JST [79722] LOG: database system is ready to accept read only connections
2017-07-16 03:01:29.160 JST [79727] LOG: started streaming WAL from primary at 0/3000000 on timeline 1
done
server started
Kiểm tra tình trạng Replication hiện tại (async: chưa đồng bộ)
Bocap-no-MacBook-Pro:~ bocap$ psql
psql (10beta1)
Type "help" for help.
postgres=# \x
Expanded display is on.
postgres=# select * from pg_stat_replication ;
-[ RECORD 1 ]----+------------------------------
pid | 79728
usesysid | 16385
usename | postgres
application_name | walreceiver
client_addr |
client_hostname |
client_port | -1
backend_start | 2017-07-16 03:01:29.158203+09
backend_xmin |
state | streaming
sent_lsn | 0/3000060
write_lsn | 0/3000060
flush_lsn | 0/3000060
replay_lsn | 0/3000060
write_lag |
flush_lag |
replay_lag |
sync_priority | 0
sync_state | async
postgres=# create table test_synchronous(id integer);
CREATE TABLE
postgres=# insert into test_synchronous values (1);
INSERT 0 1
postgres=# select * from test_synchronous ;
id
----
1
(1 row)
postgres=# \q
Bocap-no-MacBook-Pro:~ bocap$ psql -p 11111
psql (10beta1)
Type "help" for help.
postgres=# select * from test_synchronous ;
id
----
1
(1 row)
postgres=# \q
Chuyển qua chế độ tiền đồng bộ và kiểm tra tình trạng Replication
Bocap-no-MacBook-Pro:~ bocap$ echo synchronous_standby_names='walreceiver' >> $PGDATA/postgresql.conf
Bocap-no-MacBook-Pro:~ bocap$ pg_ctl reload
server signaled
2017-07-16 03:04:48.747 JST [69073] LOG: received SIGHUP, reloading configuration files
Bocap-no-MacBook-Pro:~ bocap$ 2017-07-16 03:04:48.755 JST [69073] LOG: parameter "synchronous_standby_names" changed to "walreceiver"
Bocap-no-MacBook-Pro:~ bocap$ 2017-07-16 03:04:50.068 JST [79728] LOG: standby "walreceiver" is now a synchronous standby with priority 1
Bocap-no-MacBook-Pro:~ bocap$ psql
psql (10beta1)
Type "help" for help.
postgres=# \x
Expanded display is on.
postgres=# show synchronous_standby_names;
-[ RECORD 1 ]-------------+------------
synchronous_standby_names | walreceiver
postgres=# select * from pg_stat_replication ;
-[ RECORD 1 ]----+------------------------------
pid | 79728
usesysid | 16385
usename | postgres
application_name | walreceiver
client_addr |
client_hostname |
client_port | -1
backend_start | 2017-07-16 03:01:29.158203+09
backend_xmin |
state | streaming
sent_lsn | 0/3019058
write_lsn | 0/3019058
flush_lsn | 0/3019058
replay_lsn | 0/3019058
write_lag |
flush_lag |
replay_lag |
sync_priority | 1
sync_state | sync
postgres=# \q
Chuyển qua chế độ Full Replication
Bocap-no-MacBook-Pro:~ bocap$ psql
psql (10beta1)
Type "help" for help.
postgres=# show synchronous_commit;
synchronous_commit
--------------------
on
(1 row)
postgres=# \q
Bocap-no-MacBook-Pro:~ bocap$ echo synchronous_commit='remote_apply' >> $PGDATA/postgresql.conf
Bocap-no-MacBook-Pro:~ bocap$ pg_ctl reload
server signaled
2017-07-16 03:23:54.258 JST [69073] LOG: received SIGHUP, reloading configuration files
Bocap-no-MacBook-Pro:~ bocap$ 2017-07-16 03:23:54.261 JST [69073] LOG: parameter "synchronous_commit" changed to "remote_apply"
Bocap-no-MacBook-Pro:~ bocap$ psql
psql (10beta1)
Type "help" for help.
postgres=# \x
Expanded display is on.
postgres=# select * from pg_stat_replication ;
-[ RECORD 1 ]----+------------------------------
pid | 79728
usesysid | 16385
usename | postgres
application_name | walreceiver
client_addr |
client_hostname |
client_port | -1
backend_start | 2017-07-16 03:01:29.158203+09
backend_xmin |
state | streaming
sent_lsn | 0/3019138
write_lsn | 0/3019138
flush_lsn | 0/3019138
replay_lsn | 0/3019138
write_lag |
flush_lag |
replay_lag |
sync_priority | 1
sync_state | sync
postgres=# show synchronous_commit;
-[ RECORD 1 ]------+-------------
synchronous_commit | remote_apply
postgres=# \q
Bocap-no-MacBook-Pro:~ bocap$
Về cơ bản để sử dụng chức năng Logical Replication. Chúng ta tạo Publication bằng lệnh CREATE PUBLICATION phía Master Server. Phía Server còn lại (phía nhận WAL không phải là Standby như trên mà là một DB Server có thể ghi dữ liệu bình thường) tạo Subscription bằng lệnh CREATE SUBSCRIPTION như ví dụ bên dưới. Chi tiết về chức năng này sẽ được viết ở bài viết khác, khi PostgreSQL 10 đã được hoàn thành.
Bocap-no-MacBook-Pro:~ bocap$ echo wal_level='logical' >> $PGDATA/postgresql.conf
Bocap-no-MacBook-Pro:~ bocap$ pg_ctl restart
waiting for server to shut down...2017-07-16 03:51:02.705 JST [80462] LOG: received fast shutdown request
.2017-07-16 03:51:02.705 JST [80462] LOG: aborting any active transactions
2017-07-16 03:51:02.708 JST [80464] LOG: shutting down
2017-07-16 03:51:02.750 JST [80462] LOG: database system is shut down
done
server stopped
waiting for server to start....2017-07-16 03:51:03.739 JST [80476] LOG: listening on IPv6 address "::1", port 9100
2017-07-16 03:51:03.739 JST [80476] LOG: listening on IPv6 address "fe80::1%lo0", port 9100
2017-07-16 03:51:03.739 JST [80476] LOG: listening on IPv4 address "127.0.0.1", port 9100
2017-07-16 03:51:03.754 JST [80476] LOG: listening on Unix socket "/tmp/.s.PGSQL.9100"
2017-07-16 03:51:03.787 JST [80477] LOG: database system was shut down at 2017-07-16 03:51:02 JST
2017-07-16 03:51:03.791 JST [80476] LOG: database system is ready to accept connections
done
server started
Bocap-no-MacBook-Pro:~ bocap$
Bocap-no-MacBook-Pro:~ bocap$ psql -c "CREATE TABLE test_logical_rep(id integer)"
CREATE TABLE
Bocap-no-MacBook-Pro:~ bocap$ psql -c "CREATE PUBLICATION pub_test FOR TABLE test_logical_rep"
CREATE PUBLICATION
Bocap-no-MacBook-Pro:~ bocap$ psql -p 5432 -c "CREATE TABLE test_logical_rep(id integer)"
CREATE TABLE
Bocap-no-MacBook-Pro:~ bocap$ psql -p 5432 -c "CREATE SUBSCRIPTION sub_test CONNECTION 'dbname=postgres port=9100 user=postgres' PUBLICATION pub_test"
NOTICE: synchronized table states
2017-07-16 03:58:54.172 JST [80532] LOG: logical decoding found consistent point at 0/3033BB0
2017-07-16 03:58:54.172 JST [80532] DETAIL: There are no running transactions.
NOTICE: created replication slot "sub_test" on publisher
CREATE SUBSCRIPTION
Bocap-no-MacBook-Pro:~ bocap$ 2017-07-16 03:58:54.190 JST [80533] LOG: logical replication apply worker for subscription "sub_test" has started
2017-07-16 03:58:54.196 JST [80534] LOG: starting logical decoding for slot "sub_test"
2017-07-16 03:58:54.196 JST [80534] DETAIL: streaming transactions committing after 0/3033BE8, reading WAL from 0/3033BB0
2017-07-16 03:58:54.196 JST [80534] LOG: logical decoding found consistent point at 0/3033BB0
2017-07-16 03:58:54.196 JST [80534] DETAIL: There are no running transactions.
2017-07-16 03:58:54.198 JST [80535] LOG: logical replication table synchronization worker for subscription "sub_test", table "test_logical_rep" has started
2017-07-16 03:58:54.207 JST [80536] LOG: logical decoding found consistent point at 0/3033BE8
2017-07-16 03:58:54.207 JST [80536] DETAIL: There are no running transactions.
2017-07-16 03:58:55.197 JST [80535] LOG: logical replication table synchronization worker for subscription "sub_test", table "test_logical_rep" has finished
Bocap-no-MacBook-Pro:~ bocap$ psql -c "INSERT INTO test_logical_rep VALUES(11111);"
INSERT 0 1
Bocap-no-MacBook-Pro:~ bocap$ psql -p 5432 -c "select * from test_logical_rep"
id
-------
11111
(1 row)
Bocap-no-MacBook-Pro:~ bocap$
Xin vui lòng đặt câu hỏi hoặc thảo luận bằng comments box bên dưới.
Facebook Comments Box