Why Is One Storage Key Doing All the Work?
The maintenance service has plenty of records but most requests land on one tenant. Choose a key from the work the service actually performs, then inspect the traffic it concentrates.
13 sections · 4 questions · 1 coding challenge
The arrow keys move between sections too.
Distributing Work Without Losing the Lookup Address
BOTIE
The useful intuition is an address: a request carries a key that tells the system where to look. Requests with the same address still converge on the same logical item or grouping. A large number of possible keys does not help if almost every request uses one of them.
Sources for this history
The Other Servers Are Quiet While North’s Requests Wait
Botie groups every maintenance record under its tenant. That makes a tenant’s records easy to locate, but north is a much busier customer than the others. A key can be convenient to read and still gather more work than one part of the system can handle.
Before adding machines, let’s find out what is being grouped together. We will compare logical keys using a measured request trace, then ask what a different grouping makes harder to read.
Invented maintenance records. These deterministic local models expose a storage decision; they do not run a distributed database or establish its guarantees.
Step 1 of 1
A tenant key and an asset key gather different requests
The limit in this invented trace is seven work units per logical key. It is not a vendor capacity limit.
| Request group | Work units | Tenant | Asset |
|---|---|---|---|
| First group | 6 | north | P7 |
| Second group | 4 | north | P8 |
First group
- Work units
- 6
- Tenant
- north
- Asset
- P7
Second group
- Work units
- 4
- Tenant
- north
- Asset
- P8
A useful address also determines which work stays together
The key fields determine which requests share an accumulated workload.
Inspect load under a chosen grouping
Connect the request trace and key fields before comparing the accumulated traffic with the teaching capacity.
BOTIE
Load by logical key
[
{
"key": [
"north"
],
"load": 10,
"overloaded": true
}
]Follow the operations
1. Request trace
[ { "tenant": "north", "asset": "P7", "load": 6 }, { "tenant": "north", "asset": "P8", "load": 4 } ]2. Chosen key fields
- 0tenant
3. Group traffic by the chosen key
[ { "key": [ "north" ], "load": 10 } ]4. Teaching capacity
7
5. Compare each key with the teaching capacity
[ { "key": [ "north" ], "load": 10, "overloaded": true } ]6. Result
[ { "key": [ "north" ], "load": 10, "overloaded": true } ]
Logical groups and invented work units do not simulate physical partitions or predict vendor throughput.
1. Start with the question the application will ask
The technician opens one asset’s recent readings. That request knows the tenant and asset identity. A key containing both can locate the asset’s records without asking every partition to search. A report across every asset has different needs and may require another view.
Write down those access patterns before selecting fields. A partition key is part of the query design because it decides what can be located together. Keep tenant identity in the authenticated request as well; a key containing a tenant name does not enforce authorisation.
A convenient lookup and an acceptable traffic distribution both matter.
2. Separate a logical key from a physical partition
A logical key is the value the application supplies. The database maps key ranges or hashes onto physical storage partitions, often moving them as the service grows. Several logical keys can share physical storage.
Our workshop groups traffic by logical key. It does not reproduce a vendor’s partition placement, adaptive capacity or hot-key mitigation. If one logical key dominates the trace, that is evidence to investigate. It is not a measurement of a physical server’s utilisation.
A random-looking key can distribute many independent items while leaving one popular item hot.
Check yourself
Questions on Parts 1 to 2
Question 1 of 2
Which design can separate these two groups?
Use the information below.
North has two groups: P7 uses 6 work units and P8 uses 4. The teaching capacity is 7 per logical key.3. Count work with the same key before judging the design
The Python trace is a list of dictionaries. Each dictionary contains the candidate key fields and load, an invented nonnegative work count measured over the same interval. A tuple gives us an unambiguous compound key. Concatenating text without boundaries can accidentally give different field combinations the same address.
Accumulate load for each tuple, then compare it with the supplied capacity. Preserve the groups in first-seen order so we can relate the output to the trace.
The trace measures work, not merely the number of stored records.
See which requests share an address
This program only groups addresses. The challenge adds traffic totals and overload decisions.
rows = [{"tenant":"north","asset":"P7"},
{"tenant":"north","asset":"P8"},
{"tenant":"north","asset":"P7"}]
keys = [(r["tenant"], r["asset"]) for r in rows]
print(keys)
print(len(set(keys)))[('north', 'P7'), ('north', 'P8'), ('north', 'P7')]
2The first and third requests share a compound key even though they occupy different positions in the input list.
4. A busy asset may need another deliberate split
The changed workshop trace sends most work to P7. Adding asset to the key no longer resolves the concentration. Time buckets can bound a growing history; a write shard can spread independent events from the same asset.
These choices move work into the reader. A day-spanning query must visit several buckets, and a sharded history may require parallel queries followed by a merge. A latest-value item that every request updates cannot be spread by renaming the same item several ways without defining how its values will be reconciled.
Measure both the writes you distribute and the extra reads your design creates.
5. Include item size, skew and changing traffic
Two request groups with equal counts may consume different work because their items have different sizes or their queries return different amounts of data. Measure the relevant service units and latency under representative load. Review secondary indexes too; they have their own keys and can concentrate writes differently.
A tenant can become busy after a successful rollout. Watch per-key concentration and throttling rather than relying only on an average across the table. Retain the access-pattern assumptions beside the design so that a new workload prompts a review.
The workshop limit is intentionally simple. Production capacity comes from the chosen database and measured operation sizes.
6. Choose a partitioning change with a migration path
Changing a key can change every address the readers know. A migration may need new records, backfill, compatibility reads and a controlled cutover. Decide how concurrent updates reach the new representation while the copy runs.
Keep a way to reconcile counts and identities before retiring the old view. If the old and new stores are independently writable, record which one owns the truth during each phase. Otherwise a traffic optimisation can introduce conflicting copies of the maintenance history.
The next lesson makes a bounded history bucket concrete and shows how its ordering supports the actual reading request.
Check yourself
Questions on Parts 1 to 6
Question 1 of 2
What extra work does bucketing introduce?
Use the information below.
The query needs all of P7’s events across three daily buckets.Try it with Botie
Build with Botie
Write and run Python