Lakshya

Infrastructure & Reliability · Reliability, operations & platforms · Chapter 8 of 33

Chaos engineering and game days

Controlled experiments on a running system, the human rehearsal that finds a different class of problem, and how to start without frightening anyone.

10 min read2 diagramsAll 33 chapters

Chapter 1 defined what reliable means and gave you a budget. This is how you find out whether the thing you built actually behaves the way you think it does — before an incident tells you it does not.

The name is wrong, and it matters

Chaos engineering is not breaking things randomly. It is the opposite: a controlled experiment with a written hypothesis, one variable, a bounded blast radius and an abort condition. The name conjures a monkey loose in production, which is the single biggest obstacle to getting it approved — and the obstacle is entirely linguistic.

IT IS AN EXPERIMENT, NOT A DEMOLITION — AND THE NAME IS THE PROBLEM STEP 1STEADY STATEWhat does “working” look like,as a NUMBER you already track?If you cannot say, stop here.STEP 2HYPOTHESIS“This will still hold whenone node dies / calls get slow.”Written down BEFORE you inject.STEP 3INJECTSmallest possible dose.Abort condition armed.One variable. Not three.STEP 4MEASUREDid it hold? What broke?What did NOT alert?The silent alert is the best find. You are trying to DISPROVE the hypothesis, not to break production. If nothing breaks, the experiment succeeded. That is the opposite of how the name sounds, and the name has probably cost this practice more adoption than any technical barrier. STEP 1 IS WHERE MOST TEAMS STOP, AND THAT IS ALREADY A RESULT. “We do not have a metric that would tell us whether checkout is healthy right now” is a finding worth the whole exercise, and you got it without touching anything. AND THE RULE THAT KEEPS YOU EMPLOYED: an abort condition, armed before you start. A threshold, who can call it, and a one-command stop. An experiment you cannot halt is not an experiment. It is an incident youscheduled.
Step 1 is the one that matters and the one people skip past. A team that cannot state its steady state has already learned something.

The framing that gets it approved

You are trying to disprove a hypothesis, not to cause an outage. The hypothesis is that your system already handles this. If nothing breaks, the experiment succeeded — you now have evidence rather than an assumption.

The failure you are injecting is going to happen anyway. A node will die, a dependency will slow down, a disk will fill. The only choice is whether it happens on a Tuesday afternoon with the team watching, or at 3am on a bank holiday.

Put that second sentence in the proposal. It reframes the ask from ‘may we break production’ to ‘may we choose when this happens’, and that is a different conversation.

Steady state is the whole discipline

Before you inject anything you must say what ‘working’ looks like as a number you already collect. Not ‘the service is up’ — something like orders completed per minute stays within its normal band, or p99 checkout latency stays under two seconds.

It must be a business-visible signal, not a component one. CPU is not steady state; a healthy pod count is not steady state. Both can look perfect while customers cannot buy anything — which is precisely the failure mode you are hunting.

And if the team cannot produce that number, stop there. You have found the real gap, it cost you nothing, and fixing it makes everything downstream possible. A surprising number of chaos programmes deliver their best finding in the first meeting.

What to inject

WHAT TO INJECT — RANKED BY WHAT IT TEACHES, NOT BY WHAT IS EASY LATENCY — do this firstSystems handle DOWN far better than SLOW. A dead dependency fails fast; a slow one drains your pool.Dependency failureThe database, the cache, the third-party API. Does the fallback exist, and has it ever run?Resource exhaustionFill the disk, eat the memory, exhaust the connection pool. Where does it degrade, and how loudly?Instance / pod lossThe classic. Easiest to do, and the one your platform probably already survives.Zone or region lossExpensive to test, and the only way to know your failover is real rather than configured.Certificates · clock skewBoring, and a recurring cause of real outages. Almost nobody tests them. Most teams start at row 4 because a tool makes it one click. Row 1 is where the findings are.
The top row is the recommendation. Most programmes start at row four because a tool makes it one click, and then wonder why the findings are thin.

Why latency beats failure, and it is the most useful thing in this chapter.

Systems are usually built to handle a dependency being DOWN. They are rarely built to handle it being SLOW.

A dead dependency refuses the connection immediately, your call fails fast, your fallback runs. A dependency answering in eight seconds instead of eighty milliseconds holds every one of your threads open while it does it — and your connection pool drains, and requests that have nothing to do with that dependency start queueing, and you go down because something else got slow.

That cascade is the single most common shape of a real large-scale outage, and injecting a few hundred milliseconds of latency is the cheapest way to find out whether you have it.

