InfrastructureSenior

Alerting

Alerting is how a system's state becomes a decision to wake somebody up. An alert is a request to interrupt a person, and it should be read that way every time one is written. Most alerting systems fail not because they miss things but because they cry wolf until the on-call engineer stops believing them — and that is a design failure, not a discipline problem. This page covers which conditions earn an interruption, why alerting on symptoms beats alerting on causes, how an SLO and a burn rate turn "the site feels slow" into a number worth waking up for, and what has to exist before a page is sent at all.

An alert is
An interruption
Alert on
Symptoms, not causes
Every page needs
An action, now

An alert is a request to interrupt a person

Alerting is usually taught as a technical question — which metric, which threshold, which window. It is better understood as an ethical and organisational one, because what an alert actually does is take a person away from their evening, their sleep or their concentration and point them at a problem. That framing produces a test that no threshold discussion can: if this fires at three in the morning, is there something a human must do immediately, and do they know what it is? If either half is no, it is not a page.

Two questions decide where a condition belongs, and neither is about thresholds. Does a human have to do something, and does that something have to happen now? Only the answer yes to both earns an interruption — that is a page. Yes to the first and no to the second is a ticket: real work, scheduled work. No to the first but urgent-looking is the dangerous quadrant, because someone is being woken for a condition they cannot act on; the fix is to the alert, not to the system. And no to both is a dashboard or a metric, not an alert at all. Every page that lands in the wrong quadrant costs more than the noise it makes, because it teaches the on-call engineer that pages can be ignored — and that lesson is applied to the next real one.

The bottom-left quadrant is the one worth staring at, because it is where most alerting systems actually go wrong. A condition looks urgent, someone is woken, and there is nothing they can do — the disk is filling on a node the platform will replace anyway, a dependency is degraded and its owners are already on it, the alert fired on a spike that resolved itself before anyone opened a laptop. The instinct is to tell the engineer to be more tolerant. The correct response is to change the alert, because every page that could not be acted on is a small deposit into the belief that pages can be ignored, and that belief is withdrawn during the real one.

Alert on symptoms, not on causes

The natural way to build alerting is to enumerate the things that can go wrong and put an alert on each: CPU above 90%, memory above 85%, disk above 80%, replica count below three, queue longer than a thousand. Each is defensible on its own and the set is a trap, for two reasons that pull in opposite directions. It fires constantly on conditions that are not hurting anyone — a batch job legitimately pinning CPU for ten minutes — and it misses entirely the failure nobody enumerated, which is the one that takes you down.

Symptom-based alerting inverts it. Instead of asking what could break, ask what the user experiences when something has broken, and alert on that: requests are failing, requests are slow, the queue is not draining, orders are not being placed. There are only a handful of such conditions per service, they cover causes nobody predicted, and each one is by construction something a user would complain about — which makes "is this worth waking someone" answer itself.

Alerting on a causeAlerting on the symptomWhy the second is better
CPU above 90% for 5 minutesp99 latency above the targetHigh CPU that hurts nobody is normal; slow responses are never normal.
Replica count below threeError rate above the targetTwo replicas serving perfectly is not an incident. Failing requests are, at any replica count.
Database connections near the limitRequests failing or timing outThe pool being full only matters if it is turning users away, which the symptom measures directly.
A specific job failedThe output is stale or missingA job can fail and be retried successfully; the data being late is the thing that has consequences.

SLOs and burn rate: alerting on a number that means something

Symptom alerting needs a target, and picking one by feel produces either an alert that never fires or one that fires every Tuesday. Three terms make the target explicit, and they are worth defining precisely because they are used loosely everywhere.

  • An SLI is the measurement: the proportion of requests that succeeded within 300 ms, as a number between 0 and 1. It is a ratio of good events to valid events, not an average.
  • An SLO is the target for that measurement over a window: 99.9% of requests over the last 28 days. It is a promise you choose, not one the system makes.
  • The error budget is what the SLO permits: 0.1% of 28 days is about 40 minutes of failure you are allowed to spend, and spending it is normal rather than a failure of discipline.

The budget is what makes alerting sane, because it converts an unanswerable question ("is 0.3% errors bad?") into an arithmetic one ("at this rate, how long until the month’s budget is gone?"). That ratio is the burn rate: burning at 1× spends the budget exactly over the window; at 14.4× a whole month’s budget is gone in two days. Alert on the burn rate rather than on the raw error rate, and the same alert covers both the sudden outage and the slow bleed that a fixed threshold always misses.

