epok
← Blog
·8 min read

When Fifty Alerts Are One Incident

An alert storm is fifty pages for one incident. How dedup, trace-ID incident grouping, dynamic suppression, and severity rationing cut the noise.

observabilitydevopssremonitoringon-call

It's 2:11am and your phone has buzzed fifty times. Checkout is down, the cart service is throwing, three queue workers are backed up, two latency SLOs just breached, and somewhere in the scroll there's a single line that actually matters: the payments database hit its connection limit. Fifty pages. One incident. One root cause. The other forty-nine are the same failure wearing different uniforms.

An alert storm is what happens when a monitoring tool alerts per symptom instead of per incident. The fix isn't fewer detectors or higher thresholds — it's grouping: collapsing every page that traces back to the same failure into one incident with its cause attached, so on-call gets woken once and starts in the right place. That's the whole job. Most tools don't do it; they hand you the storm and a search bar.

Why one failure becomes fifty pages

Cascades fan out. The payments DB saturates, so the payments service times out, so checkout returns 500s, so the cart retries and floods, so the order-confirmation worker backs up, so a latency SLO trips, so a synthetic check fails. Each of those is a real, true, individually-correct alert. Seven services, one cause.

A per-symptom alerting model treats all seven as peers. Each crosses its own threshold, fires its own page, shows up as its own row. Nothing in that model knows the cart's retry storm and the checkout 500s are the same event as the database hitting its ceiling. So you get the storm — and the loudest service is rarely the cause. Checkout throws the most errors because it sits downstream of everything, so it's the first thing you look at and the wrong thing. (We dug into that "loud victim, quiet culprit" pattern in from alert to cited root cause.)

The on-call cost isn't the fifty buzzes. It's that the storm buries the one line pointing at the database, and you burn the first twenty minutes triaging symptoms before anyone asks the right question.

Step one: dedup, so the same thing fires once

The first layer is deduplication. The same anomaly (same detector, service, and failure signature) shouldn't page you twice in five minutes just because it's still happening. It's one alert continuing, not a new event each evaluation cycle.

Epok keys every anomaly to a dedup signature and, within a suppression window (30 minutes by default), folds repeat detections into the existing alert instead of opening a new one. The fire count goes up, the evidence refreshes, your phone stays quiet. It's the unglamorous floor of noise control: before you can group fifty *different* symptoms, you have to stop one symptom from paging fifty times on its own.

Step two: incident grouping by shared trace ID across services

Dedup handles repeats of the same symptom. Grouping handles *different* symptoms that are the same incident.

Grouping by time alone is too blunt: treat anything firing in the same five-minute window as "probably related" and two unrelated incidents that happen to overlap get fused into one blob, while a slow cascade whose pieces fire minutes apart gets split into many.

The signal that actually proves two alerts belong together is a shared trace ID: a 128-bit identifier stamped on a single request as it crosses services. It isn't recycled in practice, so the same trace ID in checkout's error and the payments service's timeout isn't a coincidence — it's one request failing in two places. Epok treats a shared trace as an identity link strong enough to override the time-gap rule entirely. Symptoms eight minutes apart still collapse into one incident if they're carrying the same request through the system.

Underneath, grouping is connected-components clustering: alerts link when they share an identity (same service, same trace, or the same correlated deploy) and overlap in time. Linked alerts merge into one incident; unlinked ones stay separate. The output is one incident per real failure with the ranked probable cause at its head, not fifty peers and a guess.

Two things keep this honest. A degenerate trace ID (all zeros, a shared default) gets rejected, because fusing every service that emitted a placeholder would build one fictional mega-incident. And grouping doesn't depend on traces existing: where there's none, Epok falls back to shared deploys, co-moving error rates, and the cause downstream errors name, so an un-instrumented database with no spans of its own still lands in the right incident. (That fallback is also why a *silent* failure can be grouped correctly; we cover the absence case in the incidents that hide between alerts.)

Step three: suppression that widens the longer something burns

Grouping gets you to one incident. The next question is how often that one incident is allowed to page.

A flat re-page interval is wrong in both directions. Page every fifteen minutes forever and a long unacked incident becomes its own storm. Page once and go silent and a real outage falls off the radar. Epok widens the interval as an alert keeps firing: roughly 15 minutes, then an hour, then four hours, then a day, then once a day after that. The cadence borrows the shape of network retransmit backoff on purpose — a rhythm SREs recognize, and one that matches reality: the longer something sits unacknowledged, the less a fifth identical page in an hour adds.

