Grokking Kafka and Event-Driven Architecture
Vote

0% completed

​

Choosing a Partition Key

What a Key Decides

Estimating a Hot Key's Share

Three Keys, One Run

What Each Key Costs

Using This in an Interview

Key Takeaways

Practice Questions

A marketplace publishes every event of an order, from OrderPlaced through OrderPaid and OrderPacked to OrderShipped, to a topic named marketplace-orders, which has 8 partitions. The events are keyed by seller ID. After 10,000 orders, a count of OrderPlaced events per partition printed this:

key = seller ID partition 0: 825 orders partition 1: 750 orders partition 2: 850 orders partition 3: 850 orders partition 4: 4225 orders partition 5: 700 orders partition 6: 775 orders partition 7: 1025 orders busiest partition: 42.3% of orders (an even spread is 12.5%)

Partition 4 holds more than five times as many orders as partition 5. The cause is a single seller, S-0007, which sells 35 percent of everything on the marketplace. Every one of its orders carries the same key, so every one of them goes to the same partition, and the consumer that reads partition 4 does more work than any other consumer in its group.

This page explains how to choose a key, how to estimate a large key's share of the load before it causes trouble, and what each repair costs.

What a Key Decides

The key was introduced in Designing an Event as the value that keeps related events in order. The producer hashes it to choose a partition, so a key decides two things at once: which events stay in order together, and how the load spreads across partitions.

A hot key is a key that carries a much larger share of a topic's events than the average key, so the partition it hashes to receives more than its share of the load. Kafka does not balance this. The default partitioner chooses "a partition based on a hash of the key," and each partition is read by exactly one consumer in a group, so one busy key means one busy consumer, however many other consumers the group has.

Three services read marketplace-orders:

  • Fulfillment handles each order's four events from this topic in sequence: placed, paid, packed, shipped.
  • Seller dashboards show each seller's sales for the day.
  • Fraud scoring checks each order on its own.

Only fulfillment needs order, and it needs it per order, not per seller. Two orders from S-0007 can be packed in either sequence without harm. The seller ID was chosen because it seemed natural, not because any reader needed per-seller sequence.

Estimating a Hot Key's Share

The busiest partition's share can be estimated before any code runs. If the largest key carries a share s of the events, and the other keys spread evenly over N partitions, the partition holding the large key receives about s + (1 - s) / N of all events.

For the marketplace, s is 0.35 and N is 8, so the busiest partition receives about 0.35 + 0.65 / 8, or 43 percent. The run measured 42.3 percent, because the small sellers did not spread perfectly evenly.

The share becomes a problem when it is compared with what one consumer can handle. Suppose the marketplace peaks at 2,000 orders a second, and one fulfillment consumer handles about 400 orders a second. At peak, partition 4 receives about 845 orders a second, more than twice that capacity. Its backlog grows by about 445 orders a second, or about 1.6 million an hour, while each of the other seven consumers runs at about half its capacity or less.

One seller fills one partition
One seller fills one partition

Adding partitions does not fix a hot key. With 32 partitions the estimate is 0.35 + 0.65 / 32, still about 37 percent, because S-0007 alone is 35 percent of the load and all of it lands on one partition. The fix has to change the key.

The input to this arithmetic is the share of traffic held by the largest keys. It can usually be read from existing data, for example by counting last month's orders per seller in the orders database, before the topic is created.

Three Keys, One Run

The program below sends the same 10,000 orders three times, each time with a different key, and counts how many land in each partition. Seven of every 20 orders belong to S-0007, and the rest come from 260 small sellers. The run sends one OrderPlaced per order; each order's later events carry the same key, so they follow it to the same partition and the counts show how the whole load spreads.

run("key = seller ID", i -> sellerOf(i)); run("key = order ID", i -> "O-" + (500000 + i)); // Only the known large seller is split, into 4 sub-keys; small sellers keep their plain key. run("key = seller ID, large seller split 4 ways", i -> sellerOf(i).equals(BIG_SELLER) ? BIG_SELLER + "#" + (i % 4) : sellerOf(i));

Running it against a single Kafka 4.4 broker printed the following.

Output:

key = seller ID partition 0: 825 orders partition 1: 750 orders partition 2: 850 orders partition 3: 850 orders partition 4: 4225 orders partition 5: 700 orders partition 6: 775 orders partition 7: 1025 orders busiest partition: 42.3% of orders (an even spread is 12.5%) key = order ID partition 0: 1311 orders partition 1: 1281 orders partition 2: 1243 orders partition 3: 1260 orders partition 4: 1242 orders partition 5: 1202 orders partition 6: 1241 orders partition 7: 1220 orders busiest partition: 13.1% of orders (an even spread is 12.5%) key = seller ID, large seller split 4 ways partition 0: 825 orders partition 1: 750 orders partition 2: 1850 orders partition 3: 1850 orders partition 4: 1725 orders partition 5: 1200 orders partition 6: 775 orders partition 7: 1025 orders busiest partition: 18.5% of orders (an even spread is 12.5%)

The order ID spreads the load almost evenly: the busiest partition holds 13.1 percent, close to the ideal 12.5. Splitting S-0007 into four sub-keys spreads its orders over partitions 2, 3, 4, and 5, and the busiest partition falls to 18.5 percent. At 2,000 orders a second, that is about 370 a second. That is under one consumer's 400, but it is about 92 percent of that capacity, which leaves little room to catch up after an outage. A real design would split S-0007 into more sub-keys and check the result the same way. The four sub-keys are also uneven: because the bucket comes from the order number, they received 1,000, 1,000, 1,000, and 500 of S-0007's 3,500 orders.

