Cache keys are equivalence claims
Design canonical keys that preserve tenant, authorization, representation, and source-version boundaries.
On this page
The question for today
What you’ll understand
- Explain the correctness implication of sharing a cache key.
- Distinguish safe canonicalization from collapsing meaningful request differences.
- Account for representation and authorization context without storing raw credentials.
A cache key claims that requests mapped to it can safely reuse the same stored result under a defined freshness contract. A collision in that meaning can leak another tenant's data or return a different representation even when the hash function is perfect. Begin with the equivalence relation the application actually permits. Encoding and hashing come later, after identity, permissions, parameters, and version boundaries have been specified.
Define which results can be shared
List every input that can change the response: tenant identity, resource identity, selected fields, locale, format, feature configuration, and source version where relevant. Authorization needs particular care. A tenant-scoped key may still be too broad when users in that tenant have different visibility. Recheck permissions at the appropriate boundary and decide whether entries represent public, role-scoped, user-scoped, or permission-versioned data. A correct identifier does not make a previously authorized result safe after permissions change.
A raw bearer token is generally a poor cache-key component because it exposes a secret and fragments entries unnecessarily. Prefer a stable nonsecret authorization scope or a deliberate private-cache policy, while preserving the actual access-control decision. For HTTP shared caches, follow the protocol's Authorization and cache-control rules rather than implementing an informal application rule. Vary identifies relevant request-header dimensions, but does not automatically capture every application-specific tenant or permission distinction.
Canonicalization must preserve meaning
Sorting independent named parameters can make equivalent requests share a key, but repeated parameters, order-sensitive filters, Unicode normalization, case, and missing-versus-empty values may change meaning. Apply transformations only when the API contract establishes equivalence. Use a structured, unambiguous encoding, such as length-prefixed fields or a precisely specified serializer. Naive concatenation can make different tuples identical before hashing, which no stronger digest can repair. Test both equivalences and intentionally distinct near-collisions.
Namespace keys by schema or representation version so a deployment can change the stored shape without interpreting old bytes incorrectly. Bound key lengths and reject unsupported input combinations. A digest can compact a canonical encoding, but digest collision handling and operational debuggability still need a policy. Avoid logging sensitive canonical contents merely to debug hit rates. Store enough nonsecret metadata to identify the key schema and scope without recreating a credential or personal-data leak.
Test shared and separated cases deliberately
Create paired requests that should share a response and paired requests that must remain separate. Include tenants with overlapping resource identifiers, permission changes, locale differences, missing parameters, and repeated fields. Check the actual returned data and authorization result, not just generated strings. A warm-cache test matters because a cold request can consult the origin and conceal a flawed reuse decision. During a key-schema rollout, measure temporary duplicate storage and cold-origin load as well as correctness.
The cache lab demonstrates key identity only as a toy address trace. Reset and set both C=4, s=4; predict four distinct identifiers and twelve hits among the initial sixteen requests, then Step to add one hit. The fully associative empty-start LRU trace requests (i×s) mod 16 and caps at 4096 requests. It has no tenant, permission, or representation context. Its successful hits therefore cannot validate an application's equivalence relation; explain which extra key dimensions would make those reused values safe.
Work it through
Count useful representation dimensions
A resource has 12 tenants,3 supported locales, and 2 response formats. Resource identifiers can repeat across tenants. Assume every combination is allowed and has different reusable bytes.
For one identifier value, the tenant-locale-format combinations number 12×3×2=72. A key containing only the identifier incorrectly collapses all seventy-two possibilities.
Adding tenant but omitting locale and format still merges six potentially different responses per tenant. A canonical tuple must preserve all three dimensions under the stated contract.
If authorization differs within a tenant, even the 72-way partition may be insufficient. Add the appropriate nonsecret scope or private policy, and handle permission-version changes rather than embedding raw credentials.
Cardinality follows the response contract. Fewer keys are not an optimization when they merge results that cannot safely be shared.
The living notebook
Explore the model
Interactive lab · cache
A hit proves identity only within the toy
Reset and set C=4, s=4: predict four misses and twelve hits at t=0, then Step to add one hit. This capped 4096-request LRU address model has no authorization, tenants, canonicalization, or HTTP cache rules.
- Hits / requests
- 0 / 16
- Hit rate
- 0%
- Address-stream period
- 16 addresses
A fully associative LRU cache starts empty and requests address (i·s) mod 16. Hits move an address to the newest position; misses evict the oldest when full. Playback starts with 16 requests and adds two per second, capped at 4096 explicitly simulated requests. This toy stream is not a processor-cache benchmark. 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 forKey equality is useful only when it preserves the real response and access-control contract.
Pause & reason
Check your understanding
Your turn
Try it yourself
A search API treats repeated sort fields as order-sensitive but treats the order of independent filter names as irrelevant. Which part may be sorted during canonicalization, and what test would expose an unsafe transformation?
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Canonicalization follows semantic equivalence rather than visual similarity of requests.
Compare with the solution
Sort independent filter-name entries only under the API's stated equivalence, preserving their values and multiplicity rules. Do not sort the ordered sort-field sequence. A paired warm-cache test with sort=[price, rating] versus sort=[rating, price] should preserve different results when the contract says their precedence differs. Also test different tenants to ensure canonicalization does not erase access boundaries.
Keep the idea
Take it with you
- Key sharing is a claim about safe response equivalence.
- Canonicalization must preserve access scope and meaningful parameter differences.
- Versioned schemas and warm-cache tests reveal reuse errors that hashing cannot fix.
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.