Partitioning assigns work; state gives that work a history
Distinguish source partitions, keyed state, operator state, and recoverable positions before reasoning about parallel stream execution.
On this page
The question for today
What you’ll understand
- Separate partition-local order from a global stream order.
- Explain keyed state and operator state with distinct ownership rules.
- Calculate a simple state payload budget without confusing it with checkpoint durability.
A streaming operator does more than transform the current record when its output depends on earlier records. Counts, joins, deduplication sets, and unfinished windows all require remembered state. Parallel execution must assign both records and the history they need to compatible owners. Begin with explicit identities for source partitions, keys, and operator instances; otherwise scaling a job can silently change the meaning of the computation.
A partition is an ordering boundary, not the whole application
A partitioned source divides a log into independently progressing sequences. Kafka preserves its defined ordering within a partition, not a universal order across every partition in a topic. An offset identifies a position within its partition; offset 100 in one partition is not necessarily earlier than offset 90 in another. A source reader's recoverable position therefore needs a vector of partition identities and positions. Record identity is a separate application choice, especially when producers can submit duplicate business events at different log offsets.
Downstream repartitioning can route the same business key from several source partitions to one keyed operator. This makes per-key history available at the responsible instance, but it does not invent a meaningful global order among unrelated events. If order matters within a key, define which upstream guarantees or sequence fields establish it. A timestamp alone can tie or arrive late. More parallel readers can increase available work while a hot key still concentrates state and processing on one owner. Diagnose skew before assuming an equal partition count means balanced CPU or memory usage.
Name the scope of remembered information
In Flink 2.1's state model, keyed state is associated with a key after keyed partitioning, so an update can refer to the current key's history. Operator state belongs to a parallel operator instance and uses declared redistribution behavior when parallelism changes. A source's assigned partition positions are a useful operator-state example; a user's running sum is a useful keyed-state example. Arbitrary mutable fields in application code do not automatically acquire the recovery and redistribution guarantees of managed state. Use the documented state interface and preserve its identity through upgrades.
State size depends on distinct active keys, retained history, serializer representation, indexes, and overhead. A bounded input batch may eventually end, while an unbounded stream needs an explicit reason old state can be removed. A count per permanent customer grows with customer cardinality; a raw event buffer grows with retained events. An incremental aggregate can store less than a full history only when its algebra and later corrections permit it. A smaller state representation must preserve the required answer, not merely make a checkpoint or dashboard look lighter.
Recovery needs state and positions from one consistent boundary
Restoring an old aggregate while restarting sources after newer offsets loses contributions; restoring a newer aggregate while replaying earlier records can count contributions twice. A coordinated checkpoint connects source positions with operator state and, where required, channel state at a consistent cut. That guarantee concerns recovery of the managed computation. Outputs to an external service need their own compatible commit or replay contract. Keep logical state ownership, live storage, durable snapshots, and external visibility as separate parts of the system diagram.
The modular lab illustrates uneven coverage in a deliberately fictional routing rule. Reset, explicitly set BOTH modulus m=8 and additive step a=2, predict that only four residues are visited, then Play or Step. Reset and re-set BOTH m=8 and a=3; predict all eight residues before repetition. Playback selects n=floor(2t), not real partition arrivals. Edits retain t and recompute the orbit. Flink does not assign keys with this additive toy; use it only to show why a routing rule's coverage must be checked rather than inferred from the number of available buckets.
Work it through
Separate keyed payload from instance-local payload
A fictional job retains 100,000 keyed counters of 24 payload bytes each and four operator instances with 50,000 payload bytes of operator state each. Ignore every storage overhead.
Keyed payload is 100,000×24=2,400,000 bytes. Its ownership follows keys rather than simply one equal-sized allocation per instance.
Operator-state payload is 4×50,000=200,000 bytes. Add the two categories for 2,600,000 bytes of logical payload.
Changing to eight instances does not automatically double keyed cardinality. It can change instance-local state and overhead; redistribution policy must determine the new operator-state contents rather than blindly copying every previous allocation.
The initial logical payload is 2.6 decimal MB. This is neither a guaranteed resident-memory measurement nor a durable checkpoint-size estimate.
The living notebook
Explore the model
Interactive lab · modular
Available buckets do not guarantee coverage
For EACH run Reset, set BOTH m and a, predict, then Play or Step. Compare (8,2), period four, with (8,3), period eight. The orbit is na mod m with n=floor(2t); edits retain t. This additive coverage illustration is not a Flink key hash, partition scheduler, or state redistribution algorithm.
- Residue r0
- 0
- Orbit period · m/gcd(m,a)
- 12
- Distinct residues visited
- 1 of 12
Addition modulo m starts at zero: rₙ = na mod m. Playback advances two additions per second. The orbit has period m/gcd(m,a), including period one for a = 0. This is not a cryptographic security test or a primality algorithm. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.
Look forCheck a routing rule's actual coverage and skew before equating bucket count with balanced parallel work.
Pause & reason
Check your understanding
Your turn
Try it yourself
Three fictional source partitions use dense consecutive offsets and resume from next-record positions (10,20,15). One record from each is then processed into a new consistent snapshot. What is the new position vector, and does it imply a global order of those three events?
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Advance each local next-record position once; compare positions only within the same partition.
Compare with the solution
The vector becomes (11,21,16) under the stated next-record convention. It records one additional consumed event in each partition, not which of the three happened first globally. The corresponding operator state must include those same contributions at a compatible snapshot boundary.
Keep the idea
Take it with you
- Partition positions and business keys describe different ownership and ordering scopes.
- Managed keyed and operator state require explicit recovery and redistribution semantics.
- A consistent recovery boundary coordinates history with replay positions.
Read further
Original sources and deeper explanations to follow at your own pace.
Optional progress, saved in this browser when available. Revisit any lesson at any time.
Lesson not marked complete.