Logical Decoding and Slots

PostgreSQL Logical Decoding and Replication Slots

PostgreSQL 1,289 writes every change to its write-ahead log (WAL). With wal_level = logical (set once by cdc/up.sh, with a restart) it logs enough to rebuild row changes, and logical decoding turns the WAL into inserts, updates and deletes through an output plugin; the built-in pgoutput needs no extension. A publication names the tables to decode, and a replication slot remembers how far one consumer has confirmed, so the server keeps every WAL segment that consumer still needs. BookNest's side of the setup:

cdc/setup.sql (excerpt): a replication role and a publicationSQL
CREATE ROLE debezium WITH LOGIN REPLICATION PASSWORD 'cdc-sample-password';
GRANT SELECT ON orders TO debezium;               -- for the initial snapshot
CREATE PUBLICATION booknest_cdc FOR TABLE orders; -- what pgoutput may decode

The connector creates its slot itself. That slot is also the main operational risk: it holds WAL for the whole server, not only for published tables. cdc/c4.sh paused the connector, wrote 1 million rows to an unrelated table, resumed it, and measured how far the slot's confirmed position trailed the current WAL position:

Output of 44
02:53:46 start                      100 kB
02:53:55 paused, 1M rows written    92 MB
02:55:25 resumed, 90 s later        93 MB
02:56:31 heartbeat on, caught up    440 bytes

Resuming did not help: with no change to orders, Debezium 317,608 had no position to confirm, so on a busy server with a quiet captured table the retained WAL grows until the disk fills. The fix is a heartbeat: heartbeat.interval.ms=10000 with a heartbeat.action.query that updates a one-row table in the publication gives the connector a fresh position every 10 seconds; the slot caught up within about a minute, after Kafka Connect 129 's next offset commit. Also set max_slot_wal_keep_size (PostgreSQL 13+) so a forgotten slot is invalidated before it fills the disk, and monitor pg_replication_slots.