CDN Architecture & Performance

Edge congestion is inevitable. A flash sale, a viral video, or a bot scrape can push a PoP's egress to 95%+ in seconds. Without Quality of Service (QoS), the CDN serves requests first-come, first-served. The result: critical HTML and API calls queue behind 4K images and non-essential prefetch, spiking Largest Contentful Paint (LCP) and killing conversion.

CDN traffic shaping solves this by classifying, queuing, and scheduling traffic at the edge — before it hits the congested link or origin. Unlike traditional network QoS that operates at L3/L4, CDN QoS is application-aware. It understands content type, business priority, and user context, allowing you to reserve bandwidth for revenue-critical flows while gracefully degrading the rest.

Key principle: Shape at the edge, not at the origin. By the time traffic reaches your origin, latency is already lost. Edge shaping enforces policy within 10-30ms of the user, where it has maximum impact on perceived performance.

Why QoS at the Edge Is Different

Traditional WAN QoS uses DSCP markings and strict priority queuing on routers. CDN edge QoS builds on that foundation but adds three unique capabilities:

Without this, you rely on TCP fairness — which is fair, but not smart. TCP gives each connection an equal share. QoS gives each connection the share it deserves.

The 4-Tier Classification Framework

Most high-performing CDN deployments converge on a four-tier model. Keep it simple; more than five tiers becomes unmanageable to tune.

