CDN Reliability Metrics: What to Measure and How to Set Meaningful Targets

Back in 2019 I watched a major retail launch stall even though our status page showed 99.95% availability. Checkout API calls from half of Europe were timing out, but our edge health checks were all green. That night cost the client a fortune and taught me that what you choose to measure determines what you actually fix. If you're running a CDN without clear reliability metrics, you're flying blind until users tell you something's broken.

Why "Four Nines" Misleads You About Real Availability

When I started in CDN operations, we treated availability as a single percentage on a dashboard. If we hit 99.99%, we celebrated. The problem is that a single number hides where and how failures happen. A point of presence can be reachable via ICMP while failing to serve 15% of requests due to cache overload or TLS handshake errors. I’ve seen teams hit their availability target for the month while still dropping a painful number of user requests because they measured the wrong thing. Your SRE Practices for CDN: Applying Site Reliability Engineering to Content Delivery approach has to start by defining what a successful request actually means.

For CDN measurement, I now separate machine availability from service availability. Machine availability is whether the edge node responds to a probe. Service availability is whether a valid user request gets a correct, timely response. That means you count every HTTP response from the edge, not just whether the server is up. You also need to decide what counts as success. Is a 429 due to your own rate limiting a success? Is a 502 from origin that you correctly passed through a failure of the CDN? These decisions change your numbers dramatically, so document them with your team before you set any target.

