Apache Kafka · KFK-09
Event & topic design
- 4 h
- requires KFK-08
From your world. fact grain and multi-company marts, decided at the topic layer
Design topics for multi-company commerce
Design the topic and key layout for a multi-company (multi-tenant) commerce platform. Then implement the partitioning function that makes your design hold. Two checks grade you. A rubric checks your design decisions. A property test checks your key and partition function (per-entity ordering, tenant isolation, no hot partition under skew).
An event is a dict:
{"company_id": "C001", "order_id": "O-123", "event_type": "created", "ts": 170...}
Companies are skewed: a few huge tenants, many tiny ones.
Your task — implement solution.py
1. message_key(event) -> str
Return the Kafka message key for an order event. The key must make all events for
the same order go to one partition. Then the per-partition ordering of Kafka
keeps created before updated. The key must not send a whole big tenant to
one partition.
2. partition_for(event, num_partitions) -> int
Return the partition index in range(num_partitions) for the event. It must be a
pure, deterministic function of message_key(event) and num_partitions. The
same inputs give the same partition, across processes. Use a stable hash
(hashlib). Do not use hash() of Python, because Python salts it for each
process.
3. design() -> dict
Return your design decisions as a dict with exactly these keys:
{
"orders": {
"topic_type": "event" | "entity",
"retention": "time" | "compacted",
"key": "order_id" | "company_id" | "customer_id" | "random",
"factors": [ ... ], # from the vocabulary below
},
"customers": {
"topic_type": ...,
"retention": ...,
"key": ...,
"factors": [ ... ],
},
}
Controlled vocabulary for factors:
per_entity_ordering, tenant_isolation, avoid_hot_partition,
high_cardinality_key, latest_state_per_key, rebuildable_from_log,
append_only_history, time_retention, log_compaction.
The defensible design:
- orders = a time-retained event topic (append-only history of order
facts), keyed by
order_id. Required factors:per_entity_ordering,avoid_hot_partition,high_cardinality_key. Also add at least one ofappend_only_history/time_retention. - customers = a compacted entity topic (latest state per customer),
keyed by
customer_id. Required factors:latest_state_per_key,log_compaction. Also add at least one ofrebuildable_from_log/tenant_isolation.
Grading
- The rubric checks the
design()choices and the required factor keys. - Property tests (Hypothesis) check your
message_keyandpartition_for:- Per-entity ordering — all events for one
order_idmap to one partition. - Determinism — the same event gives the same partition, recomputed in a fresh process.
- No hot partition under skew — for a heavily skewed tenant with many orders, the events spread across (nearly) all partitions, not just one.
- Tenant isolation — the key is derived from the entity. The tenant alone does not force the distinct orders of two tenants to collide on one partition.
- Per-entity ordering — all events for one
Pure Python, no Docker.
Starter code
"""Starter — not implemented yet (must FAIL the tests: gate G1)."""
def message_key(event):
# TODO: return a key that co-locates all events of ONE order while spreading
# a skewed tenant's orders across partitions.
return event["company_id"]
def partition_for(event, num_partitions):
# TODO: a stable, deterministic hash of message_key(event) % num_partitions.
return 0
def design():
# TODO: fill in the orders/customers design per the README rubric.
return {}
Hints
Hint 1
Key by the high-cardinality entity id (order_id) so all events for one order share a partition — not by company_id, which hot-spots skewed tenants.
Hint 2
partition_for must be a pure, deterministic function of message_key(event) and num_partitions, e.g. a stable hash modulo num_partitions. Use hashlib (not Python's salted hash()).
Hint 3
Fill design() per the README rubric: orders = time-retained event topic keyed by order_id; customers = compacted entity topic keyed by customer_id; carry company_id for tenant filtering.
uv run de start KFK-09/01-topic-design
# edit workspace/KFK-09/01-topic-design/
uv run de test