Streaming Pipeline Topologies
Purpose
Give a pipeline a vocabulary of stage shapes, and decide for each whether it may run at
concurrency above 1 — the single question where correctness is silently traded for throughput.
The shapes are small: copier (fan-out to independent consumers), filter (drop by
predicate), splitter (one input, many outputs), sharder (re-partition by a new key),
merger/join (combine streams; a union can interleave without keyed join state).
Semantic parallelism is safe when operations commute/order does not matter, or keyed state and
effects have one current owner with recovery/fencing. Stateless code can still emit ordered or
non-idempotent effects; stateful frameworks can safely parallelize by key. Repartitioning is a
shuffle boundary: old-key order no longer defines order among records sharing a new key, state
must migrate/rebuild and skew changes. It does not inherently end exactly-once—some engines
include repartition topics/state in one transaction or checkpoint. The two failures prevented are the stage
parallelised because it "looked stateless", and the join that retains every key it has ever
seen — which passes every load test and dies in week three of memory, not of throughput.
Workflow
Inspect deployed engine/API, connector and Java versions, topology configuration and state
backend before using version-sensitive guarantees; no upgrade is implied. Missing watermark,
checkpoint or sink evidence is unknown. Deliver a stage map with ordering/authority boundaries,
state/backlog budgets and the tested recovery contract. Replay, resets and failure injection
must use isolated targets or existing explicit authorization for their effects.
- Name each stage by shape before drawing arrows. If an operator combines shapes, model
each semantic step even when the implementation fuses them; this exposes separate ordering,
state and failure boundaries without forcing an unnecessary network hop.
- For each stage, answer four questions: what ordering does it preserve, is it safe above
concurrency 1, what state does it hold, and how does it fail. The table is
references/stage-catalogue.md.
- Mark every shuffle/repartition explicitly. State old/new key, partitioner/count/epoch,
ordering semantics, framework transaction/checkpoint boundary and recovery. Never inherit an
exactly-once label across a sink the engine does not control.
- For any stateful stage, bound the state. Specify key count, bytes/events per key,
multiplicity, and the clock/progress that drives cleanup. A window or TTL alone is not a
physical bound when progress stalls. See
references/stateful-stages.md.
- Write the late-data policy down — drop, side stream, or correction. Not deciding is
accepting an unverified framework default; inspect and instrument it.
- Trace flow control and backlog separately. Operator queues/credits can backpressure
upstream within a job; a durable log usually decouples producers, so consumer lag measures
backlog without slowing production. Bound both internal buffers and log retention/replay.
- Specify replay semantics: use event time when historical event-time answers are required,
pin timestamp/watermark/late-data rules, and test with controlled time rather than sleeping.
Decision block
Run a stage above concurrency 1 when:
- records/effects commute or sequence/version checks tolerate completion reordering, or
- state is keyed by the partition key, one current owner is enforced, and checkpoint,
rebalance and stale-owner behavior are defined
Keep a stage at one worker per partition when:
- downstream state is order-sensitive per key: a state machine, a CDC apply, an
event-sourced projection. Unordered execution/emission can reorder it; ordered per-key lanes
or validated ordered-async operators may preserve the required contract
Do not treat parallelism as a knob when:
- the stage changes the partitioning (sharder) or combines partitions (merger, join).
Evaluate key ownership, migration and ordering; changing parallelism need not change the key
Push the stage upstream instead when:
- it is a filter with high selectivity and the source can evaluate the predicate
Split into separate pipelines instead when:
- two branches need different parallelism, ordering or retention. One topology forced to
satisfy both is sized for the stricter and pays for it twice
Rules
- Statelessness alone does not make effects order-insensitive. Parallelize freely only when
output/effect composition tolerates completion order and duplicates; otherwise preserve a
serial lane or version/sequence guard. Stateful keyed ownership also needs checkpoint,
rebalance and stale-task fencing semantics.
- Filter cost and removable upstream work depend on payloads, batching and predicate cost.
Push a pure predicate earlier only if null/type/time semantics and required audit/security
observations remain equivalent; a 99% record drop does not imply 99% byte or CPU savings.
- A splitter raises one question and it is transactional: are the N outputs atomic? If not,
a crash after output 1 leaves consumers of output 2 with a gap they must tolerate. What a
transaction covers, and what it does not, is
delivery-semantics.
- A sharder/shuffle changes the key and forces three reviews:
per-key ordering (records sharing a new key may arrive from inputs with no relative order),
the guarantee/checkpoint scope (which may or may not include the shuffle), and skew profile (a new
key is a new distribution —
hot-partitions-and-rebalancing).
- A stream-stream join without eviction can retain unmatched records indefinitely. Table/latest-
value joins may retain current state per live key and tombstones may remove it; fixed-size
aggregates need less per-key bytes than raw-event joins. Bound by semantic retention and
measure distinct keys, unmatched events, bytes and compaction/checkpoint amplification.
- A copier—a second consumer group—decouples offsets/failure but adds broker read/network/
cache and downstream cost. Kafka groups have independent offsets, but share topic retention
and compaction; another group does not preserve expired input or create independent retention.
- Say which window and implementation you mean. Naive sliding windows replicate each record
across
size/step windows; pane/incremental aggregation can reduce storage/CPU depending on
whether the function is algebraically mergeable. Continuous sessions may never finalize,
but state growth depends on accumulator versus raw-event/join storage.
- A watermark is an engine/source assertion about event-time progress, commonly the minimum
across active partitions plus out-of-orderness/idleness policy—not a guarantee. It encodes how
long to wait for stragglers; the late-data policy is a
separate decision about the one that arrives anyway. Name both — "it probably won't happen" is
insufficient evidence for a loss policy. Replay behavior depends on how progress is rebuilt.
- In a log-based boundary, lag is durable backlog, not backpressure to producers. A slow
consumer reads later while producers may continue. Retention can make old input unavailable;
internal queues/state can still OOM before that. Alert on age/bytes/catch-up capacity against
SLO and effective retention. In-process demand signalling—
request(n), credits, bounded buffers
strategies — is a different mechanism inside one JVM (reactive-backpressure).
- Processing-time windows generally produce different buckets on replay; use them only when
current processing behavior is the intended semantics. Event time improves reproducibility
only with stable timestamp extraction, watermark/idleness rules, late policy, input snapshot
and deterministic operators/sinks.
- Replay is not merely "start at offset 0": a full recomputation needs isolated/reset state,
while checkpoint recovery restores state and source positions consistently. Choose versioned
output/cutover or a sink protocol that tolerates replay (
idempotency) before running it.
- Never size a state store from the average key: size it from distinct keys × per-key state ×
window multiplicity, and export the real number as a metric. A store whose size is visible
only in a heap dump has already taken the outage.
Exactly-once scope
For each engine, enumerate source offsets, shuffle topics, state changelog/checkpoint and sinks
inside one atomic recovery boundary. Kafka Streams exactly_once_v2 can transactionally couple
Kafka input/output/state changelog, but an external database call is outside. Flink checkpoints
need a replayable source and checkpoint-aware/idempotent/transactional sink; checkpoint success
does not make an arbitrary side effect exactly once. Upgrades, rescaling and savepoint/state-
serializer compatibility are part of the contract.
Security and operability
- Authenticate/authorize internal topics/state stores and protect replay tools; topology
duplication can bypass the API's tenant controls.
- Minimize PII in repartition keys/changelogs and apply retention/deletion to derived copies.
- Expose topology version, partition/key distribution, watermark per input, idle partitions,
late/drop/correction count, state bytes/entries, checkpoint duration/failure and restore time.
References
- The stage catalogue — every shape with its ordering effect,
parallel-safety condition, state requirement and characteristic failure, plus the composition
rules and the shapes that are two stages pretending to be one. Read when designing a topology
or reviewing whether a stage may be parallelised.
- Stateful stages — window types with their state cost,
watermarks and late-data policy options, the unbounded-state failure with the metrics that
catch it before OOM, state store sizing, and how to test a windowed join deterministically on
controlled event time. Read before building a join, or when state is growing.
1---2name: streaming-pipeline-topologies3description: Composable stage shapes for event-driven pipelines — copier, filter, splitter, sharder, merger — with ordering, semantic parallelism, state, shuffle and recovery boundaries; exactly-once scope across source, state and sinks; bounded joins and windows; watermarks, late-data policy, backlog versus flow control, and reproducible replay. Use when a stage is parallelised, when a join grows state without bound, when a stage re-keys the stream, when late events arrive after a window closed, when a windowed test uses wall-clock, or when reprocessing gives a different answer. Not whether to be event-driven (event-driven-architecture), ordering scope (message-ordering-and-partitioning), barriers (distributed-aggregation-and-barriers), skew (hot-partitions-and-rebalancing), the consumer (kafka-consumers-in-java), or in-process demand (reactive-backpressure).4---56# Streaming Pipeline Topologies78## Purpose910Give a pipeline a vocabulary of stage shapes, and decide for each whether it may run at11concurrency above 1 — the single question where correctness is silently traded for throughput.12The shapes are small: **copier** (fan-out to independent consumers), **filter** (drop by13predicate), **splitter** (one input, many outputs), **sharder** (re-partition by a new key),14**merger/join** (combine streams; a union can interleave without keyed join state).1516Semantic parallelism is safe when operations commute/order does not matter, or keyed state and17effects have one current owner with recovery/fencing. Stateless code can still emit ordered or18non-idempotent effects; stateful frameworks can safely parallelize by key. Repartitioning is a19shuffle boundary: old-key order no longer defines order among records sharing a new key, state20must migrate/rebuild and skew changes. It does **not** inherently end exactly-once—some engines21include repartition topics/state in one transaction or checkpoint. The two failures prevented are the stage22parallelised because it "looked stateless", and the join that retains every key it has ever23seen — which passes every load test and dies in week three of memory, not of throughput.2425## Workflow2627Inspect deployed engine/API, connector and Java versions, topology configuration and state28backend before using version-sensitive guarantees; no upgrade is implied. Missing watermark,29checkpoint or sink evidence is unknown. Deliver a stage map with ordering/authority boundaries,30state/backlog budgets and the tested recovery contract. Replay, resets and failure injection31must use isolated targets or existing explicit authorization for their effects.32331. **Name each stage by shape** before drawing arrows. If an operator combines shapes, model34 each semantic step even when the implementation fuses them; this exposes separate ordering,35 state and failure boundaries without forcing an unnecessary network hop.362. **For each stage, answer four questions:** what ordering does it preserve, is it safe above37 concurrency 1, what state does it hold, and how does it fail. The table is38 `references/stage-catalogue.md`.393. **Mark every shuffle/repartition explicitly.** State old/new key, partitioner/count/epoch,40 ordering semantics, framework transaction/checkpoint boundary and recovery. Never inherit an41 exactly-once label across a sink the engine does not control.424. **For any stateful stage, bound the state.** Specify key count, bytes/events per key,43 multiplicity, and the clock/progress that drives cleanup. A window or TTL alone is not a44 physical bound when progress stalls. See `references/stateful-stages.md`.455. **Write the late-data policy down** — drop, side stream, or correction. Not deciding is46 accepting an unverified framework default; inspect and instrument it.476. **Trace flow control and backlog separately.** Operator queues/credits can backpressure48 upstream within a job; a durable log usually decouples producers, so consumer lag measures49 backlog without slowing production. Bound both internal buffers and log retention/replay.507. **Specify replay semantics**: use event time when historical event-time answers are required,51 pin timestamp/watermark/late-data rules, and test with controlled time rather than sleeping.5253## Decision block5455```text56Run a stage above concurrency 1 when:57- records/effects commute or sequence/version checks tolerate completion reordering, or58- state is keyed by the partition key, one current owner is enforced, and checkpoint,59 rebalance and stale-owner behavior are defined6061Keep a stage at one worker per partition when:62- downstream state is order-sensitive per key: a state machine, a CDC apply, an63 event-sourced projection. Unordered execution/emission can reorder it; ordered per-key lanes64 or validated ordered-async operators may preserve the required contract6566Do not treat parallelism as a knob when:67- the stage changes the partitioning (sharder) or combines partitions (merger, join).68 Evaluate key ownership, migration and ordering; changing parallelism need not change the key6970Push the stage upstream instead when:71- it is a filter with high selectivity and the source can evaluate the predicate7273Split into separate pipelines instead when:74- two branches need different parallelism, ordering or retention. One topology forced to75 satisfy both is sized for the stricter and pays for it twice76```7778## Rules7980- Statelessness alone does not make effects order-insensitive. Parallelize freely only when81 output/effect composition tolerates completion order and duplicates; otherwise preserve a82 serial lane or version/sequence guard. Stateful keyed ownership also needs checkpoint,83 rebalance and stale-task fencing semantics.84- Filter cost and removable upstream work depend on payloads, batching and predicate cost.85 Push a pure predicate earlier only if null/type/time semantics and required audit/security86 observations remain equivalent; a 99% record drop does not imply 99% byte or CPU savings.87- A **splitter** raises one question and it is transactional: are the N outputs atomic? If not,88 a crash after output 1 leaves consumers of output 2 with a gap they must tolerate. What a89 transaction covers, and what it does not, is `delivery-semantics`.90- A **sharder/shuffle** changes the key and forces three reviews:91 per-key ordering (records sharing a new key may arrive from inputs with no relative order),92 the guarantee/checkpoint scope (which may or may not include the shuffle), and skew profile (a new93 key is a new distribution — `hot-partitions-and-rebalancing`).94- A stream-stream join without eviction can retain unmatched records indefinitely. Table/latest-95 value joins may retain current state per live key and tombstones may remove it; fixed-size96 aggregates need less per-key bytes than raw-event joins. Bound by semantic retention and97 measure distinct keys, unmatched events, bytes and compaction/checkpoint amplification.98- A **copier**—a second consumer group—decouples offsets/failure but adds broker read/network/99 cache and downstream cost. Kafka groups have independent offsets, but share topic retention100 and compaction; another group does not preserve expired input or create independent retention.101- **Say which window and implementation you mean.** Naive sliding windows replicate each record102 across `size/step` windows; pane/incremental aggregation can reduce storage/CPU depending on103 whether the function is algebraically mergeable. Continuous sessions may never finalize,104 but state growth depends on accumulator versus raw-event/join storage.105- A watermark is an engine/source assertion about event-time progress, commonly the minimum106 across active partitions plus out-of-orderness/idleness policy—not a guarantee. It encodes how107 long to wait for stragglers; the late-data policy is a108 separate decision about the one that arrives anyway. Name both — "it probably won't happen" is109 insufficient evidence for a loss policy. Replay behavior depends on how progress is rebuilt.110- **In a log-based boundary, lag is durable backlog, not backpressure to producers.** A slow111 consumer reads later while producers may continue. Retention can make old input unavailable;112 internal queues/state can still OOM before that. Alert on age/bytes/catch-up capacity against113 SLO and effective retention. In-process demand signalling—`request(n)`, credits, bounded buffers114 strategies — is a different mechanism inside one JVM (`reactive-backpressure`).115- Processing-time windows generally produce different buckets on replay; use them only when116 current processing behavior is the intended semantics. Event time improves reproducibility117 only with stable timestamp extraction, watermark/idleness rules, late policy, input snapshot118 and deterministic operators/sinks.119- Replay is not merely "start at offset 0": a full recomputation needs isolated/reset state,120 while checkpoint recovery restores state and source positions consistently. Choose versioned121 output/cutover or a sink protocol that tolerates replay (`idempotency`) before running it.122- Never size a state store from the average key: size it from distinct keys × per-key state ×123 window multiplicity, and export the real number as a metric. A store whose size is visible124 only in a heap dump has already taken the outage.125126## Exactly-once scope127128For each engine, enumerate source offsets, shuffle topics, state changelog/checkpoint and sinks129inside one atomic recovery boundary. Kafka Streams `exactly_once_v2` can transactionally couple130Kafka input/output/state changelog, but an external database call is outside. Flink checkpoints131need a replayable source and checkpoint-aware/idempotent/transactional sink; checkpoint success132does not make an arbitrary side effect exactly once. Upgrades, rescaling and savepoint/state-133serializer compatibility are part of the contract.134135## Security and operability136137- Authenticate/authorize internal topics/state stores and protect replay tools; topology138 duplication can bypass the API's tenant controls.139- Minimize PII in repartition keys/changelogs and apply retention/deletion to derived copies.140- Expose topology version, partition/key distribution, watermark per input, idle partitions,141 late/drop/correction count, state bytes/entries, checkpoint duration/failure and restore time.142143## References144145- [The stage catalogue](references/stage-catalogue.md) — every shape with its ordering effect,146 parallel-safety condition, state requirement and characteristic failure, plus the composition147 rules and the shapes that are two stages pretending to be one. Read when designing a topology148 or reviewing whether a stage may be parallelised.149- [Stateful stages](references/stateful-stages.md) — window types with their state cost,150 watermarks and late-data policy options, the unbounded-state failure with the metrics that151 catch it before OOM, state store sizing, and how to test a windowed join deterministically on152 controlled event time. Read before building a join, or when state is growing.