CDN Throughput vs Bandwidth: Understanding the Difference and Why It Matters

Last year a customer filed a pretty heated ticket saying our CDN was capping them at 200 Mbps. They'd just upgraded to a 10 Gbps dedicated link and couldn't understand why a 1GB video file was still taking over 40 seconds to pull from the edge. I've had that exact conversation a dozen times in the last ten years, and it always starts with the same confusion between throughput vs bandwidth. They sound interchangeable, but mixing them up is why a lot of teams overpay for network capacity they never actually use.

Bandwidth Is Your Highway's Size, Not Its Speed

Think of bandwidth as the width of the highway between your origin and the user. It's the maximum data transfer rate your link, your carrier, and your CDN edge can theoretically handle if everything is perfect. When a provider sells you a 10 Gbps port, they're selling you network capacity — the number of lanes — not a guarantee you'll fill those lanes every second. That capacity is fixed by physics and by the hardware in the path: fiber, NICs, switches, and the peering agreements in between.

I learned this the hard way early in my career. We provisioned a new PoP in Frankfurt with 2x100G uplinks and assumed our CDN speed would instantly double. It didn't. Our synthetic tests still showed modest performance for users in southern Italy because the bottleneck wasn't our edge at all. The bandwidth was there, but no single user could use it all. Bandwidth tells you the ceiling; it doesn't tell you how fast one car — or one TCP connection — can actually go. If you want to understand how that ceiling interacts with latency, the Bandwidth-Delay Product and CDN Tuning: Filling the Pipe Without Overwhelming It is where that math really clicks.

For me, the cleanest way to keep it straight is to calculate the ideal case and then remind yourself you'll never hit it. Here's the kind of back-of-the-napkin check I still run when someone quotes a link speed:

# Ideal transfer time if you could actually use all available bandwidth
# No TCP overhead, no loss, no congestion - just pure network capacity

file_size_mb = 1024  # 1 GB file
bandwidth_gbps = 10  # Advertised link speed
bandwidth_mbs = (bandwidth_gbps * 1000) / 8  # Convert to MB/s

ideal_time = file_size_mb / bandwidth_mbs
print(f"Ideal time on 10 Gbps: {ideal_time:.2f}s")
# Output: Ideal time on 10 Gbps: 0.82s

# In reality, you'll see 40-60s for a single connection over the public internet.
# Why? Because throughput is not bandwidth.

Throughput Is What You Actually Measure on the Wire

If bandwidth is the highway's size, throughput is the actual traffic flow you measure during rush hour. It's the real data transfer rate delivered to the browser or video player over a given period, and it's almost always lower than the bandwidth. Throughput is affected by everything bandwidth ignores: round-trip time, packet loss, congestion, TCP settings, and how many people are sharing that highway at the same time.

We see this constantly on the CDN side. A user in New York hitting a Newark PoP with 20ms RTT might easily get 800 Mbps on a 1 Gbps access line. That same user pulling from London at 90ms RTT on the exact same 1 Gbps line might get 120 Mbps for a single connection. Nothing changed about the network capacity, but the throughput collapsed. One of the biggest culprits I've debugged is an undersized TCP window — the sender literally isn't allowed to have enough data in flight to fill the pipe. If you're seeing that pattern, read up on TCP Window Scaling and Its Impact on CDN Throughput: Why Defaults Fall Short before you buy more bandwidth.

The rule that governs this is simple: Throughput <= TCP Window / RTT. You can't cheat it. I also obsess over how we measure RTT itself, because a bad measurement will make your throughput estimates useless. We had a stretch where our probes were queuing behind bulk traffic and artificially inflating RTT, which made everything look like a congestion issue. Fixing our RTT Measurement Methodology for CDN: Getting Accurate Round-Trip Times cut our false alerts in half. As the HTTP Working Group Specifications and web.dev Articles both emphasize, modern HTTP performance is end-to-end — you have to measure what the client actually experiences, not what the switch port says.

# Real-world throughput check from an edge server (what we run daily)
# 1. Single connection test - this is your effective CDN speed for one user

curl -o /dev/null -s -w \
"DNS: %{time_namelookup}s | TCP: %{time_connect}s | TTFB: %{time_starttransfer}s | Total: %{time_total}s\nSpeed: %{speed_download} bytes/sec\n" \
https://cdn.example.com/testfiles/100MB.bin

