Skip to lesson
‹

Courses / System Design Interview / Chapter 12

Module 2 · Building Blocks · Chapter 12 of 39

Monitoring: Metrics, Logs, Traces and Alerts

19 sections · ~32 min✓ Fact-checked

Builds on Availability, Reliability, Scalability and Latency, DNS: How a Name Becomes an Address, Load Balancers and Content Delivery Networks. Next up: Distributed Caches.

Part 1 · Why Watch a System

You cannot fix what you cannot see

10:00 am, board results day. Two million students (20 lakh) open the results site at once. Pages load, the servers look busy but fine, and the team relaxes. Meanwhile one of thirty servers has a full disk, and every request it serves fails: about 3% of students get a blank screen. Nobody on the team knows. The first sign is an angry post at 10:40, shared ten thousand times. With monitoring, a graph turns red at 10:01, an alert pages the on-call engineer at 10:05, and the bad server is out of rotation before most students notice. This chapter builds that second morning.

Monitoring answers three questions, in this order:

  • Is it working for users right now? Not "are the servers up", but "can students see their results, quickly".
  • If not, where is it broken? Which service, which server, which dependency.
  • What changed? A deploy, a traffic spike, a full disk, a slow database.
Observability

You will also hear observability: how well you can work out what is happening inside a system from what it emits. Monitoring tells you that something is wrong; good observability lets you ask new questions about why, without shipping new code.

The first question is the hardest to answer well. Which numbers tell you users are fine?

The four golden signals

If you can watch only four numbers for a service, watch these. Together they catch most of the problems users feel, and the table shows each one on the results site.

SignalQuestionOn the results siteWatch out
LatencyHow long do requests take?p99 time to show a resultTrack percentiles, not averages, and time failed requests separately: fast errors make latency look good
TrafficHow much demand is there?Result lookups per second, by regionA sudden drop is as alarming as a spike; it can mean users cannot reach you
ErrorsHow many requests fail?Share of lookups ending in an error or timeoutCount wrong answers too, such as "result not found" for a valid roll number, sent with status 200
SaturationHow full is the system?Database connection pool 90% used; request queue growingThe fullest resource decides, and trouble starts before it reaches 100%
Latency

QuestionHow long do requests take?

On the results sitep99 time to show a result

Watch outTrack percentiles, not averages, and time failed requests separately: fast errors make latency look good

Traffic

QuestionHow much demand is there?

On the results siteResult lookups per second, by region

Watch outA sudden drop is as alarming as a spike; it can mean users cannot reach you

Errors

QuestionHow many requests fail?

On the results siteShare of lookups ending in an error or timeout

Watch outCount wrong answers too, such as "result not found" for a valid roll number, sent with status 200

Saturation

QuestionHow full is the system?

On the results siteDatabase connection pool 90% used; request queue growing

Watch outThe fullest resource decides, and trouble starts before it reaches 100%

These are the ideas from Availability, Reliability, Scalability and Latency, turned into things you can graph. Saturation is the early warning, because systems usually slow down before they fail.

Two shorter checklists cover the same ground. RED (rate, errors, duration) is for anything that serves requests, such as an API or a queue consumer. USE (utilisation, saturation, errors) is for resources: CPU, disks, network links, connection pools. Apply RED to every service and USE to every machine and pool it depends on.

Percentiles, once more

An average latency of 120 ms can hide that 2 lookups in every 100 take 3 seconds. The p99 shows them at once. You also cannot average percentiles across servers: merge the servers’ latency histograms first, then read the percentile from the merged one.

Part 2 · Metrics, Logs and Traces

Three kinds of telemetry

The golden signals are numbers, but numbers alone cannot say why one student’s lookup failed. Systems emit three kinds of data about themselves, together called telemetry, and each answers a different question.

MetricsLogsTraces
What it isNumbers measured over timeRecords of single events, as text or JSONThe path of one request through many services, with timings
AnswersHow many? How fast? Getting worse?What exactly happened to this request?Where did the time go? Which service failed?
CostCheap: one number per series every few secondsExpensive at volume: one record per eventIn between, because traces are usually sampled
Typical useDashboards and alertsDebugging one specific failureFinding the slow hop in a chain of calls
What it is

