Marketplace-Research OpenSearch + Personalize Caching Best Practices
A reference distillation of caching strategies for two-sided marketplaces running AWS OpenSearch (search) and AWS Personalize (recommendations behind a microservice). Contains 52 rules across 9 categories, ordered by cascade effect — from the upstream decision of whether to cache, through key design, personalisation boundary, strategy selection, TTL design, stampede protection, observability, and the lower-cascade categories of negative caching and tier composition. Each rule explains the WHY (the cost, latency, or correctness mechanism), shows incorrect-vs-correct code (TypeScript/Node for the microservice layer, Python for batch and analytics, OpenSearch JSON for OS-specific queries, YAML for CDN/Kubernetes), and cites the canonical source — AWS Personalize/OpenSearch/ElastiCache documentation, the XFetch paper (Vattani et al. VLDB 2015), RFC 5861 (stale-while-revalidate), and the engineering blogs of cache infrastructure teams (Netflix EVCache, Pinterest Cachelib, Twitter Twemcache, Cloudflare).
This is the complement to opensearch-function-scoring-algorithms — that skill answers "what should the ranking compute?", this skill answers "how do you scale it to production traffic without burning down OpenSearch or Personalize?"
When to Apply
Reach for this skill when:
- Adding caching to a search or recommendation surface for the first time — start with decide-cache-roi-calculation and decide-hot-key-distribution
- A homepage or category page renders 5+ recommenders and Personalize bills are growing faster than traffic — decide-amplification-multiplier, pers-recommender-fan-out-coalescing, pers-cohort-precomputation
- Cache hit rate is suspiciously low (under 30-40%) and you don't know why — key-canonicalize-query, key-strip-volatile-params, key-bucket-numerical-ranges, obs-key-cardinality-tracking
- Personalize is throttling (HTTP 429) during traffic spikes — decide-personalize-quota-budget, neg-cache-throttled-personalize, stamp-circuit-breaker-on-origin-error
- p99 spikes at TTL boundaries — stamp-coalesce-concurrent-misses, stamp-probabilistic-early-expiration, stamp-serve-stale-on-rebuild, ttl-soft-and-hard, ttl-jitter-to-prevent-thundering
- Recommendations stay stale after a model retrain — key-version-the-model, ttl-personalize-solution-version, strat-async-warm-up
- A read-after-write surface shows stale data (user favourites, saved searches) — strat-write-through-mutations, ttl-event-driven-invalidation
- Cache decisions need to be defensible to finance — decide-cache-roi-calculation, obs-cost-attribution, obs-cache-simulation-from-logs
- Anonymous and logged-in traffic mix on the same routes — pers-anonymous-vs-logged-split, tier-cdn-for-anonymous
- Cache is at memory pressure and you need to know whether to upsize, shorten TTL, or change strategy — decide-hot-key-distribution, tier-l2-elasticache-redis, obs-cache-simulation-from-logs
- OpenSearch CPU is high on common queries — tier-opensearch-request-cache, tier-opensearch-filter-context, neg-cache-empty-results
- A traffic spike from a viral link or crawler is hammering the origin — neg-bloom-filter-against-misses, neg-cache-empty-results, stamp-circuit-breaker-on-origin-error
The rules apply to any AWS-based marketplace with OpenSearch and Personalize fronted by an application microservice, regardless of vertical — accommodation, food delivery, fashion, services, jobs, secondhand goods, real estate. Triggers include "cache hit rate", "cache miss storm", "Personalize throttling", "Personalize cost", "multi-recommender page", "cohort caching", "single-flight", "stale-while-revalidate", "XFetch", "OpenSearch slow queries", "ElastiCache sizing", "CloudFront search caching", "Bloom filter cache penetration", and "thundering herd".
The Caching Pipeline
Categories are derived from the request-time caching pipeline. Earlier stages cascade: a wrong "should we cache?" decision wastes everything below; un-canonicalised keys cap hit rate at a fraction of the achievable ceiling; without observability you can't tell whether any of the rules helped.
Request → [1] Decide → [2] Key construction → [3] Personalisation boundary
→ [4] Strategy (read/write path) → [5] TTL/freshness → [6] Stampede protection
→ [8] Negative/defensive → [9] Tier composition (L1/L2/CDN/OS-internal) → Response
↑
[7] Observability (meta-layer applied to all stages:
hit rate by key class, latency-with-and-without,
cost-per-1k, cardinality, staleness, log-replay)
Rule Categories by Priority
| Priority |
Category |
Impact |
Prefix |
Rules |
| 1 |
Decision & Cost Calculus |
CRITICAL |
decide- |
7 |
| 2 |
Cache Key Design |
CRITICAL |
key- |
7 |
| 3 |
Personalisation Boundary |
HIGH |
pers- |
6 |
| 4 |
Strategies & Write Paths |
HIGH |
strat- |
6 |
| 5 |
TTL & Freshness |
HIGH |
ttl- |
6 |
| 6 |
Stampede Protection |
HIGH |
stamp- |
5 |
| 7 |
Observability & Empirical Measurement |
HIGH |
obs- |
6 |
| 8 |
Negative & Defensive Caching |
MEDIUM-HIGH |
neg- |
4 |
| 9 |
Tiered & Edge Caching |
MEDIUM-HIGH |
tier- |
5 |
Quick Reference
1. Decision & Cost Calculus (CRITICAL)
decide-cache-roi-calculation — Compute Cache ROI Before Adding the Cache
decide-cardinality-floor — Skip Caching When Traffic Distribution is Flat
decide-personalize-quota-budget — Model Personalize TPS Budget Before Choosing a Cache Strategy
decide-latency-budget — Cache Only When Origin p99 Exceeds the Latency Budget
decide-amplification-multiplier — Account for Multi-Recommender Page Amplification
decide-hot-key-distribution — Profile Traffic Distribution Before Sizing the Cache
decide-search-vs-personalize-asymmetry — Cache Candidate Sets for Search, Full Payloads for Personalize
2. Cache Key Design (CRITICAL)
key-canonicalize-query — Canonicalise Queries Before Hashing
key-segment-not-user — Key Recommenders by Cohort When Users Outnumber Cohorts
key-version-the-model — Include the Personalize Solution Version in the Cache Key
key-locale-currency-explicit — Make Locale, Currency, and Timezone Explicit in the Key
key-strip-volatile-params — Strip Volatile and Tracking Params Before Hashing
key-bucket-numerical-ranges — Bucket Continuous Filters Before Hashing
key-stable-hash-algorithm — Use SHA-256 over MD5 for High-Cardinality Keys
3. Personalisation Boundary (HIGH)
pers-cohort-precomputation — Precompute Recommendations Per Cohort Offline
pers-anonymous-vs-logged-split — Route Anonymous Traffic to Global Cache, Logged-in to Cohort Cache
pers-cold-start-cache-priority — Serve Cold-Start Users From Popularity Cache, Skip Personalize
pers-recommender-fan-out-coalescing — Coalesce Multi-Recommender Fan-Out Into Batched Calls
pers-shared-candidates-private-ranking — Cache Retrieval Candidates Globally, Re-Rank Per-User From Cache
pers-session-vector-write-through — Maintain Session Vectors in Cache with Write-Through on Every Event
4. Strategies & Write Paths (HIGH)
strat-cache-aside-default — Use Cache-Aside as the Default Strategy for Read-Heavy Paths
strat-refresh-ahead-hot-keys — Use Refresh-Ahead Only for the Top 1% of Hot Keys
strat-write-through-mutations — Use Write-Through When User Mutations Are Immediately Re-Read
strat-precompute-batch — Precompute the Popular Fraction with Batch Jobs
strat-tiered-promotion — Promote to L1 In-Process Cache on L2 Hit
strat-async-warm-up — Async Warm-Up After Deploy, Restart, or Model Retrain
5. TTL & Freshness (HIGH)
ttl-by-content-volatility — Set TTL From Content Volatility, Not Engineering Convenience
ttl-soft-and-hard — Separate Soft TTL (Async Refresh) from Hard TTL (Sync Miss)
ttl-jitter-to-prevent-thundering — Add Random Jitter to TTL to Prevent Synchronized Expiry
ttl-personalize-solution-version — Pin TTL to Personalize Solution Version, Not Wall Clock
ttl-event-driven-invalidation — Pair TTL with Event-Driven Invalidation for Critical Freshness
ttl-bound-by-staleness-tolerance — Bound TTL by Product Staleness Tolerance, Not the Default
6. Stampede Protection (HIGH)
stamp-coalesce-concurrent-misses — Coalesce Concurrent Misses Into a Single Origin Call
stamp-probabilistic-early-expiration — Use XFetch Probabilistic Early Expiration for Hot Keys
stamp-serve-stale-on-rebuild — Serve Stale While Refresh Is In Flight
stamp-circuit-breaker-on-origin-error — Trip the Circuit Breaker on Origin Errors; Fall Back to Stale
stamp-distributed-lock-rebuild — Use a Distributed Lock to Coordinate Cross-Instance Cache Rebuilds
7. Observability & Empirical Measurement (HIGH)
obs-hit-rate-by-key-class — Track Hit Rate by Key Class, Never Aggregate Only
obs-latency-histograms-with-without — Measure Latency Histograms With-Hit and With-Miss Separately
obs-cost-attribution — Attribute Cost Per Thousand Requests With and Without Cache
obs-key-cardinality-tracking — Sample Key Cardinality Daily; Alert on Explosion
obs-stale-served-ratio — Measure Stale-Served Ratio to Validate TTL Choice
obs-cache-simulation-from-logs — Replay Production Logs Through a Cache Simulator Before Changing TTL or Strategy
8. Negative & Defensive Caching (MEDIUM-HIGH)
neg-cache-empty-results — Cache Empty Search Results With a Short TTL
neg-cache-throttled-personalize — Serve Last-Known-Good When Personalize Throttles
neg-bloom-filter-against-misses — Use a Bloom Filter to Block High-Cardinality Miss Storms
neg-poison-pill-detection — Checksum Cache Entries to Detect and Reject Poisoned Writes
9. Tiered & Edge Caching (MEDIUM-HIGH)
tier-l1-in-process — Use In-Process LRU as L1 for Sub-Millisecond Reads
tier-l2-elasticache-redis — Size L2 ElastiCache to the Cross-Instance Working Set
tier-cdn-for-anonymous — Use CDN for Anonymous Traffic; Bypass for Cookies
tier-opensearch-request-cache — Enable OpenSearch Request Cache for Aggregation-Heavy Queries
tier-opensearch-filter-context — Put Reusable Predicates in Filter Context for Segment-Level Caching
How to Use
For a focused question ("should I cache this?", "why is my hit rate low?", "how do I survive Personalize throttling?"), jump directly to the relevant rule — each is self-contained with the WHY, code, and citation.
For a full caching-design review of a new or struggling surface, work the categories top-to-bottom. The cascade is real: a wrong decide-cache-roi-calculation wastes engineering effort on a cache that doesn't pay; a leaky key-canonicalize-query caps the achievable hit rate; a missing pers-cohort-precomputation keeps Personalize bills proportional to MAU. Stampede and observability are mandatory once hit rate exceeds 90% — the 10% miss in a thundering herd kills the origin, and without per-class hit-rate dashboards you can't tell.
For tuning an existing cache empirically, start with obs-cache-simulation-from-logs (replay your logs through what-if configs) and pair with obs-hit-rate-by-key-class, obs-cost-attribution, and obs-stale-served-ratio for the dashboards. The trio answers: is the cache doing its job, what does it cost, and are users seeing stale data?
For the multi-recommender homepage problem specifically (the most common Personalize cost-explosion pattern), the priority order is: decide-amplification-multiplier → pers-cohort-precomputation → pers-recommender-fan-out-coalescing → pers-anonymous-vs-logged-split. These four typically cut Personalize spend by 70-90% on consumer marketplaces.
For the "Personalize is throttling under load" incident, the priority is: stamp-circuit-breaker-on-origin-error → neg-cache-throttled-personalize → decide-personalize-quota-budget. The first two stabilise the user-facing impact; the third right-sizes minProvisionedTPS so it doesn't happen again.
For sibling-skill cross-reference, see opensearch-function-scoring-algorithms — that skill covers what to compute in OpenSearch (function_score, kNN, RRF, rank_feature, decay, LTR, MMR, evaluation). This skill covers how to cache it so the cluster survives production traffic.
Read section definitions for the cascade-impact rationale, or the rule template when adding a new rule.
Related Skills
Reference Files
| File |
Description |
| references/_sections.md |
Category definitions and ordering by cascade impact |
| AGENTS.md |
Compact TOC navigation (auto-built; do not edit by hand) |
| assets/templates/_template.md |
Template for authoring new rules |
| metadata.json |
Version and authoritative reference URLs |
1---
2name: opensearch-personalize-caching-strategies
3description: Caching strategies in front of AWS OpenSearch (Elasticsearch) or AWS Personalize — search, recommenders, multi-recommender pages, anon vs logged-in traffic. Covers ROI decision (TPS/minProvisionedTPS, Zipf, amplification), key design (canonicalisation, cohort vs user, solution-version pinning, bucketing), personalisation boundary (anon/logged split, fan-out coalescing), strategies (cache-aside, refresh-ahead, write-through, batch precompute, L1+L2), TTL (volatility, soft/hard, jitter, event-driven invalidation), stampede protection (single-flight, XFetch, stale-while-revalidate, circuit breaker), observability (hit-rate, cost-per-1k, cardinality drift, log-replay), defensive caching (negative, Bloom filter), and tier composition (LRU, ElastiCache Redis, CloudFront, OpenSearch request/filter cache). Triggers on cache hit rate, Personalize throttling, stampede, single-flight, L1/L2, ElastiCache sizing. Complements opensearch-function-scoring-algorithms.
4---
5
6# Marketplace-Research OpenSearch + Personalize Caching Best Practices
7
8A reference distillation of caching strategies for two-sided marketplaces running AWS OpenSearch (search) and AWS Personalize (recommendations behind a microservice). Contains **52 rules across 9 categories**, ordered by cascade effect — from the upstream decision of *whether* to cache, through key design, personalisation boundary, strategy selection, TTL design, stampede protection, observability, and the lower-cascade categories of negative caching and tier composition. Each rule explains the WHY (the cost, latency, or correctness mechanism), shows incorrect-vs-correct code (TypeScript/Node for the microservice layer, Python for batch and analytics, OpenSearch JSON for OS-specific queries, YAML for CDN/Kubernetes), and cites the canonical source — AWS Personalize/OpenSearch/ElastiCache documentation, the XFetch paper (Vattani et al. VLDB 2015), RFC 5861 (stale-while-revalidate), and the engineering blogs of cache infrastructure teams (Netflix EVCache, Pinterest Cachelib, Twitter Twemcache, Cloudflare).
9
10This is the **complement** to [`opensearch-function-scoring-algorithms`](../opensearch-function-scoring-algorithms/) — that skill answers "what should the ranking compute?", this skill answers "how do you scale it to production traffic without burning down OpenSearch or Personalize?"
11
12## When to Apply
13
14Reach for this skill when:
15
16- Adding caching to a search or recommendation surface for the first time — start with [decide-cache-roi-calculation](references/decide-cache-roi-calculation.md) and [decide-hot-key-distribution](references/decide-hot-key-distribution.md)
17- A homepage or category page renders 5+ recommenders and Personalize bills are growing faster than traffic — [decide-amplification-multiplier](references/decide-amplification-multiplier.md), [pers-recommender-fan-out-coalescing](references/pers-recommender-fan-out-coalescing.md), [pers-cohort-precomputation](references/pers-cohort-precomputation.md)
18- Cache hit rate is suspiciously low (under 30-40%) and you don't know why — [key-canonicalize-query](references/key-canonicalize-query.md), [key-strip-volatile-params](references/key-strip-volatile-params.md), [key-bucket-numerical-ranges](references/key-bucket-numerical-ranges.md), [obs-key-cardinality-tracking](references/obs-key-cardinality-tracking.md)
19- Personalize is throttling (HTTP 429) during traffic spikes — [decide-personalize-quota-budget](references/decide-personalize-quota-budget.md), [neg-cache-throttled-personalize](references/neg-cache-throttled-personalize.md), [stamp-circuit-breaker-on-origin-error](references/stamp-circuit-breaker-on-origin-error.md)
20- p99 spikes at TTL boundaries — [stamp-coalesce-concurrent-misses](references/stamp-coalesce-concurrent-misses.md), [stamp-probabilistic-early-expiration](references/stamp-probabilistic-early-expiration.md), [stamp-serve-stale-on-rebuild](references/stamp-serve-stale-on-rebuild.md), [ttl-soft-and-hard](references/ttl-soft-and-hard.md), [ttl-jitter-to-prevent-thundering](references/ttl-jitter-to-prevent-thundering.md)
21- Recommendations stay stale after a model retrain — [key-version-the-model](references/key-version-the-model.md), [ttl-personalize-solution-version](references/ttl-personalize-solution-version.md), [strat-async-warm-up](references/strat-async-warm-up.md)
22- A read-after-write surface shows stale data (user favourites, saved searches) — [strat-write-through-mutations](references/strat-write-through-mutations.md), [ttl-event-driven-invalidation](references/ttl-event-driven-invalidation.md)
23- Cache decisions need to be defensible to finance — [decide-cache-roi-calculation](references/decide-cache-roi-calculation.md), [obs-cost-attribution](references/obs-cost-attribution.md), [obs-cache-simulation-from-logs](references/obs-cache-simulation-from-logs.md)
24- Anonymous and logged-in traffic mix on the same routes — [pers-anonymous-vs-logged-split](references/pers-anonymous-vs-logged-split.md), [tier-cdn-for-anonymous](references/tier-cdn-for-anonymous.md)
25- Cache is at memory pressure and you need to know whether to upsize, shorten TTL, or change strategy — [decide-hot-key-distribution](references/decide-hot-key-distribution.md), [tier-l2-elasticache-redis](references/tier-l2-elasticache-redis.md), [obs-cache-simulation-from-logs](references/obs-cache-simulation-from-logs.md)
26- OpenSearch CPU is high on common queries — [tier-opensearch-request-cache](references/tier-opensearch-request-cache.md), [tier-opensearch-filter-context](references/tier-opensearch-filter-context.md), [neg-cache-empty-results](references/neg-cache-empty-results.md)
27- A traffic spike from a viral link or crawler is hammering the origin — [neg-bloom-filter-against-misses](references/neg-bloom-filter-against-misses.md), [neg-cache-empty-results](references/neg-cache-empty-results.md), [stamp-circuit-breaker-on-origin-error](references/stamp-circuit-breaker-on-origin-error.md)
28
29The rules apply to any AWS-based marketplace with OpenSearch and Personalize fronted by an application microservice, regardless of vertical — accommodation, food delivery, fashion, services, jobs, secondhand goods, real estate. Triggers include "cache hit rate", "cache miss storm", "Personalize throttling", "Personalize cost", "multi-recommender page", "cohort caching", "single-flight", "stale-while-revalidate", "XFetch", "OpenSearch slow queries", "ElastiCache sizing", "CloudFront search caching", "Bloom filter cache penetration", and "thundering herd".
30
31## The Caching Pipeline
32
33Categories are derived from the request-time caching pipeline. Earlier stages cascade: a wrong "should we cache?" decision wastes everything below; un-canonicalised keys cap hit rate at a fraction of the achievable ceiling; without observability you can't tell whether any of the rules helped.
34
35```text
36Request → [1] Decide → [2] Key construction → [3] Personalisation boundary
37 → [4] Strategy (read/write path) → [5] TTL/freshness → [6] Stampede protection
38 → [8] Negative/defensive → [9] Tier composition (L1/L2/CDN/OS-internal) → Response
39 ↑
40 [7] Observability (meta-layer applied to all stages:
41 hit rate by key class, latency-with-and-without,
42 cost-per-1k, cardinality, staleness, log-replay)
43```
44
45## Rule Categories by Priority
46
47| Priority | Category | Impact | Prefix | Rules |
48|----------|----------|--------|--------|-------|
49| 1 | Decision & Cost Calculus | CRITICAL | `decide-` | 7 |
50| 2 | Cache Key Design | CRITICAL | `key-` | 7 |
51| 3 | Personalisation Boundary | HIGH | `pers-` | 6 |
52| 4 | Strategies & Write Paths | HIGH | `strat-` | 6 |
53| 5 | TTL & Freshness | HIGH | `ttl-` | 6 |
54| 6 | Stampede Protection | HIGH | `stamp-` | 5 |
55| 7 | Observability & Empirical Measurement | HIGH | `obs-` | 6 |
56| 8 | Negative & Defensive Caching | MEDIUM-HIGH | `neg-` | 4 |
57| 9 | Tiered & Edge Caching | MEDIUM-HIGH | `tier-` | 5 |
58
59## Quick Reference
60
61### 1. Decision & Cost Calculus (CRITICAL)
62
63- [`decide-cache-roi-calculation`](references/decide-cache-roi-calculation.md) — Compute Cache ROI Before Adding the Cache
64- [`decide-cardinality-floor`](references/decide-cardinality-floor.md) — Skip Caching When Traffic Distribution is Flat
65- [`decide-personalize-quota-budget`](references/decide-personalize-quota-budget.md) — Model Personalize TPS Budget Before Choosing a Cache Strategy
66- [`decide-latency-budget`](references/decide-latency-budget.md) — Cache Only When Origin p99 Exceeds the Latency Budget
67- [`decide-amplification-multiplier`](references/decide-amplification-multiplier.md) — Account for Multi-Recommender Page Amplification
68- [`decide-hot-key-distribution`](references/decide-hot-key-distribution.md) — Profile Traffic Distribution Before Sizing the Cache
69- [`decide-search-vs-personalize-asymmetry`](references/decide-search-vs-personalize-asymmetry.md) — Cache Candidate Sets for Search, Full Payloads for Personalize
70
71### 2. Cache Key Design (CRITICAL)
72
73- [`key-canonicalize-query`](references/key-canonicalize-query.md) — Canonicalise Queries Before Hashing
74- [`key-segment-not-user`](references/key-segment-not-user.md) — Key Recommenders by Cohort When Users Outnumber Cohorts
75- [`key-version-the-model`](references/key-version-the-model.md) — Include the Personalize Solution Version in the Cache Key
76- [`key-locale-currency-explicit`](references/key-locale-currency-explicit.md) — Make Locale, Currency, and Timezone Explicit in the Key
77- [`key-strip-volatile-params`](references/key-strip-volatile-params.md) — Strip Volatile and Tracking Params Before Hashing
78- [`key-bucket-numerical-ranges`](references/key-bucket-numerical-ranges.md) — Bucket Continuous Filters Before Hashing
79- [`key-stable-hash-algorithm`](references/key-stable-hash-algorithm.md) — Use SHA-256 over MD5 for High-Cardinality Keys
80
81### 3. Personalisation Boundary (HIGH)
82
83- [`pers-cohort-precomputation`](references/pers-cohort-precomputation.md) — Precompute Recommendations Per Cohort Offline
84- [`pers-anonymous-vs-logged-split`](references/pers-anonymous-vs-logged-split.md) — Route Anonymous Traffic to Global Cache, Logged-in to Cohort Cache
85- [`pers-cold-start-cache-priority`](references/pers-cold-start-cache-priority.md) — Serve Cold-Start Users From Popularity Cache, Skip Personalize
86- [`pers-recommender-fan-out-coalescing`](references/pers-recommender-fan-out-coalescing.md) — Coalesce Multi-Recommender Fan-Out Into Batched Calls
87- [`pers-shared-candidates-private-ranking`](references/pers-shared-candidates-private-ranking.md) — Cache Retrieval Candidates Globally, Re-Rank Per-User From Cache
88- [`pers-session-vector-write-through`](references/pers-session-vector-write-through.md) — Maintain Session Vectors in Cache with Write-Through on Every Event
89
90### 4. Strategies & Write Paths (HIGH)
91
92- [`strat-cache-aside-default`](references/strat-cache-aside-default.md) — Use Cache-Aside as the Default Strategy for Read-Heavy Paths
93- [`strat-refresh-ahead-hot-keys`](references/strat-refresh-ahead-hot-keys.md) — Use Refresh-Ahead Only for the Top 1% of Hot Keys
94- [`strat-write-through-mutations`](references/strat-write-through-mutations.md) — Use Write-Through When User Mutations Are Immediately Re-Read
95- [`strat-precompute-batch`](references/strat-precompute-batch.md) — Precompute the Popular Fraction with Batch Jobs
96- [`strat-tiered-promotion`](references/strat-tiered-promotion.md) — Promote to L1 In-Process Cache on L2 Hit
97- [`strat-async-warm-up`](references/strat-async-warm-up.md) — Async Warm-Up After Deploy, Restart, or Model Retrain
98
99### 5. TTL & Freshness (HIGH)
100
101- [`ttl-by-content-volatility`](references/ttl-by-content-volatility.md) — Set TTL From Content Volatility, Not Engineering Convenience
102- [`ttl-soft-and-hard`](references/ttl-soft-and-hard.md) — Separate Soft TTL (Async Refresh) from Hard TTL (Sync Miss)
103- [`ttl-jitter-to-prevent-thundering`](references/ttl-jitter-to-prevent-thundering.md) — Add Random Jitter to TTL to Prevent Synchronized Expiry
104- [`ttl-personalize-solution-version`](references/ttl-personalize-solution-version.md) — Pin TTL to Personalize Solution Version, Not Wall Clock
105- [`ttl-event-driven-invalidation`](references/ttl-event-driven-invalidation.md) — Pair TTL with Event-Driven Invalidation for Critical Freshness
106- [`ttl-bound-by-staleness-tolerance`](references/ttl-bound-by-staleness-tolerance.md) — Bound TTL by Product Staleness Tolerance, Not the Default
107
108### 6. Stampede Protection (HIGH)
109
110- [`stamp-coalesce-concurrent-misses`](references/stamp-coalesce-concurrent-misses.md) — Coalesce Concurrent Misses Into a Single Origin Call
111- [`stamp-probabilistic-early-expiration`](references/stamp-probabilistic-early-expiration.md) — Use XFetch Probabilistic Early Expiration for Hot Keys
112- [`stamp-serve-stale-on-rebuild`](references/stamp-serve-stale-on-rebuild.md) — Serve Stale While Refresh Is In Flight
113- [`stamp-circuit-breaker-on-origin-error`](references/stamp-circuit-breaker-on-origin-error.md) — Trip the Circuit Breaker on Origin Errors; Fall Back to Stale
114- [`stamp-distributed-lock-rebuild`](references/stamp-distributed-lock-rebuild.md) — Use a Distributed Lock to Coordinate Cross-Instance Cache Rebuilds
115
116### 7. Observability & Empirical Measurement (HIGH)
117
118- [`obs-hit-rate-by-key-class`](references/obs-hit-rate-by-key-class.md) — Track Hit Rate by Key Class, Never Aggregate Only
119- [`obs-latency-histograms-with-without`](references/obs-latency-histograms-with-without.md) — Measure Latency Histograms With-Hit and With-Miss Separately
120- [`obs-cost-attribution`](references/obs-cost-attribution.md) — Attribute Cost Per Thousand Requests With and Without Cache
121- [`obs-key-cardinality-tracking`](references/obs-key-cardinality-tracking.md) — Sample Key Cardinality Daily; Alert on Explosion
122- [`obs-stale-served-ratio`](references/obs-stale-served-ratio.md) — Measure Stale-Served Ratio to Validate TTL Choice
123- [`obs-cache-simulation-from-logs`](references/obs-cache-simulation-from-logs.md) — Replay Production Logs Through a Cache Simulator Before Changing TTL or Strategy
124
125### 8. Negative & Defensive Caching (MEDIUM-HIGH)
126
127- [`neg-cache-empty-results`](references/neg-cache-empty-results.md) — Cache Empty Search Results With a Short TTL
128- [`neg-cache-throttled-personalize`](references/neg-cache-throttled-personalize.md) — Serve Last-Known-Good When Personalize Throttles
129- [`neg-bloom-filter-against-misses`](references/neg-bloom-filter-against-misses.md) — Use a Bloom Filter to Block High-Cardinality Miss Storms
130- [`neg-poison-pill-detection`](references/neg-poison-pill-detection.md) — Checksum Cache Entries to Detect and Reject Poisoned Writes
131
132### 9. Tiered & Edge Caching (MEDIUM-HIGH)
133
134- [`tier-l1-in-process`](references/tier-l1-in-process.md) — Use In-Process LRU as L1 for Sub-Millisecond Reads
135- [`tier-l2-elasticache-redis`](references/tier-l2-elasticache-redis.md) — Size L2 ElastiCache to the Cross-Instance Working Set
136- [`tier-cdn-for-anonymous`](references/tier-cdn-for-anonymous.md) — Use CDN for Anonymous Traffic; Bypass for Cookies
137- [`tier-opensearch-request-cache`](references/tier-opensearch-request-cache.md) — Enable OpenSearch Request Cache for Aggregation-Heavy Queries
138- [`tier-opensearch-filter-context`](references/tier-opensearch-filter-context.md) — Put Reusable Predicates in Filter Context for Segment-Level Caching
139
140## How to Use
141
142For a focused question ("should I cache this?", "why is my hit rate low?", "how do I survive Personalize throttling?"), jump directly to the relevant rule — each is self-contained with the WHY, code, and citation.
143
144For a full caching-design review of a new or struggling surface, work the categories top-to-bottom. The cascade is real: a wrong [decide-cache-roi-calculation](references/decide-cache-roi-calculation.md) wastes engineering effort on a cache that doesn't pay; a leaky [key-canonicalize-query](references/key-canonicalize-query.md) caps the achievable hit rate; a missing [pers-cohort-precomputation](references/pers-cohort-precomputation.md) keeps Personalize bills proportional to MAU. Stampede and observability are mandatory once hit rate exceeds 90% — the 10% miss in a thundering herd kills the origin, and without per-class hit-rate dashboards you can't tell.
145
146**For tuning an existing cache empirically**, start with [obs-cache-simulation-from-logs](references/obs-cache-simulation-from-logs.md) (replay your logs through what-if configs) and pair with [obs-hit-rate-by-key-class](references/obs-hit-rate-by-key-class.md), [obs-cost-attribution](references/obs-cost-attribution.md), and [obs-stale-served-ratio](references/obs-stale-served-ratio.md) for the dashboards. The trio answers: is the cache doing its job, what does it cost, and are users seeing stale data?
147
148**For the multi-recommender homepage problem specifically** (the most common Personalize cost-explosion pattern), the priority order is: [decide-amplification-multiplier](references/decide-amplification-multiplier.md) → [pers-cohort-precomputation](references/pers-cohort-precomputation.md) → [pers-recommender-fan-out-coalescing](references/pers-recommender-fan-out-coalescing.md) → [pers-anonymous-vs-logged-split](references/pers-anonymous-vs-logged-split.md). These four typically cut Personalize spend by 70-90% on consumer marketplaces.
149
150**For the "Personalize is throttling under load" incident**, the priority is: [stamp-circuit-breaker-on-origin-error](references/stamp-circuit-breaker-on-origin-error.md) → [neg-cache-throttled-personalize](references/neg-cache-throttled-personalize.md) → [decide-personalize-quota-budget](references/decide-personalize-quota-budget.md). The first two stabilise the user-facing impact; the third right-sizes minProvisionedTPS so it doesn't happen again.
151
152**For sibling-skill cross-reference**, see [`opensearch-function-scoring-algorithms`](../opensearch-function-scoring-algorithms/) — that skill covers what to compute in OpenSearch (function_score, kNN, RRF, rank_feature, decay, LTR, MMR, evaluation). This skill covers how to cache it so the cluster survives production traffic.
153
154Read [section definitions](references/_sections.md) for the cascade-impact rationale, or [the rule template](assets/templates/_template.md) when adding a new rule.
155
156## Related Skills
157
158- [`opensearch-function-scoring-algorithms`](../opensearch-function-scoring-algorithms/) — Research-backed ranking, retrieval, and evaluation rules for OpenSearch. The "what to compute"; this skill is the "how to scale it."
159
160## Reference Files
161
162| File | Description |
163|------|-------------|
164| [references/_sections.md](references/_sections.md) | Category definitions and ordering by cascade impact |
165| [AGENTS.md](AGENTS.md) | Compact TOC navigation (auto-built; do not edit by hand) |
166| [assets/templates/_template.md](assets/templates/_template.md) | Template for authoring new rules |
167| [metadata.json](metadata.json) | Version and authoritative reference URLs |