We learned to combine synthetic checks with real user monitoring (RUM) to avoid blind spots. Synthetics tell you if a PoP is reachable from known vantage points, but RUM tells you what actual users experienced, including last-mile issues you can’t see from inside your network. The HTTP Working Group Specifications (https://httpwg.org/specs/) are helpful here for understanding how status codes, caching, and retries should be interpreted when you classify success and failure. Don’t just count 2xx as good and everything else as bad — be intentional about it.

# SLI for CDN service availability - successful requests over total valid requests
# Counts 2xx and 3xx as success, excludes client-aborted requests
sum(rate(cdn_edge_requests_total{status=~"2..|3.."}[5m]))
/
sum(rate(cdn_edge_requests_total{status!~"4..abort"}[5m]))

# Alert if availability drops below SLO over 30-minute window
- alert: CDN_Availability_BurnRate
  expr: |
    (
      1 - (
        sum(rate(cdn_edge_requests_total{status=~"2..|3.."}[30m]))
        /
        sum(rate(cdn_edge_requests_total[30m]))
      )
    ) > (1 - 0.999) * 14.4
  for: 5m
  labels:
    severity: critical

Measuring What Users Feel: Latency, Hit Ratio, and Error Quality

Availability alone won’t tell you if your CDN is reliable. I once worked with a video platform that never breached its availability SLO, yet support tickets kept climbing. When we dug in, p95 Time to First Byte (TTFB) from Southeast Asia had crept from 120ms to 850ms after a routing change. The service was “up,” but it felt broken. That’s why your reliability KPIs need latency and quality signals alongside availability. For CDNs, TTFB at the edge, cache hit ratio, and origin offload health are often more telling than a simple up/down check.

Don’t average latency. An average hides outliers that matter most to users. I track p50 for the typical experience, p95 for the degraded experience you’re willing to tolerate, and p99 for the tail you need to understand but may not burn error budget on. You should measure these from the client side where possible, not just from the edge node’s logs. Articles on web.dev (https://web.dev/articles/) do a good job explaining how metrics like TTFB and LCP relate to perceived performance, which helps you connect edge latency to real user impact. If your p95 TTFB degrades by 300ms, users notice even if your dashboards don’t turn red.

Cache hit ratio and error classification complete the picture. A sudden drop in hit ratio from 92% to 78% might not trigger an availability alert, but it will hammer your origin and cascade into 5xx errors minutes later. Similarly, not all errors are equal. I classify errors as edge-generated (like cache write failures), origin-generated (like 502s you cache for a short time), and client-generated. You’ll set very different meaningful targets for each. We use this structure to define SLOs that tie directly to user experience, and you can formalize how you balance those targets against shipping speed with a clear CDN Error Budget Management: Balancing Reliability with Feature Velocity policy.

# slo.yaml - Example CDN SLO definitions tied to user experience
apiVersion: openslo/v1
kind: SLO
metadata:
  name: cdn-latency-p95
  displayName: "Edge TTFB p95"
spec:
  description: "95% of cache HIT requests served within 150ms TTFB"
  service: cdn-edge
  indicator:
    metadata:
      name: ttfb-hit-latency
    spec:
      ratioMetric:
        good:
          metricSource:
            metric: cdn_request_duration_seconds
            filter: 'cache_status="HIT" and ttfb <= 0.15'
        total:
          metricSource:
            metric: cdn_request_duration_seconds
            filter: 'cache_status="HIT"'
  objectives:
    - displayName: "p95 TTFB < 150ms"
      target: 0.95
      op: gte
      timeWindows:
        - duration: 28d
          isRolling: true
      budgetingMethod: Occurrences

From Vanity Numbers to Targets Your Team Can Actually Keep

Setting targets is where most teams get stuck. It’s tempting to copy a “four nines” target because it sounds impressive, but a target you can’t measure consistently or can’t act on is just theater. I’ve found the best approach is to start with what users will tolerate, then work backward to what you can reliably deliver and measure. If your product is a static asset CDN for marketing sites, a 200ms p95 TTFB target might be fine. If you’re delivering authenticated API responses for checkout, you’ll need something tighter and you’ll need to budget for origin variability.

Good targets are also tied to consequences. If you hit your target, you ship features. If you burn your error budget, you stop and focus on reliability. Without that link, no one changes behavior. We review our SLOs quarterly and adjust based on burn rate patterns, not gut feelings. And we automate the boring parts — collection, aggregation, and burn-rate alerting — so engineers don’t spend their weeks updating spreadsheets. That’s the core idea behind CDN Toil Reduction Through Automation: Eliminating Repetitive Operations Work; if measuring reliability feels like toil, people will stop doing it.

Here’s the set of reliability metrics I recommend as a baseline for intermediate teams. You don’t need all of them on day one, but you should be able to explain why you picked the ones you did. Start with these, get your measurement pipeline solid, then add more as your CDN measurement matures.

Metric (Reliability KPI) How to Measure It Example Meaningful Target
Service Availability (Valid Requests) Successful (2xx + 3xx) / total valid requests from RUM + edge logs; exclude client-aborted 99.9% over 28-day rolling window
Edge TTFB p95 (Cache HIT) RUM TTFB for cache HIT at edge, p95 percentile per region p95 < 150ms globally, < 100ms in primary markets
Cache Hit Ratio HIT requests / (HIT + MISS) for cacheable content, per content type > 90% for static assets, > 65% for API-accelerated
Origin Error Rate Passed to Users 5xx responses generated by origin that reached client / total requests < 0.1% over 5-minute window; alert on 10x burn rate
Error Budget Burn Rate Rate of SLO violation vs. budget remaining; calculated from above SLIs Block releases if 28-day budget < 25% remaining

From SLO to Signal: Implementing Measurement That Actually Works

You've got targets on paper — now you've got to prove you're hitting them without burning out your on-call rotation. We've seen teams deploy beautiful SLO dashboards that nobody looks at until a customer complains. The gap's usually instrumentation. If you're measuring availability at the origin or relying solely on synthetic checks from three US PoPs, you're not measuring what users feel. You need Real User Monitoring (RUM) at the edge, plus synthetic probes in every region you claim to serve. We typically instrument at three layers: client-side Navigation Timing for TTFB and LCP, edge logs for cache status and response codes, and mid-tier origin logs to isolate shield vs. edge misses.

Once you've got the data, don't alert on raw thresholds. Alerting that "p95 latency > 200ms for 1 minute" will page you every time there's a brief PoP congestion event in Jakarta that self-heals in 90 seconds. Instead, use multi-window burn rate alerting. We run 5-minute and 30-minute windows against our 28-day error budget. A fast burn (say, 10x over 5 minutes) pages immediately; a slow burn (2x over 30-60 minutes) creates a ticket for business hours. That alone cut our non-actionable pages by about 68% when we rolled it out across a 250-PoP footprint last year. And please, wire those alerts directly into executable runbooks — if your alert just links to a wiki page, you've already lost two minutes of MTTR. Our approach is detailed in CDN Runbook Automation: Converting Manual Procedures into Executable Scripts, and it’s the difference between scrambling and clicking "remediate."

Here's the Prometheus-style SLO burn alert we've standardized on for our edge 5xx ratio. It's tuned for a 99.9% availability target (which gives you just 43.2 minutes of error budget per month — tighter than it sounds):

# SLO: 99.9% of requests should be non-5xx over 28 days
# Error budget burn rate alerting - 5m fast burn, 30m slow burn
groups:
- name: cdn-slo-burn
  rules:
  - alert: CDNHighErrorBudgetBurn_Fast
    expr: |
      (
        sum(rate(cdn_edge_requests_total{status=~"5.."}[5m]))
        /
        sum(rate(cdn_edge_requests_total[5m]))
      ) > 0.01  # 10x burn rate (0.1% budget * 10)
    for: 2m
    labels:
      severity: critical
      burn: "fast"
    annotations:
      summary: "Fast burn: {{ $value | humanizePercentage }} error rate"

  - alert: CDNHighErrorBudgetBurn_Slow
    expr: |
      (
        sum(rate(cdn_edge_requests_total{status=~"5.."}[30m]))
        /
        sum(rate(cdn_edge_requests_total[30m]))
      ) > 0.002  # 2x burn rate
    for: 15m
    labels:
      severity: warning
      burn: "slow"
# Pair this with a `slo:burn:ratio` recording rule for dashboarding

When Your Numbers Look Fine But Users Are Hurting

The nastiest CDN failures don't show up as global error rates. They show up as regional drift and partial degradation. We've debugged incidents where our global hit ratio held steady at 94.7%, but Singapore and Mumbai were sitting at 61% for six hours because a shield PoP had a stale parent selection after a config push. Users saw 800-1100ms TTFB instead of our 75ms p50 target, but our aggregate dashboard was green. You have to slice your SLOs by PoP, by cache tier, and by content class. We now track hit ratio, p95 TTFB, and 5xx rate per continent and per asset type (video segment vs. API vs. static image) — you'll catch cache poisoning and origin shield overloads weeks earlier that way.

Another pattern that'll bite you is correlated failure after an automation. You push a "harmless" cache-key normalization rule, it passes canary on 5 PoPs, then your config orchestrator rolls it to 100% in 90 seconds. Suddenly your origin sees a 400% spike as every edge revalidates at once — classic thundering herd, and your origin's autoscaler can't keep up for 4-5 minutes. That's why we enforce progressive delivery with automatic rollback on SLO burn, not just on synthetic health checks. If you're automating purging, routing, or config distribution without circuit breakers, you're trading human error for faster, bigger machine error. We cover this failure mode extensively in The CDN Automation Reliability Paradox: When Automation Causes More Outages.

When you do get bit, don't just fix the symptom and bump the error budget. A good postmortem asks: did our SLI hide the problem, or did we measure the wrong thing entirely? For that Singapore shield incident, our action item wasn't just "fix parent selection" — it was "add a shield miss ratio SLI with a 92% target and stop averaging hit ratio globally." Every incident should leave you with a better metric, not just a better runbook. If your postmortems still end with "human error, will be more careful next time," you're missing the point — check our framework in CDN Postmortem Analysis: Learning from Incidents to Prevent Recurrence for turning incidents into durable reliability gains.

Frequently Asked Questions

What's a realistic availability target for a multi-CDN setup?

Don't chase 99.99% on a single provider unless you've got the contract and architecture to back it up. For most teams, 99.95% measured at the eyeball (RUM, not provider status page) over 28 days is ambitious but achievable. If you're running active-active multi-CDN with automated failover in under 45 seconds, you can credibly target 99.99% for static assets — but keep your dynamic/API targets at 99.9% to 99.95%. Anything higher without real failover testing every two weeks is just marketing.

Should we use hit ratio as an SLO?

Use it as an SLI, but be careful making it a formal SLO with error-budget consequences. Hit ratio is a means, not an end — users care about latency and errors. We've seen teams hit 98% hit ratio by over-caching stale content and serving 10-minute-old API responses. Track hit ratio per content class (aim for >92% for immutable images, >85% for API with 30s TTL) and alert if it drops 8-10 points from baseline for 10 minutes, but tie your burn-based paging to latency and availability.

How do we avoid alert fatigue with latency SLOs?

Never alert on instantaneous p95 or p99 — they're too spiky. Use windowed percentiles and burn rates. We alert on p95 TTFB averaged over 5 minutes exceeding 180ms for static and 350ms for dynamic, but only if the 60-minute burn is also elevated. Also, filter out your top 1% of outliers from bot traffic and single bad ISPs; we exclude any ASN that contributes less than 0.5% of traffic from SLO calculations to keep one flaky eyeball network from torching our budget.

How often should we review and adjust our CDN SLOs?

Quarterly is the sweet spot. Monthly is too noisy — you'll chase variance. Annually is too slow — your traffic mix will have changed. At each review, look at the last 90 days: if you've burned less than 25% of your error budget, your target's probably too loose and you're leaving performance on the table. If you're burning 80%+ consistently or paging more than 2-3 times per quarter on SLOs, your target's too tight or your instrumentation's wrong. Adjust by no more than 0.05% availability or 15ms latency per quarter.

Related Articles

References & Standards: HTTP Working Group Specifications · web.dev Articles · IETF Datatracker