MetricsNumbers measured over time

LogsRecords of single events, as text or JSON

TracesThe path of one request through many services, with timings

Answers

MetricsHow many? How fast? Getting worse?

LogsWhat exactly happened to this request?

TracesWhere did the time go? Which service failed?

Cost

MetricsCheap: one number per series every few seconds

LogsExpensive at volume: one record per event

TracesIn between, because traces are usually sampled

Typical use

MetricsDashboards and alerts

LogsDebugging one specific failure

TracesFinding the slow hop in a chain of calls

A good setup uses all three, because each is cheap where the others are expensive. Here is one failed lookup seen three ways:

text
metric  http_requests_total{service="results", status="500"}  1423
log     {"ts":"2026-10-16T10:00:03Z", "level":"error", "request_id":"r-81f2", "msg":"marksheet timeout"}
trace   r-81f2: gateway 3,120 ms > results 3,090 ms > marksheet 3,010 ms > document store 3,000 ms (timeout)

A counter that went up, a log line with details, and a trace showing where the time went.

Watch the labels on metrics

Every unique combination of label values is a separate time series. A region label with 30 values is fine. A roll_number label with 2 million values creates 2 million series and can bring the metrics system down. Keep per-student detail in logs and traces.

Following one request with a trace

The trace line above packs a whole story into one row; this page unpacks it. A results page can involve several calls. A trace records each call as a span: which service, when it started, how long it took, and which span called it. All spans of one request share a trace id, which every service passes along in a request header; the standard header is called traceparent.

You rarely write this by hand. OpenTelemetry, an open standard with SDKs for most languages and a collector, creates the spans, passes the header and also emits metrics and logs, so you can change monitoring vendors without changing your code. The failed lookup’s spans look like this:

SpanCalled byStarts atDuration
API gatewaythe student’s browser0 ms3,120 ms
Results serviceAPI gateway10 ms3,090 ms
Student profileResults service20 ms18 ms
Marksheet serviceResults service45 ms3,010 ms
Document storeMarksheet service50 ms3,000 ms, timed out
API gateway

Called bythe student’s browser

Starts at0 ms

Duration3,120 ms

Results service

Called byAPI gateway

Starts at10 ms

Duration3,090 ms

Student profile

Called byResults service

Starts at20 ms

Duration18 ms

Marksheet service

Called byResults service

Starts at45 ms

Duration3,010 ms

Document store

Called byMarksheet service

Starts at50 ms

Duration3,000 ms, timed out

The trace answers in seconds what logs alone would take an hour to piece together: the document store timed out after 3 seconds, and every span above it was waiting. It even suggests a fix, because a 3-second timeout on a call the student is waiting for is too long.

Tracing every request is expensive, so systems sample: keep perhaps 1% of normal requests, but keep every trace that ended in an error or ran slowly. Deciding after a request finishes is called tail-based sampling; it keeps the interesting traces and drops the dull ones, at the cost of buffering every trace for a few seconds until it ends.

Collecting the numbers: pull or push

Traces and metrics are useless while they sit on thousands of servers; they must travel to one place. Usually a small agent runs on every server, gathering numbers from the machine (CPU, memory, disk) and from the services on it. There are two ways to move them.

Pull (scrape)Push
HowThe monitoring server fetches each target’s /metrics page every 15 to 60 secondsAgents send their numbers to a collector every few seconds
Spotting a dead targetEasy: the scrape failsHarder: silence could mean dead or just idle, so agents send heartbeats
Short-lived jobsCan finish before the next scrapePush their numbers before they exit
Firewalls and private networksThe server must be able to reach every targetOnly outgoing connections are needed
Load controlThe server sets the paceA burst of agents can flood the collector, so it needs buffering or a queue

Both work at scale, and many setups mix them: pull inside one network, push from short jobs and from places the server cannot reach. Whichever you choose, decide how a dead server shows up, because a silent server must never look like a healthy one.

Names you will hear

