Streaming replication (physical) sao chép cả cụm ở mức byte của WAL — mạnh cho dự phòng và đọc, nhưng cứng nhắc: toàn bộ hoặc không gì, subscriber chỉ đọc, và phải cùng phiên bản PostgreSQL. Khi bạn cần linh hoạt hơn — chỉ nhân bản vài bảng, cho đích ghi được, hay nhân bản qua hai phiên bản khác nhau — câu trả lời là logical replication. Bài này dựng thật một cặp publisher/subscriber, publish chọn lọc, và đo từng khả năng.

Cơ chế: publisher và subscriber

Logical replication không sao chép byte WAL thô. Nó giải mã WAL thành các thay đổi ở mức hàng (chèn hàng này, sửa hàng kia), rồi gửi sang đích để áp lại. Kiến trúc là publisher/subscriber:

  • Publisher khai một PUBLICATION — tập các bảng muốn công bố.
  • Subscriber khai một SUBSCRIPTION trỏ tới publication đó; nó tự copy dữ liệu ban đầu rồi nhận các thay đổi tiếp theo.

Điều kiện tiên quyết: wal_level = logical (cao hơn replica của physical), cần restart để áp.

-- PUBLISHER: chỉ công bố MỘT SỐ bảng
CREATE PUBLICATION pub_kinhdoanh FOR TABLE khach_hang, don_hang;  -- KHÔNG log_debug

Ảnh chụp đoạn mã SQL nền tối minh hoạ logical replication nhân bản theo bảng không phải cả cụm PostgreSQL 16 publisher subscriber chọn lọc bảng khác phiên bản được, điều kiện wal_level logical cần restart ALTER SYSTEM SET wal_level logical rồi restart server physical replication chỉ cần replica logical cần logical, publisher công bố chỉ một số bảng chọn lọc CREATE PUBLICATION pub_kinhdoanh FOR TABLE khach_hang don_hang không có log_debug có thể FOR ALL TABLES hoặc FOR TABLE WHERE lọc dòng PG15, subscriber tự tạo schema trước logical không copy cấu trúc CREATE TABLE khach_hang CREATE SUBSCRIPTION sub_kd CONNECTION host dbname lab user lab PUBLICATION pub_kinhdoanh tự copy dữ liệu ban đầu cộng stream tiếp, khác physical replication ở điểm nào physical cả cụm byte-level WAL subscriber chỉ đọc cùng phiên bản logical chọn bảng giải mã ra hàng subscriber ghi được khác phiên bản OK dùng logical để nâng cấp phiên bản không downtime gộp tách DB đẩy một phần dữ liệu sang hệ thống khác

Hình 1: Logical replication cần wal_level=logical. Publisher khai PUBLICATION chọn lọc bảng; subscriber tự dựng schema rồi CREATE SUBSCRIPTION. Khác physical: chọn bảng, subscriber ghi được, chạy khác phiên bản.

Đo thật: publish chọn lọc, copy, và stream

Tôi dựng ba bảng trên publisher (khach_hang 1.000 dòng, don_hang 5.000 dòng, log_debug 101 dòng) nhưng chỉ publish hai bảng đầu. Subscriber là một database riêng (sub_db) trong cùng cluster — tôi tạo trước schema hai bảng đó (logical replication không tự copy cấu trúc bảng, chỉ copy dữ liệu), rồi CREATE SUBSCRIPTION.

Ảnh chụp bảng kết quả đo thật nền tối logical replication giữa hai database lab sang sub_db PostgreSQL 16, publication chọn lọc 2 trong 3 bảng CREATE PUBLICATION pub_kinhdoanh FOR TABLE khach_hang don_hang log_debug cố ý không đưa vào, copy ban đầu tự động sau CREATE SUBSCRIPTION bảng khach_hang publisher 1000 subscriber sau sync 1000 don_hang publisher 5000 subscriber 5000 srsubstate r ready cho cả hai bảng, INSERT UPDATE DELETE trên publisher nhân bản tiếp INSERT don_hang 99999 tien 777 sub thấy tien 777 UPDATE khach_hang id 1 ten ĐÃ ĐỔI sub thấy ten ĐÃ ĐỔI DELETE don_hang id 1 sub còn 0 dòng id 1, tính chọn lọc log_debug không được nhân bản bảng log_debug trên publisher 101 dòng trên subscriber does not exist không nhân bản, trạng thái pg_replication_slots slot_kd active t pg_stat_replication sub_kd state streaming

