learn-data-engineering-with-phoebe / Builder session 6 of 10
Learn Data Engineering with Phoebe · Builder track · Session 6 of 10

Streaming and CDC

So far Daybreak's data moved in scheduled chunks. But some data arrives as an endless trickle of events - a click, a login, a row changing in the source database - and waiting for tonight's batch is too slow. This session covers the streaming model, Change Data Capture, and the practical middle ground most teams actually run: the micro-batch. You will simulate a stream on DuckDB, honestly, using batch tools.

🟠 Builder track Practitioners: DE · analysts · DS · PMs Runs in your browser · DuckDB 45 min
0-3 · Recap 3-20 · Streams, CDC, micro-batch, tools 20-42 · Micro-batch a stream 42-45 · Q&A
Part 0

Where the pipeline stands

Daybreak's pipeline can now extract from the source (b2), ingest incrementally (b3), land in good formats (b4), and transform raw into served tables (b5). Every stage so far has been batch: data moves in scheduled chunks. This session adds the other clock. Some data does not wait for a schedule - it arrives continuously, one event at a time. Streaming is how you ingest and process that; Change Data Capture is how a source database's own changes become such a stream.

Live - presented in session Self-study - read after class ▶ Live pipeline - editable & runnable Official sources covered
★ What you walk out with today A clear mental model of streaming (an unbounded event log read by consumers), what CDC captures and why it matters, the micro-batch pattern that most real "streaming" quietly is, a hands-on micro-batch you run against Daybreak's events on DuckDB, and an honest decision test for when you actually need streaming versus a batch you already know how to build.
Part 1 · covers DLAI Source Systems M2 (streaming), Intro to DE M3

The streaming model, and CDC 6 min live

A batch reads a bounded chunk of data on a schedule - "all of yesterday's orders, at 2am." A stream is different: it is an unbounded log of records that arrive continuously, with no end. Consumers read the log at their own pace, tracking an offset - a bookmark for how far they have read. Nothing is "done"; there is always more coming. Change Data Capture turns a source database into exactly this kind of stream.

The event log - records arrive continuously, never "done" e1 e2 e3 e4 e5 e6 e7 ... more arriving → ↑ offset - consumer has read up to here already processed (offset behind this line) not yet read CDC - a source DB's inserts / updates / deletes become the stream source DB log CDC capture event stream
🔍 Click to zoom - the log, the consumer's offset, and how CDC feeds it
LiveBatch vs streaming, and what CDC captures3 min