Pick Prometheus for pull-based metrics and alert rules you run yourself; Grafana for dashboards over several stores; the OpenTelemetry Collector when services push metrics, logs and traces and you want to switch backends freely; Jaeger or Zipkin for traces; Elasticsearch, OpenSearch or Loki for logs; PagerDuty or a similar on-call tool for paging and rotations. A hosted observability service bundles these when you would rather not run them.

Storing time series

Once the numbers arrive, they need a store built for their shape. A time series is a metric name plus a set of labels, holding a list of (timestamp, value) points. Points arrive in time order, are almost never updated, and are read as ranges. Neighbouring points look alike, so they compress very well, often to a couple of bytes a point.

The results site’s fleet shows the scale. 500 servers with 200 series each, sampled every 15 seconds, make 100,000 series and 576 million points a day. At about 2 bytes a point that is roughly 1.2 GB a day, so 15 days of raw points fit in under 20 GB. Part 5 scales the same sum to a whole company.

Raw data is cheap for days, not for years, so older data is kept at lower resolution, a process called downsampling:

AgeResolutionUsed for
Last 15 daysEvery 15 s (raw)Debugging today’s incident
Up to 6 months5-minute summariesComparing with last month
Up to 2 years1-hour summariesComparing with last year’s results day

Each step down cuts the points twentyfold or more, so two years of history costs less than the raw fortnight.

Averages hide spikes

A 5-minute average can flatten a 30-second outage into a small bump. When downsampling, keep the maximum and a latency histogram alongside the average, so spikes and percentiles survive.

Part 3 · Alerts and the People Behind Them

Alert on symptoms, not causes

Stored numbers help only if someone looks at the right moment, and nobody watches graphs all night. An alert is a rule that watches a metric and notifies a person when it crosses a line. The key decision is what to alert on. A symptom is something users feel: errors, slowness, failed lookups. A cause is something that might lead to a symptom: high CPU, one dead server, a disk at 80%.

Each kind gets a different response:

Alert onExample ruleWhy
Symptom: page someoneResult lookup errors above 2% for 5 minutesStudents are hurting now, whatever the cause
Symptom: page someonep99 lookup latency above 1.5 s for 10 minutesSlow pages drive refreshes, which add load
Cause: open a ticketDisk 80% full and filling for 3 daysNeeds action this week, not at 3 am
Cause: dashboard onlyOne server’s CPU at 95%If users are fine, nothing is urgent; if the server stops answering, the health checks from Load Balancers take it out

Symptoms page, causes wait. The reason is arithmetic: a fleet has dozens of causes going slightly wrong every day, and paging on each one buries the page that matters. A symptom alert also catches causes nobody thought to watch, such as the full disk on results morning.

The cost is that a symptom alert fires only once users feel something; canaries and error budgets, later in this part and the next, catch trouble while it is small. First, watch one symptom alert end to end.

From an error spike to a page

Here is a symptom alert end to end on results morning. Agents report error rates, a rule watches the overall rate, and only a sustained spike pages the on-call engineer.

Predict before you watch: the rule pages after three checks above 2%. If one server in three starts failing 18% of its lookups, will it page? What if it were one server in thirty?
  • One in three: yes, the overall rate is about (0.2 + 18 + 0.3) ÷ 3 ≈ 6.2%. One in thirty: no, it rises only to about 0.8%.
Animated sceneFrom an error spike to a page0:26

Every 10 seconds, an agent on each server pushes its error rate to the collector

Read it as steps

Watch for the rule’s badge: a bad hotfix on one server pushes the overall error rate past 2%, and only a sustained spike pages.

The rule needed three bad checks in a row before it paged; real rules usually ask for a few minutes. That short wait filters out one-off blips, so the page that does arrive is worth waking up for. But one bad server in thirty would never have crossed the line at all, which is the problem the next page solves.

Catch bad deploys with a canary

In the scene, a person rolled back the hotfix. Most teams automate that step with a canary: the new version goes to a small slice of servers first, and a deploy tool compares that slice with the rest of the fleet before going wider.

A canary that rolls itself back
  1. 1Deploy to 1 server in 30about 3% of traffic gets the new version; the other 29 servers are the baseline
  2. 2Compare for 10 minutescanary error rate and p99 latency against the baseline, not against a fixed line
  3. 3Canary clearly worsethe tool rolls it back on its own and posts in the team’s channel; nobody is woken
  4. 4Canary as good as the restwiden in stages, such as 10%, 50%, then everyone, comparing again at each step
  5. 5Fleet-wide alerts stay onif something slips through, the symptom alert pages as before