Hình 2: Publish 2 trong 3 bảng. Sau CREATE SUBSCRIPTION, subscriber tự copy đủ 1.000 + 5.000 dòng (srsubstate=r). INSERT/UPDATE/DELETE trên publisher nhân bản tiếp. Bảng log_debug không publish thì không tồn tại ở subscriber. Slot active, walsender streaming.

Kết quả thật, từng khả năng:

1. Copy ban đầu tự động. Ngay sau CREATE SUBSCRIPTION, subscriber tự đồng bộ đủ 1.000 dòng khach_hang và 5.000 dòng don_hang (srsubstate = r — ready). Không cần tự dump/restore.

2. Thay đổi tiếp theo được stream. Tôi INSERT một đơn (id 99999, tiền 777), UPDATE tên khách id=1 thành 'ĐÃ ĐỔI', và DELETE đơn id=1 trên publisher. Sau vài giây, subscriber phản ánh đúng cả ba: đơn mới có tiền 777, tên đã đổi, đơn id=1 biến mất. Cả INSERT, UPDATE, DELETE đều nhân bản.

3. Chọn lọc thật sự. Bảng log_debug không nằm trong publication: nó có 101 dòng trên publisher nhưng không tồn tại trên subscriber (does not exist). Đây là điểm mấu chốt khác physical — bạn chọn chính xác bảng nào đi, bảng nào ở lại.

Khác physical replication ở đâu

Physical (streaming) Logical
Phạm vi Cả cụm (mọi DB) Chọn từng bảng
Cơ chế Byte WAL Giải mã ra hàng
Subscriber Chỉ đọc Ghi được
Phiên bản Phải giống Khác được

Chính vì subscriber ghi được và chạy khác phiên bản, logical replication mở ra những việc physical không làm nổi: nâng cấp phiên bản gần như không downtime (dựng cụm mới phiên bản cao, logical replicate sang, rồi chuyển tải), gộp nhiều database vào một, tách một phần dữ liệu ra hệ thống phân tích riêng.

Đánh đổi cần cân nhắc

Không copy schema, không copy DDL. Logical replication chỉ nhân bản dữ liệu, không nhân bản cấu trúc bảng hay thay đổi cấu trúc (ALTER TABLE ADD COLUMN). Bạn phải tự tạo schema ở subscriber trước, và khi đổi cấu trúc phải làm ở cả hai phía, đúng thứ tự, nếu không nhân bản sẽ lỗi. Đây là gánh vận hành thật.

Cần khoá định danh hàng (REPLICA IDENTITY). Để nhân bản UPDATE/DELETE, subscriber cần biết hàng nào bị sửa — mặc định dùng khoá chính. Bảng không có khoá chính phải khai REPLICA IDENTITY FULL (dùng cả hàng làm định danh, chậm hơn) hoặc một unique index, nếu không UPDATE/DELETE sẽ lỗi.

Tốn CPU giải mã và có thể lag. Giải mã WAL thành hàng tốn CPU hơn physical (chỉ copy byte). Trên tải ghi rất cao, logical replication có thể lag nhiều hơn — và như mọi replication, slot giữ WAL khiến publisher phình pg_wal nếu subscriber chết. Giám sát pg_replication_slots và pg_stat_replication như với physical.

Ba ý mang về

  1. Logical replication nhân bản chọn lọc theo bảng qua publisher/subscriber: dựng thật, publish 2 trong 3 bảng thì subscriber tự copy đủ 1.000 + 5.000 dòng còn bảng log_debug không publish thì không tồn tại ở đích — khác hẳn physical vốn sao cả cụm.
  2. Subscriber ghi được và chạy khác phiên bản, mở ra nâng cấp không downtime, gộp/tách database, đẩy một phần dữ liệu sang hệ thống khác — những việc physical replication (chỉ đọc, cùng phiên bản) không làm được; INSERT/UPDATE/DELETE đều nhân bản (đo thật cả ba).
  3. Cái giá là gánh vận hành: không copy schema/DDL (phải tự đồng bộ cấu trúc hai phía), cần REPLICA IDENTITY để nhân bản UPDATE/DELETE, và tốn CPU giải mã hơn physical — chọn logical khi cần sự linh hoạt, dùng physical khi chỉ cần bản sao nóng cả cụm.

Phần sau ta chuyển sang chủ đề chẩn đoán vận hành hằng ngày: Phần sau mổ xẻ pg_stat_activity — cách nhìn database đang chạy truy vấn gì, phiên nào đang chờ, và tìm ra thủ phạm khi hệ thống chậm.