What experiments actually find

  • Retry storms. Every caller retries, nobody added jitter, and the moment the struggling service recovers it is flattened by the backlog. The system's own recovery behaviour is what prevents recovery.
  • Timeouts that do not compose. The classic: a caller with a 3-second timeout in front of a service whose own retry budget is 10 seconds. The caller gives up and retries while the first attempt is still running, so load triples under stress.
  • A fallback that has never executed. Written two years ago, never exercised, and it throws on the first call because a field was renamed.
  • A hidden dependency. The service you were told was standalone turns out to call the identity provider on every request.
  • And the best possible outcome: an alert that did not fire. The system degraded exactly as predicted, nobody was told, and you found that out on a Tuesday. Every experiment should check what alerted, not only what broke.

Game days — the same idea pointed at people

A game day runs a realistic scenario against real systems with the actual humans, in real time. Chaos experiments test whether the system copes. Game days test whether the organisation does — and they reliably find a different class of problem.

Chaos experimentGame day
TestsThe systemThe people and the process
Typically findsRetry storms, timeouts, missing fallbacksStale runbooks, unclear ownership, missing access
RunsAutomated, continuouslyScheduled, a few times a year
NeedsA tool and an abort switchCalendars, which is the harder problem

The findings from a first game day are almost never technical, and they are almost always the same three. The runbook references a dashboard that was migrated. The one person who knows how the failover works is on leave, and nobody else has the access. And the recovery procedure requires a tool that authenticates through the single sign-on which is part of the scenario.

That last one recurs so often it is worth designing against directly: at least one recovery path must not depend on the systems most likely to be down. See operational resilience, where the same problem appears in its most severe form — recovering when the identity provider itself is compromised.

How to start without frightening anyone

  • 1. Run a game day first. No production risk, no tooling, no approval battle — a room, a scenario and two hours. It will produce findings, which is what buys you permission for step 2.
  • 2. Experiment in staging, and be honest that staging lacks the traffic, the data volume and the people. It proves the mechanism, not the behaviour.
  • 3. Production, off-peak, smallest dose, abort armed, everyone watching. One instance, one percent of traffic, a few hundred milliseconds.
  • 4. Widen only after a boring result. If the experiment found something, fix it and re-run the same one before escalating scope.
  • 5. Automate last. Continuous automated chaos is the mature end state and a terrible beginning — an unattended experiment that finds something real at 2am is just an outage you caused.

Two things to fix before you start, not after: your observability has to be good enough to see the effect, or you are injecting failure blind — and you need a written rule that an experiment is never run during an active incident or a change freeze, because someone will otherwise do it during one.

What it does not tell you

It tests what you thought of. An experiment is a hypothesis, and you cannot hypothesise about a failure mode you have never imagined — so a long clean run is evidence about your imagination as much as about your system.

Which is why the regulatory cousin exists. Scenario testing under an operational resilience programme runs end to end, including suppliers and people, against a scenario somebody else chose. Chaos gives you continuous evidence that known failure modes are handled; scenario testing gives you periodic evidence that the business service survives a bad day. Most organisations have one and not the other, and they are usually run by teams that never speak — see operational resilience.

Check yourself

What is chaos engineering actually?A controlled experiment with a written hypothesis, one variable, a bounded blast radius and an abort condition. Not breaking things randomly — the name is the biggest obstacle to approval, and it is purely linguistic.
What is the framing that gets it approved?The failure is going to happen anyway. The only choice is whether it happens on a Tuesday with the team watching, or at 3am on a bank holiday.
What is a steady state, and what disqualifies one?A business-visible number you already collect — orders per minute, p99 checkout latency. CPU and pod count do not count; both can look perfect while customers cannot buy anything.
What if the team cannot state one?Stop there. You have found the real gap, it cost nothing, and a surprising number of programmes deliver their best finding in the first meeting.
Why inject latency before failure?Systems are built to handle a dependency being down, rarely to handle it being slow. A dead dependency fails fast; a slow one holds your threads open and drains the connection pool, so unrelated requests queue and you go down too.
What do experiments typically find?Retry storms with no jitter, timeouts that do not compose, fallbacks that have never executed, hidden dependencies — and the best find of all, an alert that did not fire.
How do game days differ?They test the organisation rather than the system. The findings are almost never technical: stale runbooks, the one person who knows is on leave, and a recovery tool behind the single sign-on that is part of the scenario.
What is the safe starting order?Game day first (no production risk, buys permission), then staging, then production off-peak with an abort armed, widen only after a boring result, and automate last.
Why is automating early a mistake?An unattended experiment that finds something real at 2am is just an outage you caused.
What can chaos engineering not tell you?Anything about a failure mode you never imagined. A long clean run is evidence about your imagination as much as your system — which is why end-to-end scenario testing exists alongside it.
← Running productionKubernetes, honestly →