The comparison is the point. One bad server in thirty lifts the fleet’s error rate only from 0.2% to about 0.8%, under the 2% page line, but its own 18% stands out at once against its 29 neighbours. A canary turns a fleet-wide blip into an obvious outlier, while only about 3% of students ever see the bad version.

Roll back first, debug later

When a deploy and a symptom start together, roll back before you investigate. Keep releases small so rollbacks are quick, and keep database changes compatible with the previous version, so a rollback is always safe. Many teams simply freeze deploys on days like results day.

Dashboards and on-call

When a page does arrive, the engineer opens a dashboard. It is read by a tired person looking for a problem, often at 3 am, so it should answer "is this service healthy?" in five seconds. Four habits make that possible:

  • Golden signals at the top: traffic, errors, latency percentiles and saturation, in that order.
  • Dependencies next: the database, cache and services this one calls, with their own errors and latency.
  • Deploys and config changes as markers on every graph. The most common answer to "what changed?" is "we did".
  • Fewer panels. Eight graphs everyone understands beat forty that nobody does.

On-call means carrying a phone that alerts can ring, usually for a week at a time in a rotation across the team. It works only if pages are rare and meaningful. A team that gets dozens of alerts a day starts ignoring them, and the one real alert gets lost. This is alert fatigue, and every page should pass four tests:

Silence is a symptom too

If the agent on a server dies, that server’s error rate does not go up; it disappears. Add rules that fire when expected data stops arriving. After any real incident, write a blameless postmortem: what happened, how it was found, why it spread, and what will stop it happening again.

Part 4 · Seeing What Users See

What the server cannot see

Everything so far measures requests that reach your servers. Many failures happen before that: the page’s script crashes on one phone model, DNS fails in one city, a certificate expires, or a CDN edge misbehaves. Your servers see nothing, so their graphs look perfect while students suffer. Four tools together cover the whole path:

ToolHow it worksCatches
Server-side metricsMeasure every request your servers handleErrors and slowness inside your system
Client reporting (real-user monitoring)The page or app sends crashes, script errors and timings to a collection endpoint, sampledA release broken on one phone model, slow pages on weak mobile networks
Synthetic checksRobots in several cities run key flows every minute: open the site, enter a test roll number, see a resultDNS, TLS and CDN failures, and outages in quiet hours when real traffic is low
Traffic-drop alertsCompare traffic with the same minute last weekUsers who cannot reach you at all

The last row is subtle. If students in one region cannot connect, your error rate does not rise; your traffic falls. A drop of 30% against the same minute last week is often the first sign of a problem outside your servers, such as the resolver outages from DNS: How a Name Becomes an Address or a misbehaving edge from Content Delivery Networks. On results day, compare with last year’s results day, not last week.

Test the whole path

A synthetic check that only calls /health on one server proves very little. Send it through DNS, the CDN and the load balancer, and have it complete a real user action.

SLIs, SLOs and error budgets

Seeing what users see raises the next question: how good is good enough? "As reliable as possible" is not a useful target, because every extra nine costs more and slows feature work. Teams agree on numbers instead, using four terms:

TermMeaningExample
SLI (service level indicator)A measured ratio of good events to all eventsShare of result lookups that succeed within 1 s
SLO (service level objective)The target for an SLI over a time window99.9% of lookups succeed within 1 s, over 30 days
Error budgetHow much the SLO allows to fail0.1%: with 10 million lookups a month, 10,000 may fail
SLA (service level agreement)A contract with customers, with penaltiesSet looser than the SLO, so you miss the SLO well before the SLA

The error budget turns reliability into a shared decision. While budget remains, the team ships features and takes risks. When a bad month uses it up, risky launches pause and the team works on reliability until it recovers.

In time terms, 99.9% over 30 days allows about 43 minutes of complete outage: 0.1% of the month’s 43,200 minutes. But a budget counts requests, not minutes. If most of the month’s lookups arrive on results morning, ten minutes of failures that morning can spend more budget than a quiet week of trouble. That is why the budget, not a clock, is what alerts should watch, as the next page shows.

