Logical Replication của PostgreSQL có thể chỉ truyền một phần bảng bằng row filter và chỉ truyền các cột được chọn bằng column list. Đây là công cụ hữu ích để tách workload đọc, di chuyển từng tenant hoặc dựng database phục vụ tích hợp; nhưng nó không tự đồng bộ DDL, không thay thế kiểm soát truy cập và có thể giữ WAL không giới hạn nếu subscriber ngừng hoạt động.
Bài viết xây quy trình production dựa trên tài liệu PostgreSQL Logical Replication, từ replica identity, publication/subscription, snapshot ban đầu đến monitoring, cutover và rollback. Luôn dùng tài liệu đúng major version ở cả publisher và subscriber vì hành vi, tùy chọn và khả năng tương thích thay đổi theo phiên bản.
1. Kiến trúc: snapshot trước, WAL tiếp nối
Publisher giải mã thay đổi logic từ WAL qua output plugin pgoutput. Khi subscription được tạo với data copy, subscriber lấy snapshot ban đầu của các bảng rồi tiếp tục nhận thay đổi phát sinh sau mốc nhất quán đó. Trong một subscription, transaction được apply theo thứ tự commit của publisher.
| Thành phần | Vai trò | Rủi ro chính |
|---|---|---|
| Publication | Chọn bảng, thao tác, hàng và cột được phát | Filter sai hoặc quên bảng mới |
| Logical slot | Giữ vị trí WAL cho subscriber | Subscriber hỏng làm WAL tích tụ đầy disk |
| Subscription | Kết nối, copy ban đầu và apply thay đổi | Conflict/DDL lệch làm worker dừng |
| Target schema | Nhận DML trên subscriber | Không được logical replication tự tạo/cập nhật |
2. Chọn use case đúng
Row filter và column list phù hợp cho database báo cáo chỉ cần một vùng dữ liệu, migration theo cohort, tích hợp chỉ cần trường công khai hoặc subscriber có schema thu gọn. Chúng không phù hợp nếu ứng dụng cần đồng bộ DDL tự động, muốn dùng như backup hoàn chỉnh, cần conflict-free multi-writer hoặc xem việc bỏ cột là ranh giới bảo mật tuyệt đối.
Logical replication truyền thay đổi DML đã chọn, không sao chép toàn bộ trạng thái vật lý như physical streaming replication. Sequence, large object, schema, role và nhiều object khác cần quy trình riêng.
3. Chuẩn bị publisher và capacity
# postgresql.conf — giá trị minh họa, phải tính theo số subscription thực tế
wal_level = logical
max_replication_slots = 10
max_wal_senders = 10
Sau khi áp dụng theo đúng restart/reload context của version, kiểm tra giá trị effective bằng SHOW. Tài khoản replication cần quyền LOGIN, REPLICATION, quyền kết nối database và quyền SELECT cần thiết cho initial copy. Giới hạn mạng và pg_hba.conf tới đúng subscriber, bắt buộc TLS khi đi qua mạng không tin cậy.
Subscriber cũng cần đủ worker slot cho apply, table synchronization và parallel apply nếu dùng. Không đặt mọi giới hạn bằng nhau theo thói quen; lập capacity plan cho số subscription hoạt động đồng thời và các đợt initial sync.
4. Replica identity quyết định UPDATE/DELETE tìm hàng nào
Mặc định PostgreSQL dùng primary key làm replica identity. Nếu publication phát UPDATE hoặc DELETE, publisher phải có identity phù hợp để subscriber tìm đúng hàng. REPLICA IDENTITY FULL dùng toàn bộ hàng cũ làm khóa tìm kiếm và có thể rất đắt; chỉ dùng như fallback đã đo.
Ví dụ muốn filter theo region trong publication có UPDATE/DELETE, cột filter phải nằm trong replica identity:
ALTER TABLE orders
ALTER COLUMN region SET NOT NULL;
CREATE UNIQUE INDEX CONCURRENTLY orders_replica_identity
ON orders (id, region);
ALTER TABLE orders
REPLICA IDENTITY USING INDEX orders_replica_identity;
Index dùng làm replica identity phải thỏa các điều kiện của PostgreSQL. Subscriber cần key/identity tương thích và index hiệu quả; nếu không, apply UPDATE/DELETE có thể quét tốn kém hoặc thất bại.
5. Tạo publication với row filter và column list
CREATE PUBLICATION apac_orders_pub
FOR TABLE orders (
id,
region,
customer_id,
status,
total,
updated_at
) WHERE (region = 'apac')
WITH (publish = 'insert, update, delete');
Column list phải gồm mọi cột replica identity khi phát UPDATE/DELETE. Subscriber phải có ít nhất các cột được publish; nó có thể có thêm cột nếu constraint/default cho phép apply. Row filter chỉ cho phép biểu thức theo giới hạn của PostgreSQL: không tùy ý gọi user-defined function hoặc hàm biến động.
Ví dụ chủ động loại TRUNCATE. Row filter và column list không có tác dụng với TRUNCATE; nếu publication phát thao tác này, toàn bộ table đích có thể bị truncate. Với tập con dữ liệu, thường nên không publish TRUNCATE và dùng delete có kiểm soát.
6. UPDATE đi qua biên filter được biến đổi thế nào?
| Hàng cũ khớp | Hàng mới khớp | Subscriber nhận |
|---|---|---|
| Không | Không | Không có thay đổi |
| Không | Có | INSERT |
| Có | Có | UPDATE |
| Có | Không | DELETE |
Vì vậy một order đổi từ vùng khác sang apac sẽ xuất hiện ở subscriber, còn đổi ra khỏi apac sẽ bị xóa. Ứng dụng downstream phải chấp nhận semantics này; event INSERT ở subscriber không nhất thiết là INSERT nguyên thủy tại publisher.
7. DDL phải được triển khai riêng và đúng thứ tự
Trước khi tạo subscription, dựng table đích, type, constraint và index tương thích. Logical replication không tự đồng bộ ALTER TABLE. Migration an toàn thường theo nguyên tắc expand–migrate–contract:
- Thêm schema tương thích trên subscriber trước.
- Triển khai thay đổi tương thích trên publisher.
- Cập nhật publication/column list khi cần và refresh subscription.
- Đợi lag về ngưỡng chấp nhận được, xác minh dữ liệu.
- Chỉ loại schema cũ sau khi mọi consumer đã chuyển.
Đổi kiểu không tương thích, bỏ cột sớm hoặc thêm constraint mà dữ liệu snapshot không thỏa có thể dừng initial sync/apply.
8. Tạo subscription mà không làm lộ credential
CREATE SUBSCRIPTION apac_orders_sub
CONNECTION 'host=publisher.internal port=5432 dbname=app user=replicator sslmode=verify-full'
PUBLICATION apac_orders_pub
WITH (
copy_data = true,
create_slot = true,
enabled = true
);
Không hardcode password trong migration, shell history hoặc source control. Dùng passfile/secret store trên server với quyền file chặt và quy trình rotation. CREATE SUBSCRIPTION tạo kết nối ra ngoài trong transaction; chạy từ session vận hành có kiểm soát và đọc yêu cầu quyền của đúng phiên bản.
Nếu đã nạp dữ liệu bằng cơ chế khác, copy_data=false chỉ an toàn khi chứng minh target khớp snapshot/LSN tương ứng. Nó không tự kiểm tra dữ liệu đã đồng nhất.
9. Initial copy vẫn cần capacity plan
Initial synchronization chỉ copy hàng và cột thuộc publication, nhưng tùy chọn publish='…' không giới hạn thao tác của initial data copy theo cách nhiều người kỳ vọng. Cross-version còn có khác biệt lịch sử về column list và generated column; phải kiểm tra ma trận phiên bản cụ thể.
Snapshot lớn tạo tải đọc ở publisher, ghi/index/WAL ở subscriber và giữ tài nguyên lâu. Thực hiện theo batch table, giới hạn worker, theo dõi I/O/replication lag và tránh chạy cùng maintenance nặng. Với table lớn, cân nhắc tạo index phụ sau copy, nhưng luôn giữ constraint cần cho correctness.
10. Filter cột không phải security boundary
Tài liệu PostgreSQL cảnh báo không dựa vào column list để bảo mật trước subscriber độc hại. Quyền publication hiện không thay thế một boundary truy cập dữ liệu hoàn chỉnh; role có khả năng kết nối/replicate không nên được tin chỉ vì publication đang bỏ cột nhạy cảm.
- Dùng role replication riêng, quyền tối thiểu và network allowlist.
- Không cho subscriber/operator không tin cậy truy cập publisher.
- Tách database/cluster hoặc tạo bảng sanitized nếu boundary bảo mật yêu cầu.
- Kiểm kê mọi publication vì cùng table có thể được phát ở publication khác.
- Không đặt secret trong connection string được commit hoặc log.
11. Monitoring: nhìn cả publisher lẫn subscriber
-- Publisher: slot và WAL đang bị giữ
SELECT slot_name, active, restart_lsn,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal
FROM pg_replication_slots
WHERE slot_type = 'logical';
-- Subscriber: worker và tiến độ nhận
SELECT subname, pid, relid, received_lsn,
latest_end_lsn, latest_end_time
FROM pg_stat_subscription;
-- Subscriber: lỗi/conflict tích lũy
SELECT * FROM pg_stat_subscription_stats;
Alert theo retained WAL bytes, slot inactive, apply worker vắng mặt, thời gian từ message cuối, apply errors và disk headroom. Một slot inactive không tự vô hại: nó vẫn có thể giữ WAL. Đồng thời đo data freshness ở tầng nghiệp vụ, vì worker “đang chạy” chưa chứng minh mọi table đúng.
12. Conflict và kỷ luật single-writer
Subscriber nên read-only đối với bảng replicated. Ghi cục bộ có thể tạo unique conflict làm apply dừng; update/delete không tìm thấy hàng có thể bị bỏ qua tùy trường hợp, dẫn tới sai lệch kín. DDL, trigger, RLS và quyền của subscription owner cũng có thể làm apply lỗi.
Không bỏ qua transaction bằng LSN như phản xạ đầu tiên: skip toàn transaction có thể loại cả thay đổi hợp lệ và làm target không nhất quán. Quy trình sự cố cần lưu log/LSN, xác định nguyên nhân, sửa dữ liệu hoặc schema, chạy đối soát rồi mới resume. Nếu buộc skip, ghi lại reconciliation bắt buộc.
13. Partition, nhiều publication và refresh
Với partitioned table, publish_via_partition_root ảnh hưởng identity, schema, row filter và column list nào được dùng. Test cả INSERT và UPDATE làm row chuyển partition. Không suy rằng filter đặt ở parent luôn được áp dụng như mong muốn cho mọi cấu hình.
Khi một subscription kết hợp nhiều publication, row filter cho cùng table có thể được OR theo quy tắc của PostgreSQL; column list không tương thích giữa các publication có thể làm replication lỗi. Thay đổi publication trên hệ đang chạy cần review dependency và dùng ALTER SUBSCRIPTION ... REFRESH PUBLICATION có chủ đích.
14. Cutover, validation và rollback
- Đóng băng DDL ngoài kế hoạch; xác nhận slot, worker và disk headroom.
- So sánh count theo partition/cohort, checksum theo chunk và business invariant.
- Đợi lag về ngưỡng cutover; dừng hoặc redirect writer theo runbook.
- Ghi nhận LSN/mốc thời gian, chạy validation cuối và chuyển traffic đọc/ghi.
- Giữ publisher cũ read-only trong cửa sổ rollback; không cho dual-write tự phát.
- Chỉ drop subscription/slot sau khi rollback window kết thúc và xác minh đúng tên slot.
Drop subscription có thể tác động slot từ xa tùy trạng thái/kết nối. Nếu publisher không truy cập được, xử lý slot theo tài liệu và runbook rõ ràng; không xóa nhầm slot còn giữ cho consumer khác.
Checklist production
- Major-version compatibility và feature matrix đã được kiểm tra.
- Publisher có replica identity phù hợp cho UPDATE/DELETE và cột filter.
- Column list chứa identity; TRUNCATE được loại hoặc chấp nhận có chủ đích.
- Target schema được deploy trước và migration có thứ tự.
- Credential replication nằm trong secret/passfile, dùng TLS và quyền tối thiểu.
- Initial copy có capacity window và validation theo chunk.
- Subscriber không nhận ghi ứng dụng ngoài kế hoạch.
- Retained WAL, slot activity, apply errors, lag và disk được alert.
- Partition/multi-publication semantics đã test bằng thay đổi thật.
- Cutover và rollback ghi rõ writer authority, LSN và thời điểm xóa slot.
Kết luận
Row filter và column list biến PostgreSQL Logical Replication thành công cụ di chuyển và phân phối dữ liệu có chọn lọc rất linh hoạt. Đổi lại, đội vận hành phải quản lý replica identity, DDL, slot retention, conflict và semantics khi hàng đi qua biên filter. Khi publication được xem là contract có version, subscriber giữ kỷ luật single-writer và cả dữ liệu lẫn WAL đều được giám sát, mô hình này có thể hỗ trợ migration/cutover an toàn mà không cần sao chép toàn bộ database.




Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.