Batch processes a bounded chunk on a schedule - simple, cheap, and right for most data. Streaming processes records one at a time as they arrive on an unbounded log - lower latency, more moving parts. The consumer tracks an offset so it knows where it left off and can resume after a restart.

  • The log is the core idea: events are appended to an ordered log; many consumers can read the same log independently, each at its own offset. The log does not care who reads it or when.
  • CDC turns a database into a stream: Change Data Capture reads the source database's own transaction log and emits each insert, update, and delete as an event - so downstream systems see changes seconds after they happen, without re-querying the whole table.
  • CDC is how "real-time replication" is really done: instead of re-extracting a table every hour (b3's incremental batch), CDC streams just the changed rows off the DB's log.
Real world

Why CDC beats re-querying. A team refreshed a 200-million-row table every hour by re-selecting the whole thing - slow, heavy, and hammering the production database. Switching to CDC, they streamed only the rows that changed, straight off the database's transaction log. The load on the source dropped to near zero and the downstream copy went from an hour stale to seconds stale. Same goal, a fundamentally lighter mechanism.

Self-studyExactly-once vs at-least-once2 min read

Streaming systems make a delivery promise, and it is worth knowing the two you will hear. At-least-once guarantees no event is lost, but an event may be delivered twice after a failure - so your processing must be idempotent (b5) or you double-count. Exactly-once guarantees each event is processed once and only once - stronger, but costs more coordination and throughput. Most systems default to at-least-once and lean on idempotent transforms to make duplicates harmless. It is the same idempotency discipline from b5, now protecting a stream instead of a batch.

Part 2 · the practical middle ground

Micro-batch: what most "streaming" really is 5 min live

True per-event streaming is powerful but operationally heavy. In practice, most "streaming" pipelines are micro-batches: small, frequent batches - every few seconds or minutes - over a moving time window. You get near-real-time freshness with the simplicity of batch tools you already know. Below, you treat Daybreak's events table as an arriving stream and process one window.

Batch - one big chunk on a schedule (e.g. nightly) a whole day of events, processed once at 2am highest latency Micro-batch - small frequent windows (most "streaming") window window window window minutes latency Streaming - one event at a time, the instant it arrives each event processed on arrival lowest latency, most ops
🔍 Click to zoom - the same events, three grains of freshness and cost
LiveProcess one window of the event stream4 min

Pretend events is a live log. A micro-batch processes just the slice inside the current window - here, the first week of March - and aggregates by event type. In a real streaming job this same query would fire every few minutes over the newest window. Press ▶ Run.

-- one micro-batch window over the "stream" of events
SELECT event_type,
       count(*) AS events_in_window
FROM events
WHERE CAST(event_date AS DATE)
      BETWEEN DATE '2026-03-01' AND DATE '2026-03-07'
GROUP BY event_type
ORDER BY events_in_window DESC;
The window is the whole idea Batch asks "process everything." Streaming and micro-batch ask "process the slice that arrived since my last offset." Change the two dates and you have advanced the offset to the next window - which is exactly what Demo 1 does.
Self-studyExactly-once vs at-least-once, in a micro-batch2 min read

A micro-batch inherits the same delivery question. If a window is retried after a crash, at-least-once means some events in it may be processed twice. The safe pattern: make each window's output idempotent - key the result by (window, event_type) and rebuild it with CREATE OR REPLACE or a merge, so re-processing a window overwrites rather than appends. This is why b5's idempotency lesson matters even more once data is arriving continuously: retries are not rare edge cases in streaming, they are routine.

Part 3 · covers DLAI Source Systems M2 (Kinesis), Storage M3 (◐)

Streaming tools, in concept 4 min live

Real streaming splits into two roles: the log that holds the events, and the processor that reads and transforms them. Kafka and Amazon Kinesis are logs; Flink and Spark Streaming are processors; Debezium is the most common CDC tool feeding database changes into a log. None of these run in a browser - they need running clusters - so the snippets below are read-only, honestly labeled. Orchestrating and operating them is the DataOps course, not this one.

Self-studyThe log and the processor (read-only)3 min read

A Kafka consumer reading events off a topic - the log side. This needs a running Kafka cluster, so read it, do not run it:

Kafka consumer · needs a running cluster, not live here from kafka import KafkaConsumer import json consumer = KafkaConsumer( "daybreak.events", bootstrap_servers="kafka:9092", group_id="events-aggregator", auto_offset_reset="earliest", # start from the beginning of the log value_deserializer=lambda m: json.loads(m), ) for message in consumer: # unbounded - loops forever as events arrive event = message.value handle(event) # your per-event or micro-batch logic

And Kinesis, AWS's managed log, reading one shard's records - same shape, managed service:

Kinesis · needs AWS + a live stream, not here import boto3 kinesis = boto3.client("kinesis") it = kinesis.get_shard_iterator( StreamName="daybreak-events", ShardId="shardId-000000000000", ShardIteratorType="LATEST", )["ShardIterator"] records = kinesis.get_records(ShardIterator=it, Limit=100)["Records"] # each record is one event off the stream; process, then advance the iterator
Where the lines fall Kafka / Kinesis = the log (holds events). Flink / Spark Streaming = the processor (reads + transforms). Debezium = CDC (turns a DB's changes into log events). Scheduling, deploying, and monitoring all of it = the learn-dataops course. This session is the mental model, not the ops.
Demo 1 of 2

Micro-batch a stream, window by window ★ 11 min · everyone builds

Treat Daybreak's events as an arriving event stream. Process one window, then "advance the offset" to the next window in a second query - the exact rhythm a streaming job runs, expressed on batch tools you already know.

Window 1: process the events in the first window (early March) and aggregate by type.

Advance the offset: the second query moves to the next window (mid/late March) - the consumer has moved forward on the log.

Read the rhythm: each window is one micro-batch; a real job just loops this on a timer.

-- WINDOW 1 (offset: 01-07 Mar) - the first micro-batch
CREATE OR REPLACE TABLE window_1 AS
SELECT '2026-03-01..07' AS window, event_type, count(*) AS n
FROM events
WHERE CAST(event_date AS DATE) BETWEEN DATE '2026-03-01' AND DATE '2026-03-07'
GROUP BY event_type;

-- ADVANCE THE OFFSET: WINDOW 2 (08 Mar onward) - the next micro-batch
CREATE OR REPLACE TABLE window_2 AS
SELECT '2026-03-08..31' AS window, event_type, count(*) AS n
FROM events
WHERE CAST(event_date AS DATE) BETWEEN DATE '2026-03-08' AND DATE '2026-03-31'
GROUP BY event_type;

-- what the consumer produced after advancing to window 2
SELECT * FROM window_2 ORDER BY n DESC;
Real world

This is genuinely how micro-batch streaming works. Spark Structured Streaming, under the hood, runs your query over successive micro-batches and tracks the offset for you so no window is missed or repeated. You just built that loop by hand. The production tool automates the timer and the offset bookkeeping; the per-window logic is exactly what you wrote.

Demo 2 of 2

Your turn: re-window and enrich the stream ★ 10 min · build your own

Q1 changes the window size. Q2 joins the stream to a dimension to see who is active. Q3 is the decision test: streaming, micro-batch, or plain batch?

LiveQ1 · Window the events by week instead3 min
SELECT strftime(CAST(event_date AS DATE), '%Y-W%W') AS week,
       count(*) AS events_in_week
FROM events
GROUP BY week
ORDER BY week;
LiveQ2 · Join the stream to customers - who is active?4 min
SELECT c.name, c.plan,
       count(*) AS events_in_window
FROM events e
JOIN customers c ON e.customer_id = c.customer_id
WHERE CAST(e.event_date AS DATE)
      BETWEEN DATE '2026-03-01' AND DATE '2026-03-31'
GROUP BY c.name, c.plan
ORDER BY events_in_window DESC;
Self-studyQ3 · Streaming, micro-batch, or batch?3 min

No SQL - use the one test that cuts through the hype. Ask: does lower latency change a decision or an action? If a fraud check must block a transaction in the next 200 milliseconds, or an alert must fire the instant a sensor spikes, you need true streaming - the latency is the product. If freshness of a few minutes is plenty (a live dashboard, near-real-time metrics), use micro-batch - almost all the benefit, a fraction of the operational cost. If nobody acts on the data until tomorrow anyway (a daily report, a monthly finance close), stay on batch - streaming would be complexity nobody uses. The honest default: batch unless someone can name a decision that a few minutes of delay would ruin, then micro-batch, and reserve true streaming for when milliseconds genuinely matter.

Homework

Try it yourself - this week ◐ 20-30 min total

Source material

Official sources covered

This session teaches the streaming and CDC core of the DeepLearning.AI Data Engineering Professional Certificate (Joe Reis) and Reis & Housley's Fundamentals of Data Engineering, run on a live engine instead of slides. This page covers:

DLAI Source Systems, Ingestion & Pipelines - M2: streaming ingestion, KinesisParts 1-3 · the streaming model, CDC, and the log/processor tools
DLAI Introduction to Data Engineering - M3: streaming architecturePart 1 · batch vs streaming architecture, where each clock fits
DLAI Data Storage & Queries - M3: streaming queriesParts 2-3 · windowed processing on the query side
Check yourself

Three questions before you go 🎯 ◐ 90 seconds

1 · What does Change Data Capture (CDC) capture?

CDC reads the source database's own transaction log and emits each insert, update, and delete as an event - streaming just the changed rows instead of re-querying the whole table. It is how near-real-time replication is done without hammering the source.

2 · What is a micro-batch?

A micro-batch processes small, frequent windows of the stream (every few seconds or minutes) rather than one event at a time. It is what most production "streaming" actually is - most of the freshness, a fraction of the operational cost of true per-event streaming.

3 · When do you actually need true streaming over batch or micro-batch?

The test is whether latency changes a decision. Milliseconds mattering (fraud, live alerts) needs streaming; a few minutes being fine points to micro-batch; nobody acting until tomorrow means plain batch. Default to the simplest clock the decision allows.

Builder session 6 cheat sheet · pin this

StreamUnbounded log of records arriving continuously. Consumers read at their own offset. Never "done."
Batch vs streamingBatch = bounded chunk on a schedule. Streaming = per-event off the log. Two clocks.
OffsetThe consumer's bookmark - how far it has read the log. Lets it resume after a restart.
CDCCaptures inserts/updates/deletes from a source DB's log as a stream. Beats re-querying the whole table.
Micro-batchSmall frequent batches over a moving window. What most real "streaming" is - simple + fresh enough.
DeliveryAt-least-once (may duplicate → need idempotency) vs exactly-once (stronger, costlier).
ToolsLog: Kafka, Kinesis. Processor: Flink, Spark Streaming. CDC: Debezium. None run in a browser.
The decision testDoes lower latency change a decision? Milliseconds → streaming. Minutes fine → micro-batch. Else batch.