Alerting on the error budget

A fixed line like "errors above 2%" ignores how much budget is left. A burn rate alert asks a better question: how fast are we spending the budget? Burn rate is the current error rate divided by the rate the SLO allows. With a 0.1% budget, 0.1% errors is a burn rate of 1, which uses exactly the whole budget in 30 days, or 720 hours. An error rate of 1.44% is a burn rate of 14.4.

Multiply burn rate by time to get the share of the budget spent. The table shows the usual tiers:

Burn rateSustained forBudget spentAction
14.4 (1.44% errors)1 hour14.4 ÷ 720 = 2%Page
6 (0.6% errors)6 hours36 ÷ 720 = 5%Page
2 (0.2% errors)1 day48 ÷ 720 ≈ 7%Ticket
14.4 (1.44% errors)

Sustained for1 hour

Budget spent14.4 ÷ 720 = 2%

ActionPage

6 (0.6% errors)

Sustained for6 hours

Budget spent36 ÷ 720 = 5%

ActionPage

2 (0.2% errors)

Sustained for1 day

Budget spent48 ÷ 720 ≈ 7%

ActionTicket

Fast burns page because the budget will be gone in days; slow burns open a ticket because there is time to fix them in working hours.

One window alone misbehaves. A 1-hour window is slow to notice a sudden outage and keeps firing for up to an hour after it ends. So each tier also checks a short confirming window, about one twelfth as long: page only when the burn rate exceeds 14.4 over both the last hour and the last 5 minutes. A real outage trips both quickly, and once errors stop, the 5-minute window drops at once, so the page clears in minutes instead of an hour.

Part 5 · Designing a Metrics System

A metrics system for a whole company

The results site is one of hundreds of services a large company runs, and all of them send metrics to one shared system. Designing that system tests everything in this chapter: the writes never stop, the volume is huge, and it must keep working while everything it watches is failing. It needs four things:

  • Ingest metrics from every host and service at 10-second resolution, without ever blocking the senders.
  • Answer dashboard queries over the last hour in about a second.
  • Fire alerts within a minute and reach the right team once.
  • Keep raw points for 15 days and summaries for a year or more.

The estimate that decides the shape assumes 100,000 hosts, each exposing 1,000 series, sampled every 10 seconds.

Animated sceneIngest for a company-wide metrics system0:16

Stored per day: ≈ 1.7 TB (15 days of raw points ≈ 26 TB before replicas)

Read it as steps

Watch for the number that decides the design: points per second, not bytes.

Ten million writes a second is the hard part, not the bytes. 1.7 TB a day compressed is modest, but 10 million inserts a second and 100 million active series are far more than one storage node can hold. So the design needs a sharded write path with a buffer in front, which the next page lays out.

The write path and the read path

The estimate says to shard the writes and protect the stores from bursts. Points flow through six stages:

The write path, then the read and alert paths
  1. 1Agents on every hostscrape local services every 10 s, batch and compress, then push; buffer on local disk if the next tier is slow
  2. 2Stateless ingestersbehind a load balancer: check the tenant’s limits, then append to the log; add more as traffic grows
  3. 3A durable log, partitioned by series hashabsorbs bursts and slow storage; each series always lands in the same partition, in order
  4. 4Time-series shardseach reads its partitions, keeps recent hours in memory, and writes compressed blocks to disk, then to object storage
  5. 5Query layerfans each query out to the shards that hold matching series and merges the partial results
  6. 6Rule evaluators and alert routerrun recording and alert rules every 30 to 60 s; the router deduplicates, groups and routes notifications

Sizing follows from the estimate. If one storage shard comfortably takes about 500,000 points a second, 10 million needs 20 shards, or 40 to 60 nodes with two or three replicas each.

The log carries points before storage compression. Assume about 20 bytes a point on the wire: an 8-byte value, a timestamp sent as a small delta and a short series reference, with full labels sent once per batch, not per point. That is 200 MB a second, or 20 partitions at about 10 MB a second each, so plan 30 to 40 for headroom.

