logical replication

PostgreSQL 10 - Logical replication

PostgreSQL 10 mới được release tháng 10 năm 2017 vừa qua, nổi bật với 2 tính năng mới được kỳ vọng là Logical Replication và Declarative Partitioning (ngoài ra cũng có nhiều cải thiện và thay đổi), bài viết này mình muốn giới thiệu qua về chức năng Logical Replication và cách sử dụng trong thực tế.

PostgreSQL Replication

Chức năng Replication của PostgreSQL bắt đầu được giới thiệu ở phiên bản PostgreSQL 9.0 dựa trên kỹ thuật chuyển WAL(Transaction log) qua standby. Chức năng này dần được cải thiện qua các phiên bản và gần đây nhất là chức năng Logical Replication trên phiên bản 10. Các phiên bản của chức năng Replication của PostgreSQL bạn có thể tham khảo ở bài viết chức năng replication của PostgreSQL.


Logical Replication

Logical Replication được thêm vào nhờ một số nhà phát triển PostgreSQL từ công ty 2ndQuadrant dựa trên logic của module pglogical (cũng được phát triển bởi công ty này).
Trước phiên bản logical replication, PostgreSQL cũng đã thực hiện replication qua hình thức chuyển thông tin thay đổi thông qua gửi WAL tới standby. Nhưng ở những phiên bản trước, WAL chuyển qua ở mức độ chi tiết thấp, standby thực hiện phản ảnh lên DB gần như ở mức độ vật lý (đồng bộ các file dữ liệu).
Logical Replication sử dụng WAL ở mức độ chi tiết hơn, có thể decode được thành các câu lệnh SQL (phải sử dụng module ngoài để decode). Phía master (wal sender process) decode và thực hiện ghi lại WAL trước khi gửi tới standby node, phía standby sau đó sử dụng WAL nhận được và phản ảnh vào dữ liệu phía mình ở trạng thái logic thông qua logical worker process.
Logical Replication sử dụng 2 khái niệm mới, PUBLICATION và SUBSCRIPTION. PUBLICATION hiểu đơn giản là nơi phát dữ liệu cập nhật, và SUBSCRIPTION là nơi nhận cập nhật và phản ảnh vào database phía standby.

Thiết lập paramters

Để sử dụng chức năng này. Ta cần chỉnh wal_level (mức độ chi tiết của WAL) lên mức có thể decode được "replica", mỗi một cặp Publication & Subscription cần 1 wal sender processes và một slot chứa wal cho standby ta phải tăng parameters max_wal_senders, max_replication_slots lên giá trị cần thiết.

Parameter Giá trị thiết lập
wal_level replica
max_wal_senders số lượng SUBSCRIPTION + α (cho các kết nối replication khác)
max_replication_slots số lượng SUBSCRIPTION + α (cho các kết nối replication khác)

Ngoài ra, để SUBSCRIPTION có thể connect tới PUBLICATION, ta phải thiết lập authentication cho kết nối replication. Chú ý, không giống với streaming replication, những thiết lập bên trên chỉ cần cho phía PUBLICATION.

Sử dụng Logical Replication

Để sử dụng chức năng Logical Replication, ta cần 2 database cluster riêng biệt cho PUBLICATION và SUBSCRIPTION. Cả 2 database cluster này đều phải hỗ trợ ghi dữ liệu (không giống streaming replication, dữ liệu chỉ có thể ghi ở phía primary).

  1. Thiết lập parameters
    Phía PUBLICATION Server thiết lập các tham số yêu cầu như ở trên.
DangnoMacBook-Pro:postgres bocap$ grep -e max_replication_slots -e max_wal_senders -e wal_level $PGDATA/postgresql.conf
wal_level = logical     # minimal, replica, or logical
#max_wal_senders = 10   # max number of walsender processes
#max_replication_slots = 10 # max number of replication slots
DangnoMacBook-Pro:postgres bocap$ grep replication $PGDATA/pg_hba.conf | grep -v "#"
local   replication     all                                     trust
host    replication     all             127.0.0.1/32            trust
host    replication     all             ::1/128                 trust
DangnoMacBook-Pro:postgres bocap$ 
  1. Tạo PUBLICATION
    Ví dụ bên dưới tạo PUBLICATION đối với một bảng dữ liệu(test_logical_rep). Ta cũng có thể tạo PUBLICATION ở các mức độ nhiều bảng hoặc tất cả các bảng.
10000 postgres@postgres=#  create table test_logical_rep(c1 integer primary key, c2 text);
CREATE TABLE
10000 postgres@postgres=# insert into test_logical_rep select generate_series(1,5),random()::text;
INSERT 0 5
10000 postgres@postgres=# table test_logical_rep
postgres-# ;
 c1 |         c2         
----+--------------------
  1 | 0.709808008279651
  2 | 0.426817617379129
  3 | 0.973640063311905
  4 | 0.729786423034966
  5 | 0.0786650250665843
(5 rows)

10000 postgres@postgres=# \h create publication
Command:     CREATE PUBLICATION
Description: define a new publication
Syntax:
CREATE PUBLICATION name
    [ FOR TABLE [ ONLY ] table_name [ * ] [, ...]
      | FOR ALL TABLES ]
    [ WITH ( publication_parameter [= value] [, ... ] ) ]