Performance Comparison: Edge vs Origin Processing
Metric Edge Processing Origin Processing Improvement
Latency (p50)8–15 ms120–300 ms15–20x faster
Cache Hit Ratio85–95%N/AReduces origin load
TLS Handshake1–5 ms (nearby PoP)50–150 ms10–30x faster
Bandwidth Cost$0.01–0.04/GB$0.05–0.12/GB3–5x cheaper
Availability99.99% (multi-PoP)99.9% (single DC)10x fewer outages
Priority Class & Examples Target SLA Shaping Behavior
P0 — Critical Blocking & Transactional: HTML document, critical CSS/JS, /api/* checkout, auth, personalization P95 TTFB < 80ms, 0% drops Strict priority, 40% reserved BW, no policing
P1 — Important Above-the-fold: Hero images, web fonts, LCP elements, product JSON P95 < 150ms Weighted Fair Queuing (WFQ) weight 30, burst allowed
P2 — Best Effort Deferred: Below-the-fold images, async JS, analytics, A/B scripts P95 < 400ms WFQ weight 20, WRED early drop at 70% queue
P3 — Background Non-essential: Prefetch, prerender, video autoplay, bot/crawler, stale revalidation Best effort Scavenger, capped at 10% BW, policed & delayed

Classification happens in the edge worker or VCL layer. Evaluate in order: first match wins. Place P0 rules at the top to avoid misclassification. For a deeper look at how requests reach the right PoP before classification, see our guide to load balancing algorithms.

Core Shaping Mechanisms at the Edge

Three algorithms do 90% of the work. You will configure them together, not in isolation.

1. Token Bucket for Rate Smoothing

The token bucket is the workhorse for egress shaping. Tokens are added at a fixed rate (your committed rate), and each byte sent consumes a token. Bursts are allowed up to the bucket depth, which absorbs micro-bursts without dropping. This is ideal for P1/P2 traffic where you want to smooth delivery without hard drops.

Configuration is two parameters: rate (tokens/sec) and burst (bucket size). Set burst to ~1.5x your rate for image-heavy pages to allow initial burst for above-the-fold assets.

2. Leaky Bucket for Strict Policing

Use the leaky bucket for P3 scavenger traffic. It enforces a hard ceiling: traffic that exceeds the leak rate is queued or dropped. Apply it to prefetch and bot traffic to prevent them from stealing bandwidth during peak. Unlike token bucket, it does not reward idle periods with burst credit.

3. Weighted Random Early Detection (WRED)

WRED prevents queue collapse. Instead of tail-dropping when a queue is full (which causes global TCP synchronization), WRED probabilistically drops low-priority packets as the queue fills. Configure lower thresholds for P2/P3. For example, start dropping P3 at 50% queue depth, P2 at 70%, but never drop P0 until 95%. This keeps latency low for critical flows even when the edge is saturated.

Prioritization in Practice

Effective prioritization is not just about marking traffic; it is about scheduling discipline and cache interaction.

Strict priority for P0, WFQ for the rest. Give P0 a strict priority queue with a small burst buffer (50-100ms). This guarantees HTML and API calls are always dequeued first. For P1-P3, use Weighted Fair Queuing. WFQ prevents starvation: even under heavy P1 load, P2 still gets its 20% share, so below-the-fold content eventually loads instead of timing out.

Cache status matters. A P1 image that is a cache HIT should be P0-like in scheduling — it costs nothing to serve. A P1 MISS that requires an origin fetch should be demoted to P2 until it is cached. This dynamic re-prioritization avoids origin thundering herds. Pair this with smart cache invalidation so critical assets stay hot and avoid unnecessary MISS demotion.

Align with browser priorities. Modern browsers send Priority Hints and HTTP/3 urgency signals (RFC 9218). Map u=0, i (highest urgency, incremental) to P0 and u=7 to P3. When the edge respects the same urgency the browser declares, you get end-to-end prioritization without custom logic. This is especially powerful when combined with edge computing where Workers can rewrite priorities per user segment.

Implementing Edge QoS: Code Examples

Most CDNs expose QoS via VCL, edge workers, or control-plane rules. Below are two portable patterns.

Example 1 — Cloudflare / Fastly VCL-style classification & header marking
sub vcl_recv {
  # P0: Critical - never shape
  if (req.url ~ "^/api/(cart|checkout|auth)" || req.url ~ "^/critical-css") {
    set req.http.X-QoS-Priority = "P0";
    set req.http.X-QoS-Weight = "40";
  }
  # P1: LCP elements
  elsif (req.url ~ "\.(woff2|css)$" || req.http.X-LCP-Hint == "hero") {
    set req.http.X-QoS-Priority = "P1";
    set req.http.X-QoS-Weight = "30";
  }
  # P3: Background - police aggressively
  elsif (req.http.Purpose == "prefetch" || req.url ~ "prefetch" || req.http.X-Bot == "1") {
    set req.http.X-QoS-Priority = "P3";
    # Leaky bucket: 1 Mbps, no burst
    call qos_leaky_bucket(rate=125000, burst=0);
  }
  else {
    set req.http.X-QoS-Priority = "P2";
  }
}

sub vcl_deliver {
  # Map to HTTP/3 priority for client
  if (req.http.X-QoS-Priority == "P0") {
    set resp.http.Priority = "u=0, i";
  } elsif (req.http.X-QoS-Priority == "P3") {
    set resp.http.Priority = "u=7";
  }
}
Example 2 — Edge Worker (JavaScript) token bucket for P2 image traffic
export default {
  async fetch(req, env, ctx) {
    const url = new URL(req.url);
    const isImage = /\.(avif|webp|jpg)$/.test(url.pathname);

    // Only shape cache MISS images to protect origin
    if (isImage && req.headers.get("x-cache-status") !== "HIT") {
      const bucket = env.QOS_BUCKET.get("p2-images", {
        // Token bucket: 20 Mbps sustained, 30 Mbit burst
        rate: 20_000_000 / 8, burst: 30_000_000 / 8
      });
      const { allowed, retryAfter } = await bucket.consume(req.headers.get("content-length") || 0);
      if (!allowed) {
        // Return stale or 429 with Retry-After for P2, never for P0
        return new Response(null, {
          status: 429,
          headers: { "Retry-After": String(retryAfter), "X-QoS": "P2-throttled" }
        });
      }
    }
    return fetch(req);
  }
}

Key detail: never return 429 for P0. For P0, queue and pace. For P3, 429 or serving stale is acceptable. For a full system view of where these workers run, refer to our CDN architecture overview.

Monitoring, Tuning, and Avoiding Starvation

QoS without observability is just hopeful queuing. Instrument per-class counters at each PoP:

Tune weights quarterly. Start with 40/30/20/10 and adjust based on real traffic mix. If your site is image-heavy, shift 5% from P2 to P1. If you heavily prefetch, increase P3 policing. Always test with synthetic burst: replay a 5x traffic spike in staging and verify P0 remains flat while P3 degrades gracefully.

Common pitfall: misclassifying everything as P0. If 70% of traffic is P0, you have no QoS. Be ruthless — only blocking, transactional traffic is P0. Everything else must earn its priority.

When done right, edge QoS is invisible to users but obvious in metrics: stable LCP during peaks, fewer origin 503s, and a 20-40% reduction in P95 latency for critical flows. It turns the edge from a dumb cache into an intelligent scheduler — one that knows what to protect when the network gets tough.

Frequently Asked Questions

What is the difference between traffic shaping and policing at the CDN edge?

Policing drops or re-marks traffic that exceeds a rate limit immediately, causing retransmissions and poor user experience. Shaping buffers excess traffic in queues and smooths bursts over time using token bucket or leaky bucket algorithms, delivering more consistent throughput without packet loss. At the edge, shaping is preferred for user-facing content.

How does QoS improve Core Web Vitals and LCP?

QoS ensures render-blocking resources like HTML, critical CSS, and hero images are classified as P0 and served from high-priority queues with reserved bandwidth. By deprioritizing low-value traffic like prefetch, analytics beacons, and background video, the edge reduces contention and delivers Largest Contentful Paint elements 30–50% faster under load.

Can QoS be applied with HTTP/3 and QUIC?

Yes. While QUIC encrypts transport headers, CDNs classify at the application layer using URL patterns, content-type, and custom headers before encryption. HTTP/3 stream prioritization via the Extensible Prioritization scheme (RFC 9218) then maps directly to edge QoS queues, allowing urgency levels to align with CDN shaping policies.

What metrics should I monitor for edge QoS effectiveness?

Track per-class metrics: P0 queue latency and drop rate, P50/P95 time-to-first-byte by priority, cache hit ratio by class, origin offload for critical assets, and token bucket utilization. Alert when P0 queue depth exceeds 20% or when low-priority traffic starves due to incorrect weight allocation.

References & Standards: Cloudflare documentation · W3C Web Performance