Three keys, three spreads
Three keys, three spreads

What Each Key Costs

Key by order ID. This gives the most even spread, and every event of one order still shares a partition, so fulfillment keeps its sequence. The cost is that one seller's orders are spread over every partition. A reader that needs a seller's events in sequence, for example to keep a running count of stock, can no longer rely on Kafka for that sequence.

Split the large seller. Only S-0007 gets sub-keys such as S-0007#2, so small sellers keep per-seller order. The costs are real, though. Order holds only within each sub-key, and every producer must apply the same splitting rule. The rule must also send all events of one order to the same sub-key, which is why the sample derives the bucket from the order number rather than choosing it at random.

Send no key. When no reader needs any order, events can be sent without a key. The producer then uses "the sticky partition that changes when at least batch.size bytes are produced to the partition," which fills one batch for one partition before moving to the next. Load spreads over time, but even one order's events can land in different partitions, so fulfillment could not use this topic.

Keep the seller key. It is the right choice when readers truly need per-seller sequence and no seller exceeds what one consumer can handle. The test is the arithmetic above: if the busiest partition at peak stays under one consumer's capacity, with room to catch up, the uneven spread costs nothing that matters.

KeyBusiest partitionOrder kept forMain cost
Seller ID42.3%Each sellerOne consumer gets about 845 orders a second at peak
Order ID13.1%Each orderNo per-seller sequence
Seller ID, S-0007 split 4 ways18.5%Each small seller; each sub-keyEvery producer must apply the same rule

Key by the narrowest thing whose events must stay in order. For the marketplace that is the order, so the order ID is the key. The large seller then stops being a load problem, because its orders are spread like everyone else's.

Using This in an Interview

When you name a key, name the reader that needs its order and the largest key's share: "I would key order events by order ID, because fulfillment needs each order's steps in sequence and nothing needs per-seller order. Our largest seller has 35 percent of orders, which would put about 43 percent of the load on one partition if we keyed by seller."

Two follow-up questions are common:

  • "Would more partitions solve the hot seller?" No. One key always maps to one partition, so that partition keeps at least 35 percent of the load at any partition count.
  • "What if per-seller order were required?" Keep the seller key, but split only the large seller into sub-keys derived from the order number, and accept that its order holds only within each sub-key.

Key Takeaways

  • A key decides two things together: which events stay in order, and how the load spreads over partitions.
  • One key always maps to one partition, so a key with a large share of traffic makes one consumer the busiest in its group.
  • Estimate the busiest partition's share as s + (1 - s) / N, and compare it with one consumer's capacity at peak.
  • Adding partitions does not fix a hot key; only changing the key does.
  • In the run, keying by order ID cut the busiest partition from 42.3 to 13.1 percent, and splitting only the large seller cut it to 18.5 percent.
  • Key by the narrowest thing whose events must stay in order, which is often an entity ID rather than its owner.

A key keeps events in order only while nothing else interferes, and several ordinary changes, such as a new key or a retried send, can interfere. The next lesson, Preserving Order, sets out exactly what Kafka promises about order and what breaks it.

Practice Questions

Try each question first, then open the answer.

1. A topic has 10 partitions, and its largest key carries 20 percent of the events. About what share does the busiest partition receive, and what share would an even spread give?

<details> <summary>Show answer</summary>

About 28 percent, against 10 percent. The estimate is s + (1 - s) / N = 0.20 + 0.80 / 10 = 0.28. An even spread gives each of the 10 partitions 10 percent.

</details>

2. The topic in question 1 peaks at 5,000 events a second, and one consumer handles 1,000 a second. Does the hot partition keep up, and does growing the topic to 40 partitions change the answer?

<details> <summary>Show answer</summary>

No, and no. The busiest partition receives about 0.28 x 5,000 = 1,400 events a second, more than one consumer's 1,000. With 40 partitions it still receives 0.20 + 0.80 / 40 = 22 percent, or 1,100 a second, because the large key alone is 1,000 a second.

</details>

3. A ride-hailing app keys trip events by city. One city produces half of all trips. What is the problem, and what key would you choose if each trip's events must stay in order?

<details> <summary>Show answer</summary>

One partition receives at least half the load. Every trip in the large city carries the same key, so one consumer handles half of all trips. Keying by trip ID keeps each trip's events in sequence and spreads the city's trips over every partition.

</details>

4. A team splits a large customer's events into sub-keys by choosing a random bucket from 0 to 3 for every event. What goes wrong?

<details> <summary>Show answer</summary>

Events of one order can land in different partitions and be read out of order. A random bucket sends an order's created, paid, and shipped events to different sub-keys. The bucket must come from something stable, such as the order number, so every event of one order gets the same sub-key.

</details>

5. A topic keyed by store ID has 6 partitions. The largest store has 9 percent of events, the peak is 1,200 events a second, and one consumer handles 400 a second. Is the store key a problem?

<details> <summary>Show answer</summary>

No. The busiest partition receives about 0.09 + 0.91 / 6, or about 24 percent, which is about 290 events a second at peak. That is under one consumer's 400, with room to catch up, so the store key can stay.

</details>

Reading Progress

0%


Vote for new content

On This Page

What a Key Decides

Estimating a Hot Key's Share

Three Keys, One Run

What Each Key Costs

Using This in an Interview

Key Takeaways

Practice Questions