By design, a single noisy unacked alert caps out at roughly thirty pages over a week instead of the eighty-plus a fixed two-hour cadence produces. You still get told. You don't get hammered. And the schedule is configurable, so a team can set its own.

Step four: severity rationing, so not everything pages

The last layer decides what deserves to wake a human at all. A new error appearing ten times in five minutes is worth knowing about; the same error appearing five thousand times while checkout returns 500s is a different category of event.

Epok grades severity by impact and confidence, not by which detector happened to fire. Low-confidence signals are capped (a startup banner matching an error keyword doesn't get to page critical), and channels filter by minimum severity, so info-level noise lands in a digest while the critical incident hits the pager. Repetition is weak evidence of seriousness, but it's bounded: an alert that keeps firing can escalate, yet a low-confidence signal can't launder itself into a critical page just by repeating. The honest verdict cuts both ways. Page hard when the evidence is strong, stay out of your night when it isn't. (How we keep that line calibrated, and why staying quiet matters as much as firing, is in accuracy without the noise.)

One incident, not fifty

Put the four layers together and the 2am storm changes shape. Dedup stops each symptom from paging on a loop. Grouping by trace ID collapses the seven cascading services into a single incident. Suppression keeps that one incident from re-paging you every fifteen minutes for the next six hours. Severity rationing makes sure the database-saturation page is loud and the downstream symptom noise stays in the digest.

What lands on your phone is one alert: *payments database connection pool exhausted, cascading to checkout and three downstream services,* with the evidence cited to the exact log lines and spans behind it. You start at the cause, not the loudest victim. That's the difference between an alerting tool and an incident tool — and it's the whole reason we built Epok to think in incidents instead of pages.

FAQ

What is an alert storm?

An alert storm is a flood of alerts — often dozens — triggered by a single underlying failure, because each affected service, queue, and SLO crosses its own threshold and pages independently. The failure is one incident; the storm is the same event reported many times. The fix is grouping correlated alerts into one incident rather than raising the thresholds that would also hide real problems.

What's the difference between alert deduplication and incident grouping?

Deduplication collapses repeats of the *same* alert — the same failure firing every evaluation cycle — into one ongoing alert. Incident grouping collapses *different* alerts that share a cause — checkout 500s, cart retries, and a database timeout — into one incident. You need both: dedup stops a single symptom from paging on a loop, grouping stops a cascade from paging once per affected service.

How does grouping alerts by trace ID work?

A trace ID is a unique identifier attached to one request as it travels across services. Because trace IDs aren't reused in practice, the same trace ID appearing in two services' errors means one request failed in both — strong evidence they're the same incident. Epok treats a shared, valid trace ID as an identity link that groups those alerts even when they fire minutes apart, and rejects placeholder or all-zero IDs that would falsely fuse unrelated failures.

How do you reduce alert noise without missing real incidents?

By cutting duplication and grouping rather than raising thresholds. Higher thresholds suppress noise and real signals equally. Epok dedups repeats, groups correlated symptoms into one incident, widens its re-page interval the longer an incident stays unacknowledged, and rations severity so low-confidence signals go to a digest instead of the pager — keeping recall while cutting the page count.

Does Epok require trace instrumentation to group alerts?

No. Shared trace IDs are the strongest grouping signal, but Epok also correlates by service identity, shared deploys, co-moving error rates, and the service that downstream errors name. A database or background worker with no spans of its own still gets grouped into the right incident by the other signals.

Try Epok free. First alerts in minutes.

No credit card. Every detector included, root cause on every incident. Full baseline coverage at 7 days.

Start 14-day trial
RELATED

Detection-First Observability: Stop Searching, Start Being Told

Detection-first observability flips the model: instead of storing everything and handing you a search bar, the tool finds the problem and proves it. Here's why search-first is backwards.

Root Cause Analysis Across Every Signal, On One Screen

Automated root cause analysis that reads logs, metrics, traces, infrastructure, and RUM together and cites every claim to its source, so you cut MTTR instead of hopping tabs.

Stop Building Monitoring by Hand

Static thresholds and hand-built dashboards both rot. Why you should stop writing alert rules and let detection learn each service's baseline instead.

Previous

Stop Building Monitoring by Hand

Next

How We Measure Detection Accuracy (and Admit When We're Not Sure)