⚡ Streaming & Kafka · Chapter 4
Choosing a Partition Key
The partition key decides two things at once: what stays ordered, and what gets overloaded.
Study this lesson free in the app →
The basics
A partition is one ordered slice of a Kafka topic, and the partition key is the field (like ride_id) whose hash decides which slice each event goes to.
The problem it solves: one machine can't handle every ride event in India at peak, so a topic is split into many partitions spread across brokers and read in parallel. But splitting has a price: Kafka only keeps events in order within one partition. The key is how you choose which events must stay together — and that same choice decides whether load spreads evenly or piles onto one machine.
The mental model: billing counters at a stadium. Send people to counters by ticket number and every counter is busy, but a family gets split up. Send them by surname initial and the "S" counter has a 40-minute queue while "Q" is empty. Pick the key that keeps together what must stay in order, and has enough distinct values to spread the crowd.
Words you must know 5
- Partition key
- the field hashed to choose a partition:
hash(key) % partitions. - Ordering guarantee
- same key → same partition → events stay in order.
- Cardinality
- how many distinct key values exist; 5 keys can't fill 50 partitions.
- Hotspot / skew
- one key (or a few) carrying far more traffic than the rest.
- Salting
- splitting a hot key into sub-keys to spread it, at the cost of its ordering.
Explained
Pick ride_id and every event of one ride stays in order, spread evenly across the cluster.
Pick city and Bangalore melts one broker while Shillong idles.
Pick event_timestamp and everything arriving this second lands on the same partition — you have built a queue with extra steps.
Billing counters at a stadium
Twenty counters, one crowd.
Key by surname initial — the S counter has a 40-minute queue, the Q counter reads a newspaper. That is skew.
Key by ticket number — even spread, every counter busy. But a family arriving together gets split across counters, so nothing keeps them in sequence.
Key by arrival minute — everyone in the same minute goes to one counter. Perfectly ordered, perfectly useless.
The trade is always the same: ordering pulls related events together, throughput pushes them apart.
How the key becomes a partition
partition = hash(key) % partition_count
Consequences that follow directly from that formula:
- Same key → same partition → ordered relative to each other
- No key → round-robin → maximum spread, zero ordering
- Change the partition count → the mapping changes → old and new events for a key can sit in different partitions, so ordering breaks during the transition
- Key cardinality caps your spread. 5 distinct keys cannot fill 50 partitions
So: choose the key by asking "what must stay in order?" then verify "is it high-cardinality and evenly distributed?"
Good vs bad keys for RideFlow
stream key why
────────────────────────────────────────────────────────────
ride_events ride_id all events of one ride ordered;
millions of ids = even spread
driver_location driver_id per-driver path stays sequential;
high cardinality
payments ride_id charge/refund order preserved
✗ city 10 keys, Bangalore = hotspot
✗ event_timestamp all of 'now' → one partition
✗ country 1 key = 1 partition = no scaleWhen the natural key is skewed anyway
Sometimes reality is skewed — one merchant is 30% of transactions, one city is half the rides. Standard mitigations:
- Salting — key becomes
merchant_id:bucketwhere bucket is0..N. Spreads the hot key across N partitions, at the cost of ordering within that merchant (you now need a merge/sort downstream) - Two-tier routing — hot keys get a dedicated topic with more partitions; everything else shares the default
- Reduce the event, not the key — aggregate location pings client-side to 1/second instead of 1/200ms
- Re-key at the boundary — ingest by
ride_id, then re-partition bycityonly in the analytical layer, where skew costs a slow task rather than a dropped ping
Say salting in an interview and follow it immediately with "which breaks per-key ordering, so I'd only do it where ordering isn't required". The caveat is what makes it a senior answer.
Watch keys land in partitions
Same key, same partition — every time. That is the whole ordering guarantee: rider_7's events can never be split across partitions, so they stay in order. (Kafka uses murmur2, not a sum of characters, but the shape is the same: hash, then modulo the partition count.)
Now add partitions — and watch keys move
Same keys, 6 partitions instead of 4: most keys land somewhere new. A consumer that relied on per-key order across the change can now see events out of order. Decide the partition count up front.
Ordering pulls together. Throughput pushes apart. The key is where you settle the fight.
High cardinality, evenly spread, and matching the thing that must stay in order.
Words to know
| Partition key | The field hashed to decide which partition an event lands in. |
|---|---|
| Hotspot | One partition receiving disproportionate traffic, limiting the whole system. |
| Data skew | Uneven distribution of records across partitions or tasks. |
| Cardinality | The number of distinct values a field can take. |
| Salting | Appending a bucket suffix to a hot key to spread it across partitions. |
| Re-keying | Re-partitioning a stream by a different field, usually via a shuffle. |
In two minutes
- partition = hash(key) % partition_count: same key, same partition, kept in order.
- Choose the key from the ordering requirement first (ride_id for ride status changes), then check its distribution.
- Good keys are high-cardinality and even; city, status, country and timestamps make hotspots.
- Changing the partition count remaps keys, so ordering can break across the transition — size partitions up front.
- Consumer rebalancing spreads partitions, not load within a partition; skew stays skew.
- For a genuinely hot key: salt it, give it its own topic, shrink the events, or re-key downstream — and say what ordering you lose.
- The same trade-off rules Spark shuffles, warehouse clustering and DynamoDB keys.
Test yourself
1. Why is event_timestamp a poor partition key?
- Timestamps cannot be hashed
- All events from the same instant collide on one partition
- It breaks retention
- Consumers cannot read it
Show the answer
All events from the same instant collide on one partition — It creates a moving hotspot: whichever partition owns 'now' takes the full write load while others idle.
2. You need every status change of one ride processed in order. Key by…
- city
- ride_id
- driver_id
- no key (round robin)
Show the answer
ride_id — Same key → same partition → guaranteed relative order, and ride_id is high-cardinality so the spread stays even.
3. One merchant is 30% of your payment volume. Best first mitigation?
- Add more consumers
- Salt that key into sub-buckets
- Increase retention
- Switch to round-robin for everything
Show the answer
Salt that key into sub-buckets — More consumers cannot help — a partition is read by one member. Salting spreads the hot key, at the cost of per-merchant ordering.
4. You increase partitions from 6 to 12. What breaks?
- Retention resets
- hash(key) % n changes, so a key's old and new events may sit in different partitions
- Consumers lose their group
- Nothing at all
Show the answer
hash(key) % n changes, so a key's old and new events may sit in different partitions — The modulo changes the mapping. During and after the change, per-key ordering across the boundary is not guaranteed — plan it like a migration.
5. What happens to events produced with no key (null key)?
- They're spread across partitions (in sticky batches), with no ordering between them
- They all go to partition 0
- The producer throws an error
- They're stored but never delivered
Show the answer
They're spread across partitions (in sticky batches), with no ordering between them — With no key there's nothing to hash, so the producer spreads events for throughput (modern clients fill a batch for one partition, then switch). Maximum spread, zero ordering — fine for independent logs, wrong for state changes.
6. A driver app sends a GPS ping every 2 seconds and the ETA service must process each driver's pings in order. Key by…
- city
- event_timestamp
- ping_id (unique per ping)
- driver_id
Show the answer
driver_id — Order matters per driver, and there are lakhs of drivers, so driver_id is both correct and evenly spread. ping_id spreads perfectly but scatters one driver's pings; city and timestamp create hotspots.
There are 8 questions, 3 puzzles and 5 recall cards for this lesson in the app — the recall cards come back on later days, just before you would forget.
Start this lesson →