Why a log in front, instead of writing straight to the shards? A shard that pauses to compact or restart would otherwise push back on 100,000 agents at once. With the log, the shard falls a few seconds behind and catches up, and no agent ever blocks.

Inside the metrics system

The boxes are simple; the hard parts are inside them, and the table names each one.

Hard partWhat you doWhy
CardinalityCount active series per tenant at the ingesters; reject new series past a limit, such as 1 million, with a clear errorOne roll_number label can add millions of series and slow a shard for everyone
CompressionStore timestamps as differences of differences and values as XOR with the previous value, in immutable 2-hour blocksAbout 1–2 bytes a point instead of 16, and old blocks move to cheap object storage
Recording rulesEvery minute, pre-compute common aggregates, such as errors per service, and store them as small new seriesDashboards and alerts read thousands of series instead of millions
Query fan-outSend each query only to shards with matching series; cap the series and time range per queryOne heavy dashboard cannot starve everyone else
DownsamplingA background compactor rewrites old blocks at 5-minute and 1-hour resolution, keeping min, max, sum, count and histogramsYears of history stay cheap, and spikes survive
Alert routingDeduplicate (two rule replicas fire once), group (200 hosts, one page), route by team and severity, allow silencesOne problem wakes one person, once
Monitoring the monitoringA small, separate watcher in another region checks the pipeline end to end, plus a dead man’s switch: an alert that always fires, so its silence pages someoneIf the metrics system is down, every other alert is silent too

Which row matters most depends on the pressure. For cost, it is cardinality limits, downsampling and object storage at about $0.02 per GB-month (check current prices). For reliability, it is the log as a buffer, replicated shards and the separate watcher. For speed, it is recording rules and query fan-out.

Part 6 · Review

In the interview

Monitoring closes almost every design, and "design a metrics system" is also asked on its own; these lines carry the chapter into either.

Say
"Each service exports the four golden signals, and I page on symptoms, such as lookup errors above 2% for 5 minutes, not on CPU."
Say
"The SLO is 99.9% within 1 s over 30 days; I page when the budget burns 14.4 times too fast for an hour, which spends 2%."
Say
"Ten million points a second is a write problem, not a storage one: about 1.7 TB a day compressed. I shard by series hash behind a durable log."
Avoid
Paging on every cause: high CPU, one dead server, a busy disk. Dozens of pages a day teach the team to ignore the one that matters.
Avoid
One ordinary database table with a row per point. At 10 million inserts a second, that table becomes the outage.

Wrap-up

TermMeaning
Golden signalsLatency, traffic, errors and saturation: the four numbers to watch first
Span, trace idOne timed call in a request; the id that ties all of its spans together
CardinalityHow many distinct series a metric’s label values create
DownsamplingKeeping old data at a coarser resolution, such as 5-minute summaries
Symptom alertA page on something users feel, such as errors or slowness
CanaryA new version on a small slice of servers, compared with the rest
SLO, error budgetA reliability target, and the failures it allows before launches slow down
Burn rateError rate divided by the budget rate; 1 spends the budget in exactly 30 days

Next: Distributed Caches. Many of the alerts in this chapter, slow pages and a database at full CPU, trace back to a cache that missed, expired or died.

Part 7 · Check yourself

Quick check

Q1Why does a canary compare its error rate with the rest of the fleet instead of relying on the fleet-wide alert?

Think it through, then check.

Q2At 10:05 am on results day the dashboard shows traffic, errors (0.1%) and p50 (80 ms) flat, p99 up from 300 ms to 2.5 s, and the database connection pool at 100%. What is happening, and what next?

Think it through, then check.

Q3The SLO is 99.9% of lookups succeeding over 30 days. An incident fails 5% of lookups for 2 hours. How much of the month’s error budget did it spend?

Think it through, then check.

Q4The board wants latency per student, for 2 million students. Add a roll_number label to the latency histogram, or something else? What does each cost?

Think it through, then check.

Q5From Load Balancers: every health check is green, yet 5% of result lookups fail. How can both be true, and what would catch it?

Think it through, then check.

Next chapter · 13 of 39Distributed Caches~33 min · 3 animated scenes