top of page

Change Data Capture

  • Writer: Pradeep P
    Pradeep P
  • 3 days ago
  • 3 min read

Layer 4 · Post 11 of 11

← Previous: Event Sourcing → Next: Containers

Layer 4 — Data · Post 50 of 88

Change Data Capture streams database writes as events so other systems can react without polling or dual-writing.

What you'll learn

  • How the WAL / binlog becomes a stream (Debezium, DynamoDB Streams, logical replication)

  • Why CDC beats dual writes for "DB plus Kafka plus search"

  • Ordering, deletes, schema change, and the exactly-once story you will be asked about

The idea in one minute

Change Data Capture (CDC) watches the database's own log and emits row-level events: this order was inserted, this quantity went from 5 to 4, this user was deleted.

You already paid for durability in ACID (the WAL). CDC reuses that log so other systems see the same commits, in commit order, without a second write in app code.

App --> BEGIN/COMMIT --> Postgres WAL | CDC connector | v Kafka --> search, cache, warehouse, saga consumers

Local ACID stays the source of truth. Eventual copies — replicas, CQRS views, warehouses — catch up from the log.

Why it matters

Dual write (db.save(); kafka.send()) is the bug posts 45–47 exist to avoid. An outbox table is a manual CDC: same transaction, later publisher. Real CDC reads the WAL so application code stays boring.

Interview designs that say "service A notifies B" should mention CDC or outbox, not polling updated_at.

How it works

  1. The engine writes changes to WAL (Postgres), binlog (MySQL), or a change stream (DynamoDB Streams, MongoDB change streams, SQL Server CDC).

  2. A connector (Debezium is the usual Kafka one) tails that log, decodes row images, and publishes to a topic per table (or a filtered subset).

  3. Consumers project (CQRS), index (Elasticsearch), ETL (Snowflake), or trigger workflows. They use the primary key + log offset (or LSN) for idempotency.

  4. Snapshots: first run often dumps current table state, then switches to streaming. Deletes and PK updates are first-class; your consumer must handle tombstones.

You get at-least-once delivery almost always. Exactly-once is "idempotent consumer + offset tracking," not a magic Kafka flag you set and forget.

Schema evolution: add a column, consumers must tolerate it. Debezium can include schema in the message (Avro/Registry). Breaking changes still break projections.

A simple example

Orders live in Postgres. You need Elasticsearch for search and a warehouse for finance. Debezium streams orders and order_items to Kafka. One consumer updates Elastic; another loads Snowflake. Checkout code only COMMITs to Postgres. If Kafka is down, the WAL retains (until you fill the disk — slot lag is a pager, not a footnote). When Kafka returns, CDC continues. No missing "we charged but did not publish."

DynamoDB Streams plus Lambda is the same idea on AWS: cache invalidation, not a second PutItem in the app.

Common mistakes

Unreplicated slot / binlog consumer down, disk fills, primary dies. CDC is a production dependency. Monitor LSN lag.

Treating CDC events as domain events. A qty update is not InventoryReserved. You can derive domain events, but a raw row change is a poor saga API.

No handling for deletes or PK changes. Search still shows the user.

Using CDC as a two-way sync between two writers. You just built a conflict machine. One source of truth.

How this shows up in real systems

  • Debezium + Kafka on Postgres/MySQL/SQL Server/MongoDB.

  • Postgres logical replication (even without Kafka) to followers and warehouses.

  • DynamoDB Streams, Cosmos DB change feed, MongoDB change streams.

  • Fivetran / Airbyte / Datastream: CDC into analytics.

  • Outbox pattern: CDC-of-a-table you control when you do not want to stream every row.

Recap

  • CDC turns the database log into a stream so copies stay eventual, not dual-written.

  • Layer 4's path: local ACID, then isolation and locks; across systems, 2PC or sagas; CQRS and event sourcing for models; CDC feeds copies without dual writes.

  • Infrastructure is next: how you package and run all of this.

Layer 4 · Post 11 of 11

← Previous: Event Sourcing → Next: Containers

Comments


About Me

DSC_7604.jpg

Hi, I am a software engineer from Bangalore, India. Love spending time on gaming and photography. This website is where I will ocassionally throw what comes to my mind. Hope it is useful or at least entertaining to you. :)

 

  • Instagram
  • Facebook
  • Twitter
  • LinkedIn
  • YouTube
  • 500px

© 2023 by Going Places. Proudly created with Wix.com

bottom of page