# 2. The math behind why single-stream throughput stalls
# Throughput (bps) = Window Size (bytes) * 8 / RTT (seconds)
# Example: 64 KB window (default on older stacks) / 0.08s RTT
# 65535 * 8 / 0.08 = 6,553,500 bps = ~6.5 Mbps
# Even on a 10 Gbps link, that one connection is stuck at 6.5 Mbps

# 3. iperf3 parallel streams to see if it's bandwidth or per-stream limit
iperf3 -c edge.example.com -p 5201 -P 8 -t 10
# If 1 stream = 150 Mbps but 8 streams = 1.1 Gbps, your link is fine - your window/RTT is the limiter

Head-to-Head: Why More Bandwidth Doesn't Always Mean Faster Delivery

So why does this distinction matter when you're picking a CDN plan or debugging slow downloads? Because buying more bandwidth without fixing throughput bottlenecks is like adding eight lanes to a highway but keeping the on-ramp as a single-lane dirt road. I've watched teams double their origin bandwidth from 10G to 20G and see zero improvement in p95 video start time, because their throughput was choked by 80ms transatlantic RTT and packet loss on a congested peering link, not by raw capacity.

For typical CDN traffic — lots of small to medium objects, TLS handshakes, cache misses — throughput is the number your users feel. A 100 Mbps link that consistently delivers 95 Mbps of throughput will feel dramatically faster than a 1 Gbps link that only sustains 40 Mbps due to poor tuning. That's why we tune window scaling, enable BBR, keep connections warm, and push content to the edge closer to the user. We're not increasing the network capacity; we're removing the friction that keeps you from using the capacity you already have.

Scenario (Single TCP Connection) Advertised Bandwidth Average Measured Throughput Primary Limiter
Ideal Lab Test (Same Rack, 0.2ms RTT) 10 Gbps 9.4 Gbps Hardware / NIC capacity
Regional User (20ms RTT, No Loss) 1 Gbps ~820 Mbps TCP tuning, congestion control
Cross-Continent (90ms RTT, No Loss) 1 Gbps ~120 Mbps Bandwidth-delay product, Window size
Congested Peering (40ms RTT, 1% Loss) 1 Gbps ~35 Mbps Packet loss, Retransmits
Mobile Last Mile (60ms RTT, 0.5% Loss) 100 Mbps ~18 Mbps Last-mile bufferbloat, Loss

From Theory to Practice: How to Actually Measure Throughput at the Edge

You've got a 100 Gbps commit at your primary PoP — great. But that number won't tell you what a user in Jakarta actually gets at 8 PM on a congested mobile network. If you're not measuring throughput continuously, you're flying blind. We don't rely on what the transit provider promises; we rely on what our edge sees. That means pairing synthetic testing with real-user monitoring (RUM) and looking at throughput distributions, not just averages.

For synthetics, we run parallel iperf3 and HTTP download tests from RIPE Atlas probes and our own edge agents every 5 minutes. Don't just run a single-stream test — that'll underreport your capacity due to TCP window limits. Use 8-16 parallel streams with a 60-second window to saturate the path. For RUM, we log bytes_delivered / time_to_last_byte for every cache HIT and MISS. The trick is to filter: only look at objects larger than 1MB, otherwise TCP slow-start skews your numbers. When we did this for a large video customer last quarter, their contracted bandwidth was 40 Gbps per PoP, but their p50 throughput for 4K segments was 68 Mbps and their p95 was only 18 Mbps on mobile — that's the number that actually drives rebuffering.

Don't make the mistake of averaging it all together. You'll want to slice that RUM data by ASN, PoP, and cache status. A healthy PoP should show median throughput at 80-85% of the provisioned port capacity under peak. If you're seeing 10 Gbps ports peaking at 3.2 Gbps of actual throughput with no packet loss, you've likely got a TCP tuning or congestion control issue, not a capacity problem. For a deeper dive on how to read those tails, see our breakdown on CDN Percentile Latency Analysis: What p50, p95, and p99 Actually Tell You — the same percentile logic applies directly to throughput.

# Sustained throughput test from edge to origin + RUM log analysis
# Run from 3 PoPs with 8 parallel streams for 60s (BBR congestion control)
for POP in iad sin fra; do
  echo "Testing $POP -> origin..."
  iperf3 -c origin.example.com -p 5201 -t 60 -P 8 -w 512K -C bbr -J \
  | jq '.end.sum_received.bits_per_second / 1e9 | "Gbps: \(.)"'