Fast burn — this is a page

  • Roughly 14× the budget rate, evaluated over a short window such as an hour.
  • At that rate a 28-day budget is gone in about two days: it will not resolve itself.
  • Confirm with a second, shorter window so a spike that has already stopped does not wake anyone.
  • This is the alert that goes to a phone at night, and there should be very few of them.

Slow burn — this is a ticket

  • Roughly 3× the budget rate over a long window such as six hours or a day.
  • Real degradation that gives you days rather than minutes, which is time to fix it in daylight.
  • Catches the slow bleed a fixed threshold never sees, because 0.5% errors looks fine in isolation.
  • Goes to a queue that is reviewed during working hours, never to a phone.

Alert fatigue is a design failure

When an on-call engineer stops reacting quickly, the usual diagnosis is that the person is not taking it seriously. The honest diagnosis is that the system taught them not to. A human who is interrupted twenty times a week by conditions that turned out to be nothing learns, correctly and unavoidably, that the next interruption is probably nothing too. You cannot train that away; you can only remove the interruptions that caused it.

The mechanics that keep the volume survivable are unglamorous and they work:

  • Group related alerts into one notification. A failing dependency should produce one page, not one per service that depends on it.
  • Suppress the downstream while the upstream is firing, so the cause is what reaches the person rather than forty consequences.
  • Require a duration, not an instant. A condition that must hold for five minutes filters out the spikes that resolve themselves.
  • Give every page a runbook link with the first three things to check. An alert without one is a puzzle handed to someone half asleep.
  • Review the alerts that fired every week, and delete or downgrade the ones nobody acted on. This meeting is the whole discipline.
  • Track pages per on-call shift as a number somebody owns. If it is not measured, it only ever goes up.

What has to exist before the page is sent

An alert is only the first second of a process, and the parts after it decide whether the interruption was worth anything. Four of them have to exist before the alert is switched on, not after the first incident proves they were missing.

  • A named owner

    A rotation, not a mailing list. An alert routed to a group where everyone assumes someone else has it is an alert nobody has.

  • A runbook

    Linked from the alert itself: what this means, the first three checks, how to mitigate, and who to escalate to. Written before the alert, in daylight.

  • Escalation with a timer

    If nobody acknowledges within a few minutes it goes to the next person automatically. Phones are silenced and people miss things; the system should assume it.

  • A review afterwards

    Blameless, focused on what made the failure possible and what made it hard to see. Its output is changes, including changes to the alert that found it.

One organisational point is worth stating plainly, because it decides whether any of this survives contact with a busy quarter. On-call has to be compensated and bounded — a rotation big enough that nobody carries it constantly, hours that are acknowledged as work, and permission to fix the causes of pages during normal time. Where that is absent, the alerting system degrades in a predictable direction: thresholds get loosened, alerts get muted, and the monitoring quietly stops describing the system. That outcome is not a failure of the engineers on the rotation, and it will not be fixed by adding another alert.

Anti-patterns worth naming

  • An alert per resource metric on every host, producing a wall of pages during any normal load spike.
  • Thresholds picked once and never revisited, so they describe a system that has since tripled in traffic.
  • Alerts routed to a chat channel that everyone has muted, which is deletion with extra steps.
  • A page with no runbook, handed to whoever is newest on the rotation at two in the morning.
  • Monitoring that runs inside the thing it monitors, so the outage takes the alerting with it.
  • A dashboard treated as monitoring, which only works while somebody happens to be looking at it.

When to use it

Use it when

  • A service where failure has consequences within minutes and a person can actually shorten those minutes.
  • Conditions expressed as user-visible symptoms — failing requests, slow responses, work not being completed.
  • Deadlines that are genuinely predictable — an expiring certificate, a disk that will be full before morning.
  • Any system with an on-call rotation, a runbook per alert and a weekly review of what actually fired.

Avoid it when

  • Conditions nobody can act on tonight — they belong in a ticket, however alarming the number looks.
  • Resource metrics as pages, when the resource being busy is not itself hurting a user.
  • A target chosen because it sounds impressive rather than from what users need and the business will fund.
  • Any alert without an owner, a runbook and an escalation path — those three missing is why pages go unanswered.

Found this useful?

Share it with someone who is working on the same problem.