thesis

i am struggling through debezium and kafka configuration right now, including heartbeat settings that are harder to reason about and harder to test than i expected. the struggle is where the posts come from, so this note is my effort to understand the overall picture. if it helps someone else who only sees the warehouse side of the stack, even better. regardless, i am writing to myself as the first reader.

context

most of my daily work still lives downstream. raw vault history, business vault rules, consumer-shaped tables, dbt models, tests. that world is difficult, but it is sql-shaped and i understand sql like it is my native language.

the streaming path into the warehouse is different. commits happen in an operational database far away from where i usually debug. events ride a bus. connectors have their own configuration language. when something is wrong, the symptom might show up as a stalled offset, a missing row, or a lag chart, not a red compiler error. i need a simple map before i could make sense of any single knob, including the debezium heartbeat i am trying to turn on right now.

quick answer

think in one straight line.

  1. the source of truth lives in an operational database. rows change over time through inserts, updates, and deletes.
  2. debezium reads the database change log and turns each change into an event.
  3. kafka holds those events on topics so many consumers can read the same stream at their own pace.
  4. downstream systems (warehouse landing, transformation jobs, dbt models, app-shaped tables) materialize what happened for analytics or products.

that sequence is the whole story at a high level. everything else is operational.

who this is for

  • data engineers who mostly live in the warehouse and want a map of their data stream
  • people enabling debezium connectors who feel lost in broker and connector docs
  • future me, before i open another yaml file without remembering where i am in the pipeline

the operational database

the operational database is where the business transaction actually happened. an order was placed, a status was updated, a colleague record was corrected. those writes are the facts.

for change capture, the important detail is that databases already record mutations internally. relational engines expose that through a transaction log or replication stream, depending on vendor and configuration. debezium hooks into that machinery. it does not need your application to emit custom events for every update, which would be easy to forget and hard to keep consistent.

when i debug downstream, i try to remember that every row in the warehouse is downstream of a commit timestamp i cannot always see from sql alone.

debezium

debezium is a change data capture (cdc) tool. its job is to watch the source database and publish structural change events when data changes.

each event usually carries enough information to know what changed.

  • which table (and schema) was affected
  • what operation occurred (create, update, delete)
  • the relevant row values before and after, depending on configuration and event format
  • metadata such as source timestamps and transaction boundaries

debezium runs as a connector on the kafka connect framework in many deployments. that is another layer i am still learning. connector plugins, worker processes, and distributed config all sit between the database and the topic your consumer reads.

heartbeat (where i am stuck)

debezium can emit heartbeat messages on a schedule even when no table rows change. connect and monitoring systems use those signals to prove the pipeline is alive, not silently stalled.

i am working through heartbeat configuration now, and it is a good example of why the high-level map matters. without the map, a heartbeat looks like random traffic on a topic. with the map, it is debezium saying the connector is still running even though the business tables are quiet. testing it is annoying because quiet is the whole point. you are verifying absence of business change while still expecting infrastructure change.

i do not have a clean recipe to publish yet. i am including it here because it is the struggle that prompted this learning note, not because i have mastered it.

kafka

kafka is a distributed log. producers append ordered messages to topics. consumers read from topics, often in groups, and track how far they have read using offsets.

the ideas that took me the longest to internalize are these.

  • durability and replay: messages can be retained for a window of time, so a new consumer or a rebuilt warehouse stage can catch up from history instead of only seeing new traffic.
  • decoupling: the database team does not need to know every downstream reader. debezium publishes once. many subscribers can exist.
  • pace: each consumer reads as fast as it can. lag is a normal operational metric, not necessarily a bug.

kafka is not a database in the relational sense. it is transport and buffering for events. the warehouse still has to turn events into tables that answer questions.

downstream

downstream is everything after the topic. in the stacks i work in, that often means landing raw or semi-structured events in the warehouse, normalizing them into vault-style history, applying business rules, and finally exposing governed tables for applications and bi.

dbt is usually part of this story for me, but it is not the first step. something has to ingest from kafka (or from files produced from kafka) before sql models have anything to join.

this is also where as-of is not the same as current starts to matter in practice. streaming history is a timeline of changes. warehouse models decide what "current" means for a consumer. those are related questions, not the same question.

if bronze-style history is "preserve what arrived," the streaming path is often how it arrived in the first place. bronze, silver, and gold standard data vault 2.0 is the downstream structure i already understand and use. kafka and debezium are the upstream structures that i am still (l)earning.

how the pieces work together

here is the same line again.

  1. a transaction commits in the operational database.
  2. the database records that commit in its internal log.
  3. debezium reads the log, formats a change event, and hands it to kafka connect.
  4. kafka appends the event to the appropriate topic (often one topic per table or per logical source, depending on design).
  5. a warehouse ingest path consumes the topic and persists payloads.
  6. transformation code (sql, dbt, vault macros) turns payloads into historical and business tables.
  7. consumers query the governed tables, not kafka directly.

when i am lost in connector settings, i try to remember which step i am actually touching. heartbeat is step 3 infrastructure liveness. a broken consumer group is step 5. a duplicate row in a satellite is often step 6 grain, not step 4.

that naming exercise is slow, but it beats treating the whole stack as one opaque error message.

closing

this is not a runbook. it is a map i am trying to learn while debezium heartbeat settings still will not sit still in my brain. once i line the pieces up, none of them feel as strange as they did on their own.

if you are stuck the way i was, pick one row you actually care about and follow it until it shows up somewhere you already query. doing that once beat every afternoon i spent skimming documentation without a specific table in mind.

related on this site

references