done

# Extract real throughput per request from CDN access logs (hits only, >1MB)
# log format: $bytes_sent $request_time $uri $cache_status
awk '$4 == "HIT" && $1 > 1000000 { 
  throughput = ($1 * 8) / ($2 * 1e6); 
  print throughput, $3, $2 
}' /var/log/cdn/access.log | sort -nr | head -20

# Quick check for TCP retransmits that kill throughput
ss -i dst :443 | grep -E 'rtt|cwnd|retrans'

Advanced Troubleshooting: When You've Got Bandwidth But Throughput Falls Off a Cliff

This is where most teams get stuck. Your Grafana dashboard shows you're only pushing 42 Gbps on a 100 Gbps commit, yet users are complaining about slow downloads and your origin's getting hammered. Nine times out of ten, it's not a bandwidth ceiling — it's a transport impairment. Even 0.1% packet loss on a 40ms RTT path can slash a single TCP CUBIC flow's throughput by 50-70% due to congestion window halving. We saw a case where a single faulty line card was causing 0.02% random loss, and throughput for 10MB assets dropped from 850 Mbps to under 120 Mbps. Bandwidth didn't change one bit.

Start your triage with jitter and reordering. High CDN Jitter Measurement and Its Impact on User Experience is often the early warning sign — if your RTT variance jumps from a stable 25ms ±2ms to 25ms ±18ms, your throughput variance will explode. TCP interprets jitter as potential congestion and backs off. Even worse is packet reordering, which we see a lot on equal-cost multipath (ECMP) networks that aren't hashing correctly. When packets arrive out of order, the receiver sends duplicate ACKs, the sender triggers fast retransmit, and your congestion window collapses even though nothing was actually lost. We've documented this as a silent killer in Packet Reordering Effects on CDN Performance: The Hidden Throughput Killer — if your throughput is erratic but loss is near zero, check for reordering with netstat -s | grep reord or by capturing TCP SACK blocks.

So what's the fix? First, switch your edge and origin to BBR v2 or v3 if you haven't already — it models the bottleneck bandwidth and RTT instead of just reacting to loss, and it's far more resilient to jitter and shallow buffer loss. We've seen 2-3x throughput improvements on lossy last-mile paths just from that change. Second, tune your initial congestion window (initcwnd) to 32-64 and enable TCP pacing. Third, check for bufferbloat at peering points; an over-buffered switch adding 150ms of queuing delay will destroy throughput for interactive traffic. If nothing else, isolate whether it's last-mile vs. mid-mile by comparing throughput for cache HITs vs. MISSes — if HITs are fast and MISSes are slow, your problem's on the origin path, not the eyeball network.

Frequently Asked Questions

Can I have high bandwidth but low throughput?

Absolutely, and it's the most common performance trap we see. You can pay for a 100 Gbps port (bandwidth) but only achieve 2 Gbps of throughput on a single flow due to 60ms latency, 0.5% packet loss, or a small TCP receive window. Bandwidth is the size of the pipe; throughput is how much water actually makes it through given TCP dynamics, congestion, and path impairments.

What's a good throughput target for CDN video delivery?

For 1080p adaptive bitrate, you need sustained throughput of at least 8-10 Mbps per user for a clean experience, and 25-35 Mbps for 4K. But don't look at averages — we provision so that p95 throughput stays above that line. If your p50 is 50 Mbps but your p95 dips to 4 Mbps, 5% of your viewers are constantly rebuffering even though your "average" looks great.

Why does my throughput test show 900 Mbps one minute and 150 Mbps the next?

That's almost always jitter, microbursts, or cross-traffic contention, not a bandwidth change. Throughput is highly sensitive to time-of-day congestion and TCP competition. Run tests for at least 60 seconds with multiple parallel streams and repeat them every few minutes for 24 hours. If the variance correlates with packet loss or RTT spikes, you're seeing congestion — not a capacity limit.

Should I monitor bandwidth or throughput for capacity planning?

Both, but for different reasons. Use bandwidth (95th percentile Mbps on your switch ports) for billing and commit planning. Use throughput (actual Mbps delivered per request/flow from logs and RUM) for user experience and performance engineering. If your bandwidth utilization is at 60% but throughput is degrading, you don't need a bigger pipe — you need to fix the path.

Related Articles

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