Cache Stampede Simulator

flurly1 pts0 comments

GitHub - telemetry-sh/cache-stampede-lab: Simulate cache stampedes, synchronized TTL expiry, and origin overload. · GitHub

/" data-turbo-transient="true" />

Skip to content

Search or jump to...

Search code, repositories, users, issues, pull requests...

-->

Search

Clear

Search syntax tips

Provide feedback

--><br>We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Cancel

Submit feedback

Saved searches

Use saved searches to filter your results more quickly

-->

Name

Query

To see all available qualifiers, see our documentation.

Cancel

Create saved search

Sign in

/;ref_cta:Sign up;ref_loc:header logged out"}"<br>Sign up

Appearance settings

Resetting focus

You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.

Dismiss alert

{{ message }}

Uh oh!

There was an error while loading. Please reload this page.

telemetry-sh

cache-stampede-lab

Public

Notifications<br>You must be signed in to change notification settings

Fork

Star

main

BranchesTags

Go to file

CodeOpen more actions menu

Folders and files<br>NameNameLast commit message<br>Last commit date<br>Latest commit

History<br>1 Commit<br>1 Commit

.github/workflows

.github/workflows

cmd/cache-stampede-lab

cmd/cache-stampede-lab

docs

docs

stampede

stampede

web

web

.env.example

.env.example

.gitignore

.gitignore

LICENSE

LICENSE

README.md

README.md

go.mod

go.mod

View all files

Repository files navigation

Cache Stampede Lab

TTL jitter spreads expirations. It does not stop callers from stampeding the same hot key.

Cache Stampede Lab is a deterministic Go simulator for synchronized cache expiry. It places misses behind a finite origin worker pool and compares naive TTLs, TTL jitter, request coalescing, and stale-while-revalidate against the same seeded traffic.

Why this is interesting

Cache advice is often presented as a checklist: add jitter, use singleflight, serve stale data. Those controls solve different parts of the problem.

The default scenario has 1,800 requests per second, 24 hot keys, a 1-second TTL, and 16 origin workers. Its comparison is deliberately uncomfortable:

strategy p99 timeouts origin queue<br>naive 108ms 29.23% 55.37x 12295.5ms<br>ttl_jitter 247ms 44.45% 106.74x 20305.1ms<br>singleflight 119ms 0.00% 1.00x 2.4ms<br>stale_while_revalidate 3ms 0.00% 1.00x 2.4ms

TTL jitter desynchronizes different keys, but every request arriving after an individual hot key expires can still start a fill. In this workload, jitter creates more independent expiry waves without coalescing their callers. It is useful in combination with request collapsing; it is not a substitute for it.

The naive strategy's successful p99 looks deceptively low because requests that survive the queue are fast. Its 29% timeout rate and 12-second mean origin queue reveal the actual failure.

Run the interactive lab

Go 1.16 or newer is required.

go run ./cmd/cache-stampede-lab

Open http://127.0.0.1:3000. To choose another port:

PORT=3002 go run ./cmd/cache-stampede-lab

The browser application is embedded in the binary and served with net/http. There is no frontend build, framework, CDN, or runtime dependency.

Use the CLI

go run ./cmd/cache-stampede-lab compare --preset "Synchronized expiry"<br>go run ./cmd/cache-stampede-lab compare --preset "One viral key" --json<br>go run ./cmd/cache-stampede-lab compare --preset "Slow origin"

Use the simulation package

package main

import (<br>"fmt"

"github.com/telemetry-sh/cache-stampede-lab/stampede"

func main() {<br>config := stampede.DefaultConfig()<br>config.Strategy = stampede.Singleflight

result, err := stampede.Simulate(config)<br>if err != nil {<br>panic(err)

fmt.Printf("origin=%.2fx timeouts=%.2f%%\n",<br>result.OriginAmplificationFactor,<br>result.TimeoutPercent,

Model boundaries

This is a compact discrete-event model, not a production capacity planner.

Client requests arrive at a uniform rate with a seeded hot-key distribution.

Cache entries begin with synchronized expiry unless the jitter strategy is selected.

Origin fetches queue behind a fixed-size worker pool.

Late duplicate fills continue running and can extend a key's TTL.

Singleflight callers wait for the same in-flight fill.

Stale-while-revalidate serves cached data while one background fill runs.

Client cancellation does not remove work already accepted by the origin.

Eviction pressure, cache memory limits, network loss, multi-region propagation, and write invalidation are omitted.

Every strategy receives the same key sequence and origin service-time samples.

Optional aggregate telemetry

The lab runs offline unless TELEMETRY_API_KEY is set:

export TELEMETRY_API_KEY=your_project_api_key<br>go run ./cmd/cache-stampede-lab

The server sends aggregate events directly to the Telemetry ingestion endpoint. Only the strategy,...

stampede cache origin jitter strategy github

Related Articles