Các cách bắt thay đổi trong Postgres
(blog.sequin.io)- Để truyền các thay đổi của Postgres sang hệ thống khác theo thời gian thực, cần có CDC (Change Data Capture); từ thông báo đơn giản đến sao chép dựa trên WAL, mỗi lựa chọn có độ tin cậy và gánh nặng vận hành rất khác nhau
- Listen/Notify là cách nhẹ nhất để bắt đầu, nhưng do đặc tính truyền at-most-once, thông báo tạm thời và giới hạn payload 8000 byte, nó gần với tín hiệu bổ trợ hơn là CDC cốt lõi
- Polling bảng và bảng audit (outbox pattern) có thể triển khai chỉ với bảng tiêu chuẩn và trigger, nhưng bạn phải tự giải quyết việc phát hiện xóa, diff, thứ tự commit, write amplification và backpressure
- Logical replication là cách mạnh mẽ để stream insert/update/delete từ WAL, nhưng ứng dụng phải tự quản lý replication slot, ack, khởi động lại và khả năng xử lý lưu lượng
- Sequin dựa trên logical replication của Postgres để chuyển thay đổi tới SQS, Kafka, Elasticsearch, Redis, HTTP endpoint và hơn thế nữa, giúp giảm gánh nặng phải trực tiếp xử lý replication slot
Khi nào cần Postgres CDC
- Postgres rất mạnh trong việc xử lý dữ liệu được lưu trữ, nhưng nếu muốn kích hoạt workflow từ thay đổi bảng hoặc stream theo thời gian thực sang kho dữ liệu, hệ thống hay dịch vụ khác thì cần thiết kế riêng phần di chuyển dữ liệu
- Change Data Capture (CDC) là cách xác định, ghi nhận các thay đổi trong cơ sở dữ liệu rồi truyền chúng theo thời gian thực tới các hệ thống downstream
- Có nhiều cách để bắt thay đổi trong Postgres, và độ khó triển khai, độ ổn định cũng như gánh nặng vận hành của chúng rất khác nhau
Listen/Notify: pub-sub đơn giản nhất
- Listen/Notify của Postgres là tính năng giao tiếp giữa các tiến trình, hoạt động theo mô hình publish-subscribe
- Một session có thể
listentrên một channel cụ thể, còn hoạt động trong cơ sở dữ liệu hoặc session khác có thể gửinotifytới channel đó - Có thể dùng nó cho việc bắt thay đổi bằng cách gắn trigger
- Trigger ví dụ sẽ ở thời điểm
after insert or update or delete, tạo JSON chứatable,id,actioncủa record đã thay đổi và gọipg_notify('table_changes', payload::text)
- Trigger ví dụ sẽ ở thời điểm
- Các giới hạn của nó khá rõ ràng
- Nó có ngữ nghĩa truyền at-most-once, và listener phải đang kết nối tại thời điểm thông báo được phát ra
- Listener chỉ nhận được thông báo kể từ sau khi đăng ký, nên chỉ cần ngắt mạng trong chốc lát cũng có thể bỏ lỡ thông báo
- Giới hạn kích thước payload là 8000 byte; vượt quá mức này thì lệnh
notifysẽ thất bại - Kích thước payload cũng tính cả tên channel, và tên channel giống như identifier của Postgres, có thể dài tối đa 64 byte
- Nó có thể hữu ích cho phát hiện thay đổi cơ bản hoặc tối ưu polling bảng, nhưng có thể không phù hợp với các yêu cầu CDC phức tạp
Polling bảng: đơn giản nhưng yếu ở xóa và diff
- Cách bắt thay đổi vững chắc đơn giản nhất là polling trực tiếp bảng
- Mỗi bảng cần một cột như
updated_atđược cập nhật mỗi khi hàng thay đổi; nếu cần có thể tạo bằng trigger - Dùng kết hợp
updated_atvàidlàm cursor, còn logic ứng dụng sẽ lưu và quản lý cursor đó - Nếu kết hợp thêm đăng ký Notify thì có thể báo cho ứng dụng biết khi có bản ghi được thêm hoặc sửa, từ đó giảm tần suất polling
- Vì thông báo của Postgres là tạm thời, nên phù hợp nhất là chỉ dùng như lớp tối ưu bên trên polling
- Có ba nhược điểm chính
- Hàng đã xóa không còn trong bảng nên không thể phát hiện xóa
- Một cách khắc phục là để trigger delete lưu
idvà các cột cần thiết vào bảng riêng nhưdeleted_contacts, rồi ứng dụng polling bảng đó - Bạn có thể biết rằng record đã được cập nhật, nhưng không biết cái gì đã thay đổi
- Datetime và sequence của Postgres có thể không khớp với thứ tự commit, nên khi đọc theo block dựa trên
updated_at, bạn có thể bỏ sót những hàng vẫn đang commit
- Với các trường hợp theo dõi thay đổi đơn giản, nơi việc xóa, diff hay bỏ sót thỉnh thoảng không phải vấn đề lớn, đây là lựa chọn hợp lý
Bảng audit: lưu log thay đổi theo outbox pattern
- Cách dùng bảng audit (audit table) là ghi lại thay đổi vào một bảng
changelogriêng, còn được gọi là outbox pattern changelogcó thể chứa các cột liên quan tới thay đổiaction: làinsert,updatehaydeleteold:jsonbcủa record trước khi thay đổi, để trống với insertvalues:jsonbcủa các trường đã thay đổi, để trống với deleteinserted_at: thời điểm thay đổi xảy ra
- Để triển khai, cần hàm trigger chèn vào
changelogmỗi khi có thay đổi, cùng các trigger cho từng bảng cần theo dõi - Cũng có thể tiêu thụ
changelognhư một hàng đợi- Worker của ứng dụng lấy các thay đổi từ bảng
- Có thể dùng
for update skip lockedcủa Postgres để xử lý gần mức exactly-once - Worker có thể mở transaction, khóa một lô bằng
order by timestamp limit 100 for update skip locked, xử lý chúng, xóa các record đã xử lý rồi commit
- Có một số nhược điểm về vận hành
- Một lần ghi vào bảng gốc có thể tạo ra nhiều lần ghi vào bảng audit, gây write amplification
- Thông thường sẽ có ít nhất ba lần ghi: insert ban đầu vào bảng audit, update trong lúc xử lý và delete sau khi xử lý xong
- Cách fan-out bằng worker phải được tự thiết kế cho phù hợp với ứng dụng
- Trước khi triển khai ở quy mô production, có thể phải tinh chỉnh hàm trigger và thiết kế bảng
- Cũng có thể cần cân nhắc các chính sách chi tiết như giới hạn thời gian worker được giữ thay đổi đã checkout
- Nếu worker không xử lý thành công thì bảng audit vẫn tiếp tục đầy lên, nên việc quản lý backpressure còn yếu
Foreign Data Wrapper: lựa chọn gần với đồng bộ giữa các Postgres cụ thể
- Foreign Data Wrapper (FDW) là tính năng cho phép cơ sở dữ liệu Postgres đọc và ghi vào nguồn dữ liệu bên ngoài
- Extension dựa trên FDW được hỗ trợ rộng rãi nhất là
postgres_fdw- Nó cho phép kết nối hai cơ sở dữ liệu Postgres và tạo một cấu trúc giống view để một cơ sở dữ liệu tham chiếu bảng của cơ sở dữ liệu kia
- Về bản chất, một cơ sở dữ liệu Postgres đóng vai trò client còn cơ sở dữ liệu kia là server
- Khi truy vấn foreign table, cơ sở dữ liệu client sẽ gửi truy vấn tới cơ sở dữ liệu server qua wire protocol của Postgres
- FDW không phải là cách phổ biến để bắt thay đổi, và ngoài một số tình huống rất đặc thù thì khó có thể khuyến nghị
- Nếu bạn muốn ghi thay đổi từ một cơ sở dữ liệu Postgres sang một cơ sở dữ liệu Postgres khác, FDW có thể phù hợp
- Ví dụ là khi dùng riêng một cơ sở dữ liệu cho kế toán và một cơ sở dữ liệu cho ứng dụng
- Thay vì qua bước bắt thay đổi trung gian, có thể phản ánh trực tiếp giữa các cơ sở dữ liệu bằng
postgres_fdw
- Cũng có thể tự tạo FDW để POST thay đổi tới API nội bộ
- Vì việc ghi vào API xảy ra trong commit, API có thể từ chối thay đổi và rollback commit
- FDW rất mạnh, nhưng hiếm khi là lựa chọn tốt nhất cho CDC; còn tự viết FDW thì gần như là công việc lớn nhất trong số các cách bắt thay đổi
- Việc tự viết FDW đã dễ hơn nhờ các công cụ như Supabase wrappers, nhưng vẫn là một việc lớn
Tự triển khai logical replication: CDC mạnh mẽ dựa trên WAL
- Postgres có một giao thức dành cho sao chép cơ sở dữ liệu, và một trong số đó là logical replication
- Logical replication được xây dựng trên WAL (write-ahead log) của Postgres
- Mọi thao tác insert, update, delete trong cơ sở dữ liệu đều được theo dõi
- Các thay đổi được stream tới subscriber
- Người dùng trước tiên tạo replication slot trên primary
- Dùng dạng
pg_create_logical_replication_slot('<your_slot_name>', '<output_plugin>')
- Dùng dạng
output_pluginchỉ định plugin dùng để giải mã các thay đổi trong WALpgoutputlà plugin mặc định, xuất ra định dạng nhị phân mà server client mong đợitest_decodinglà plugin đầu ra đơn giản, cung cấp thay đổi WAL ở dạng con người có thể đọc được- Dù không phải plugin tích hợp sẵn của Postgres,
wal2jsonlà plugin phổ biến và JSON dễ dùng hơn định dạng nhị phân của Postgres như một điểm bắt đầu cho ứng dụng
- Sau khi tạo replication slot, bạn có thể bắt đầu và tiêu thụ dữ liệu
- Replication slot dùng một phần giao thức Postgres khác với truy vấn tiêu chuẩn
- Nhiều thư viện client cung cấp các hàm hỗ trợ làm việc với replication slot
- Ví dụ với
psycopg2, có thể dùngcursor.start_replication(...)vàcursor.consume_stream(...)để tiêu thụ thông điệp WAL, rồi gửi ack bằngcursor.send_feedback(flush_lsn=msg.wal_end)
- Client phải ack các thông điệp WAL đã nhận; replication slot hoạt động khá giống Kafka có offset
- Logical replication là cách vững chắc được tạo ra dành cho CDC, nhưng nó phức tạp
- Replication slot và replication protocol ít quen thuộc hơn với lập trình viên so với bảng và truy vấn thông thường
- Cần chiến lược để không bỏ lỡ thông điệp khi khởi động lại
- Hệ thống cũng phải được thiết kế để xử lý lượng lớn thông điệp phát ra từ Postgres
Sequin: công cụ CDC bọc quanh logical replication
- Sequin là công cụ CDC chuyển các thay đổi và hàng của Postgres tới hàng đợi, stream, search index, cache, HTTP endpoint và hơn thế nữa
- Các đích bao gồm SQS, Kafka, Elasticsearch, Redis, HTTP endpoints...
- Sequin dùng logical replication của Postgres ở bên trong, nhưng trừu tượng hóa độ phức tạp của giao thức low-level
- Nó có thể bắt cả insert, update, delete; với update và delete, nó ghi nhận cả giá trị
newvàoldcủa hàng - Những điều kiện để cân nhắc Sequin gồm
- Cần CDC theo thời gian thực
- Muốn stream trực tiếp tới đích như SQS hoặc webhook mà không cần hệ thống trung gian
- Cần các tính năng như backfill dữ liệu lịch sử và lọc thay đổi dựa trên mệnh đề SQL
where - Cần một lựa chọn đơn giản hơn so với tự quản lý replication slot
- Cần đảm bảo xử lý exactly-once
- Nó cũng có nhược điểm
- Sequin không phải extension bên trong Postgres mà là công cụ bên thứ ba chạy cạnh cơ sở dữ liệu
- Vì không phải extension nên nó tương thích rộng với nhiều cơ sở dữ liệu Postgres, nhưng nếu không dùng Sequin Cloud thì bạn sẽ phải tự dựng thêm hạ tầng
Tiêu chí lựa chọn
- Ở giai đoạn bắt đầu, Listen/Notify và polling bảng là phù hợp
- Listen/Notify tốt cho việc bắt các sự kiện không quan trọng, tạo prototype và tối ưu polling
- Polling là lời giải ổn, đơn giản và trực diện cho các trường hợp dùng cơ bản
- Ở giai đoạn nghiêm túc hơn, bảng audit có thể là lựa chọn trung gian
- Có thể bắt được payload
newvàoldcủa hàng - Nếu làm đúng, bạn có thể có một hệ thống xử lý exactly-once
- Khi mở rộng, write amplification và thiếu backpressure sẽ trở thành vấn đề; ngoài ra cấu hình thủ công dễ làm rơi thông điệp
- Có thể bắt được payload
- Ở giai đoạn mở rộng, logical replication là lựa chọn gần nhất với một lời giải vững chắc
- Tuy vậy, nên dùng công cụ như Sequin thay vì tự đọc trực tiếp từ slot
- FDW là một tính năng thú vị, nhưng khả năng giải quyết các nhu cầu CDC phổ biến là khá thấp
1 bình luận
Các ý kiến trên Hacker News
Trigger + bảng lịch sử (bảng audit) là đáp án đúng trong 98% trường hợp. Nếu chưa dùng thì có thể bắt đầu dùng từ hôm nay. Đây là kỹ thuật đã được kiểm chứng hơn 30 năm
Một ví dụ đơn giản về cách triển khai generic có ở https://gist.github.com/slotrans/353952c4f383596e6fe8777db5d.... Cách này đánh đổi hiệu quả không gian để chọn “dễ triển khai”
Nếu có thể lưu dữ liệu bất biến thì thật sự rất tốt, nhưng trong database có lẽ có rất nhiều dữ liệu khả biến, và khả năng cao là mỗi ngày bạn đang quên rất nhiều thứ. Đừng quên, hãy dùng bảng lịch sử
Tham khảo: https://github.com/matthiasn/talk-transcripts/blob/master/Hi...
Không nên dùng các thư viện hay kỹ thuật theo dõi lịch sử ở tầng ứng dụng như Papertrail. Chúng chậm, dễ lỗi, và không bắt được các thay đổi DB đi vòng qua app stack. Việc cố gắng đóng dấu timestamp
updatedtừ ứng dụng cũng sai về căn bản, vì mỗi web server có đồng hồ khác nhau. Phải dùng đồng hồ DB, đó là chiếc đồng hồ duy nhất đúngnow()vào trong query để dùng đồng hồ DBNhưng chỉ timestamp này thôi thì chưa đủ để đồng bộ. Lý do là timestamp được tạo tại thời điểm bắt đầu transaction, không phải thời điểm commit transaction
Nếu polling bảng và lọc theo timestamp gần đây, bạn có thể bỏ sót một phần các transaction có thứ tự commit bị đảo lộn. Có thể đặt một khoảng đệm bằng cách truy vấn lùi thêm vài phút và loại bỏ trùng lặp, nhưng trong PostgreSQL thời gian transaction là không giới hạn, và truy vấn quá sâu về quá khứ sẽ rất lãng phí. Nếu độ chính xác và hiệu quả quan trọng thì cách này không phù hợp
Nếu dùng log sequence number, thời gian DB và
REPLICA IDENTITY FULL, nó còn bao gồm cả trạng thái trước/sau thay đổi. Sau đó, khi materialize collection sang nơi như Snowflake, mặc định bạn sẽ có bảng đồng bộ bám theo các cập nhật của source DBCũng có thể chuyển đổi hoặc materialize toàn bộ lịch sử bảng phục vụ mục đích audit từ cùng data lake nền tảng đó, nên không cần gắn thêm capture hay WAL reader vào source DB nữa
Tôi cũng giải thích riêng một cách SQLite triển khai pattern tương tự theo kiểu dựa trên cột thay vì JSON: https://simonwillison.net/2023/Apr/15/sqlite-history/
Bài viết này tóm tắt ngắn gọn và tốt nhiều cách tiếp cận có thể làm bằng các tính năng cơ bản của Postgres
Ở phần “capture thay đổi vào bảng audit”, tại công ty trước đây chúng tôi đã dùng tốt pattern Temporal Tables. Khác với các RDBMS lớn khác, Postgres không tích hợp sẵn tính năng này, nhưng có một pattern đơn giản có thể dùng bằng SQL function: https://github.com/nearform/temporal_tables
Bạn có thể xem trạng thái của bảng tại một thời điểm cụ thể, nên trả lời được các câu hỏi như “cài đặt của người dùng này vào ngày 12/8 là gì”, “lúc 11:55 tối qua có bao nhiêu record chưa xử lý”, “hãy cho xem khác biệt về feature flag giữa hiện tại và một tuần trước”
Tôi từng tư vấn cho một công ty có một SQL Server nguyên khối rất lớn. Nó không phải Postgres, nhưng giả sử là Postgres thì cũng tương tự
Nó đã vận hành suốt hàng chục năm, được dùng cho đủ mọi mục đích trong công ty, và về cơ bản mọi ứng dụng cùng quy trình nghiệp vụ của toàn công ty đều lưu dữ liệu vào cơ sở dữ liệu này
Vấn đề là có rất nhiều ứng dụng truy vấn DB này, và cũng có vô số quy trình, thủ tục chèn/sửa dữ liệu, nên khi các quy trình chèn/sửa ở thượng nguồn thay đổi hoặc được thêm mới, chúng bắt đầu phá vỡ các bất biến ở cấp ứng dụng. Ngay cả các quy trình bình thường cũng hoạt động khác đi khi có dữ liệu xấu
Việc truy vết nguyên nhân cực kỳ khó, vì những thứ cần xem thường được viết từ 10 năm trước và những nhân viên đó đã rời công ty từ lâu
Tôi tự hỏi liệu có thể ghi nhận các thay đổi trong cơ sở dữ liệu Postgres dưới dạng một DAG nào đó, để biết quy trình nào chèn/sửa/xóa dữ liệu, lịch sử hành vi của chúng ra sao, nhiều ứng dụng truy vấn dữ liệu này như thế nào và thống kê truy vấn thay đổi ra sao theo thời gian hay không
Tôi không rõ đã có tiền lệ nào như vậy chưa, hay cách tiếp cận nào có thể dùng để xây một công cụ như thế. Trước đây tôi từng nghĩ đến việc làm thứ tương tự, nhưng có vẻ đây là lĩnh vực đòi hỏi mức hiểu biết ngang kỹ sư lõi Postgres để đưa ra lựa chọn tốt
Với mỗi thay đổi, bạn sẽ không lấy được dữ liệu nguồn gốc ở cấp client
Dù vậy vẫn có cách обход. Luồng logical replication cũng có thể bao gồm các thông điệp thông tin từ hàm
pg_logical_emit_message, nên client có thể tự đưa metadata vào. Có lẽ có thể cấu hình để phát ra định danh client ở đầu mỗi transactionlast updated by). Có thể đây là anti-pattern, nên nếu có giải pháp vững chắc hơn thì tốtCách tiếp cận này hoạt động với hầu hết các giải pháp họ SQL dùng WAL hoặc trigger
Trong SQL Server tôi đã dùng cách trigger nhiều lần, nhưng nếu log mọi truy vấn thì thường bị chậm. Thiết kế cơ chế insert không cản trở vận hành không phải chuyện hoàn hảo, và có thể cần sampling
Nếu đi theo hướng “bảng audit” thì cứ dùng pgaudit là được. Đây là extension đã được kiểm chứng trong thực tế, và nếu dùng AWS thì cũng dùng được trên RDS
https://github.com/pgaudit/pgaudit/blob/master/README.md
https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appen...
https://github.com/arkhipov/temporal_tables
https://news.ycombinator.com/item?id=26748096
Không nhất thiết phải làm. Việc muốn thứ này nghĩa là biến các quan hệ của Postgres thành hợp đồng. Khi đó không dịch vụ nào có thể bền vững hóa trạng thái nội bộ nữa
Nếu bạn thật sự dồn toàn lực vào thiết kế hướng miền thì có thể làm được, nhưng tốt hơn là dùng một hệ thống dựa trên sự kiện vừa nhẹ vừa thực tế
Một thứ dựa trên sự kiện phức tạp hơn gấp 1000 lần
Cách polling cột
updated_atở dạng đơn giản nhất không vững chắc. Lý do là không có gì đảm bảo các transaction sẽ commit theo đúng thứ tự đóupdated_atcủa Row 1 được đặt thành2023-09-22 12:00:01Một lát sau transaction B bắt đầu,
updated_atcủa Row 2 được đặt thành2023-09-22 12:00:02, và B commit trướcTruy vấn polling chạy, coi Row 2 là thay đổi mới nhất và cập nhật con trỏ thành
2023-09-22 12:00:02, rồi sau đó A mới commit thì sẽ bỏ lỡ Row 1Cách đơn giản để tránh vấn đề này là đừng polling gần như theo thời gian thực. Thứ tự cuối cùng rồi sẽ nhất quán
Một đề xuất vững chắc hơn có thể là dùng sequence. Ví dụ đặt một cột
updated_at_idxtăng lên mỗi khi hàng thay đổiTôi thắc mắc liệu dùng before trigger đặt
now()thì timestampupdated_atcủa hai hàng vẫn có thể khác với thứ tự commit transaction hay không.updated_atkhông cần giống commit timestamp, nhưngupdated_atphải biểu thị chính xác thứ tự commit ở mức mili giây/micro giâyupdated_at, dùng cột_txiddo trigger đặt bằng transaction ID hiện tại. Sau đó khi polling, dùngtxid_current()để kiểm tra transaction nào đã commit và transaction nào chưaHơi chênh vênh và rất dễ mắc lỗi biên, nhưng đã chạy tốt trong production suốt vài năm
Bài viết rất hay
Nếu dùng Elixir và Postgres, tôi đã làm một thư viện nhỏ theo cách tiếp cận tương tự để lắng nghe thay đổi WAL: https://github.com/cpursley/walex
Những cách này đều không ổn lắm; cá nhân tôi thấy polling là thực tế nhất
Mong Postgres sẽ đổi mới trong mảng này
Tôi nghĩ trước khi nó được đưa vào tiêu chuẩn SQL, sẽ khó có động lực trong không gian kernel của các DBMS quan hệ. Các lựa chọn thì nhiều và phức tạp, còn những giải pháp thành công ở không gian người dùng cũng không đến mức tạo gánh nặng quá lớn về hiệu năng
Nhân tiện, những người nghiên cứu lĩnh vực này nhìn chung nghiêng về cách tiếp cận bảng audit. Vì nó duy trì các thuộc tính ACID nhất quán bên trong cơ sở dữ liệu, và giữ Postgres là điểm lỗi đơn thay vì thêm proxy hay tác vụ polling
Trong thế giới dữ liệu có một khoảng trống lớn. Thay vì hỏi kho dữ liệu về kết quả, sẽ tốt hơn nếu kết quả truy vấn được push dần dần
Tôi làm khá nhiều phân tích thời gian thực/streaming; có thể dùng stream processing, và cũng có thể xử lý một phần bằng materialized view trong kho dữ liệu. Nhưng sau khi dữ liệu đã vào DB hoặc data lake, để downstream thấy thay đổi thì thực chất lại quay về polling
Khi muốn phản ứng với một tình huống nào đó xảy ra trong dữ liệu, hoặc cập nhật màn hình mà không cần refresh trang, không có nhiều giải pháp gọn gàng. Các giải pháp trong bài này cũng có vẻ giống workaround hơn là tính năng hạng nhất
Nếu muốn tạo báo cáo được cập nhật theo thời gian thực mà không refresh trang, thường sẽ là tải dữ liệu từ DB rồi đẩy thay đổi tới GUI bằng Kafka và WebSocket. Khi đó bạn vận hành một kiến trúc lambda kỳ lạ, trong đó một phần phân tích nằm trong code, một phần nằm trong DB
Có đổi mới trong lĩnh vực này. KSQL và Kafka Streams có thể phát ra thay đổi, Materialize có subscription, còn ClickHouse có live view. Tuy nhiên nhiều tính năng còn mới hoặc ở giai đoạn preview và không thật sự khớp. Tôi đã thử tất cả, nhưng cảm thấy chúng đẩy quá nhiều việc sang cho lập trình viên
Ước gì có một thư viện cho phép nhận ngay change feed bằng một tùy chọn kiểu
[select * from orders with suscribe]. Đây là lĩnh vực đủ quan trọng nhưng vẫn chưa được chú ý đúng mứcCó một cạm bẫy lớn của replication mà bài không đề cập, và vì vậy tôi không dùng replication
Postgres cố gắng đảm bảo rất mạnh rằng consumer của replication slot sẽ không bỏ lỡ dữ liệu. Vì thế nếu consumer không tiêu thụ dữ liệu từ slot, Postgres sẽ tử tế tiếp tục giữ dữ liệu bị lỡ, rồi cuối cùng đi đến mức đầy đĩa và DB sập. Tôi đã gặp chuyện này với hai DB SaaS khác nhau trong lúc prototyping, và cách duy nhất để khôi phục là gửi ticket hỗ trợ
Nếu consumer của replication slot ngừng đọc, nhất định phải có cảnh báo
Một lý do khác là code path để lấy snapshot ban đầu của bảng và code path để đọc thay đổi hoàn toàn khác nhau. Khởi tạo việc đọc replication slot sao cho không bỏ lỡ bất kỳ thay đổi nào không phải chuyện nhỏ
Đáng tiếc là xét từ góc độ change capture, replication là giải pháp ít hacky nhất
Tôi dùng polling, nhưng thay vì
updated_atthì lưu txidTôi tò mò bạn muốn hành vi nào hơn
Nếu xử lý khối lượng dữ liệu lớn, bạn sẽ muốn xử lý snapshot ban đầu và đọc thay đổi theo cách khác nhau. Vì cần có thể làm những việc như khởi tạo song song hoặc khởi tạo dựa trên backup vật lý. Tuy vậy tôi hiểu rằng một tính năng streaming có chọn lọc dữ liệu hiện có sau khi tạo slot có thể hữu ích
Phần khởi tạo đọc replication slot sao cho không bỏ lỡ thay đổi lẽ ra không nên khó, tôi tò mò bạn bị vướng ở đâu
Khi không cần mọi thay đổi, replication slot tạm thời tự dọn dẹp khi kết nối bị ngắt cũng hữu ích. Cũng có cấu hình để đặt mức tối đa cho WAL được giữ lại nhằm tránh làm sập server
Bạn có thể giải thích thêm cách dùng txid thay cho
updated_atđược không