10000 postgres@postgres=# create publication test_first_pub for table test_logical_rep ;
CREATE PUBLICATION
10000 postgres@postgres=# 
  1. Tạo SUBSCRIPTION
    Ví dụ bên dưới tạo SUBSCRIPTION đối với PUBLICATION đã tạo ở 2. để đồng bộ bảng dữ liệu test_logical_rep từ database phía PUBLICATION sang phía SUBSCRIPTION.
10001 bocap@postgres=# create table test_logical_rep(c1 integer primary key, c2 text);
CREATE TABLE
10001 bocap@postgres=# \h create subscription
Command:     CREATE SUBSCRIPTION
Description: define a new subscription
Syntax:
CREATE SUBSCRIPTION subscription_name
    CONNECTION 'conninfo'
    PUBLICATION publication_name [, ...]
    [ WITH ( subscription_parameter [= value] [, ... ] ) ]

10001 bocap@postgres=# create subscription test_first_sub connection 'port=10000 dbname=postgres user=bocap' publication test_first_pub;
NOTICE:  created replication slot "test_first_sub" on publisher
CREATE SUBSCRIPTION
10001 bocap@postgres=# select * from test_logical_rep ;
 c1 |         c2         
----+--------------------
  1 | 0.709808008279651
  2 | 0.426817617379129
  3 | 0.973640063311905
  4 | 0.729786423034966
  5 | 0.0786650250665843
(5 rows)

10001 bocap@postgres=#  

Mặc định Logical Replication thực hiện đồng bộ dữ liệu ở chế độ không đồng bộ (Async). Nếu muốn thực hiện đồng bộ dữ liệu ở chế độ đồng bộ (Sync), bạn cần:

  • Chỉ định tên của Subscription qua tham số application_name trong thông tin connection khi CREATE SUBSCRIPTION.
  • Chỉ đinh tên của Subscription này trong tham số synchronous_standby_names (postgresql.conf) phía Publication.
  1. Thao tác cơ bản
-- Insert dữ liệu phía PUBLICATION  
10000 postgres@postgres=# insert into test_logical_rep select 6,random()::text;
INSERT 0 1
10000 postgres@postgres=# table  test_logical_rep;
 c1 |         c2         
----+--------------------
  1 | 0.709808008279651
  2 | 0.426817617379129
  3 | 0.973640063311905
  4 | 0.729786423034966
  5 | 0.0786650250665843
  6 | 0.50799278402701
(6 rows)

10000 postgres@postgres=#  

-- Xác nhận dữ liệu cập nhật phía SUBSCRIPTION   
10001 bocap@postgres=# table  test_logical_rep;
 c1 |         c2         
----+--------------------
  1 | 0.709808008279651
  2 | 0.426817617379129
  3 | 0.973640063311905
  4 | 0.729786423034966
  5 | 0.0786650250665843
  6 | 0.50799278402701
(6 rows)

-- Cập nhật dữ liệu phía PUBLICATION  
10000 postgres@postgres=# update test_logical_rep set c2 = random()::text where c1 = 6;
UPDATE 1
10000 postgres@postgres=# delete from test_logical_rep where c1 = 6;
DELETE 1
10000 postgres@postgres=# table  test_logical_rep;
 c1 |         c2         
----+--------------------
  1 | 0.709808008279651
  2 | 0.426817617379129
  3 | 0.973640063311905
  4 | 0.729786423034966
  5 | 0.0786650250665843
(5 rows)

-- Xác nhận thông tin cập nhật phía SUBSCRIPTION  
10001 bocap@postgres=# table  test_logical_rep;
 c1 |         c2         
----+--------------------
  1 | 0.709808008279651
  2 | 0.426817617379129
  3 | 0.973640063311905
  4 | 0.729786423034966
  5 | 0.0786650250665843
(5 rows)
  1. Chú ý
  • Câu lệnh TRUNCATE chưa support
-- Truncate phía PUBLICATION   
10000 postgres@postgres=# truncate test_logical_rep ;
TRUNCATE TABLE
10000 postgres@postgres=# table test_logical_rep;
 c1 | c2 
----+----
(0 rows)

-- Xác nhận cập nhật phía SUBSCRIPTION  
10001 bocap@postgres=# table  test_logical_rep;
 c1 |        c2         
----+-------------------
  1 | 0.709808008279651
  2 | 0.426817617379129
  3 | 0.973640063311905
  4 | 0.729786423034966
  5 | 0.918787303380668
(5 rows)
  • Conflict có thể xảy ra
    Khác với streaming replication, phía SUBSCRIPTION cũng có thể thực hiện các câu lệnh update. Thêm nữa là thao tác giữa PUBLICATION và SUBSCRIPTION là độc lập, không support cơ chế MVCC. Vậy nên dữ liệu có thể xảy ra conflict nếu thao tác xử lý trên SUBSCRIPTION không nhất quán với phía PUBLICATION.
    Đăng kí nhận RSS - logical replication