Last updated: July 2, 2026 · Reviewed by StreamingVPS.com Engineering Team
You load test a streaming VPS by simulating both ingest (publishers pushing RTMP/SRT) and delivery (viewers pulling HLS/WebRTC) at your expected peak concurrency, then watching CPU, bandwidth, and dropped-frame metrics as you scale load in increments until something degrades. Skipping this step is the single most common reason a stream that worked fine in testing with one viewer falls over the moment a real audience shows up — the failure mode isn’t usually the encoder, it’s the server running out of CPU or network headroom under concurrent load nobody actually tested for.
We run pre-launch load tests on customer streaming VPS instances before big events (product launches, live sports, church services with holiday-sized crowds) because the alternative — finding out your capacity ceiling live, in front of your actual audience — is a bad way to learn it. This guide walks through the exact tools and thresholds we use.
Key Takeaways
- Load testing a streaming server means testing two separate things: ingest capacity (how many publishers can push streams in) and delivery capacity (how many viewers can pull streams out) — most setups need to test both independently.
- ffmpeg can generate synthetic RTMP/SRT publish load for free; HLS/DASH delivery load needs an HTTP load tool like Locust, wrk, or k6 that repeatedly fetches segment playlists like a real player would.
- Keep sustained CPU usage under 70-75% at your expected peak concurrency — headroom matters more than hitting an exact viewer number, because keyframe bursts and transcoding spikes add sudden load on top of steady-state traffic.
- WebRTC requires different tooling than RTMP/HLS because it needs real peer connections and ICE negotiation, not simple HTTP requests — use headless-browser-based load tools or your engine’s built-in load tester (Ant Media Server ships one).
- Run tests for at least 20-30 minutes, not just a quick burst — memory leaks, disk I/O bottlenecks from DVR recording, and file descriptor exhaustion often only surface under sustained load.
Why Does a Stream That Worked in Testing Fail With a Real Audience?
The classic failure pattern: you test with OBS pushing one RTMP stream to your VPS, playback looks perfect, you call it done. Then 200 real viewers show up and the stream stutters or the server becomes unresponsive. The gap is that a single-viewer test only exercises the ingest path — it never touches the delivery path where the server has to serve dozens or hundreds of simultaneous HLS segment requests, each consuming CPU for segment packaging (if transcoding), disk I/O for reads, and network bandwidth for the actual bytes.
On a 4 vCPU / 8 GB VPS running NGINX-RTMP with HLS output, we’ve seen single-viewer tests pass cleanly and then watched CPU climb past 90% at around 400 concurrent HLS viewers pulling 6-second segments — not because the stream itself was heavy, but because NGINX was doing enough disk I/O and TLS handshake overhead per new connection that it became the bottleneck well before bandwidth did. That number is specific to that config; the point is you only find your specific number by testing it, not by assuming it.
How Do You Load Test RTMP Ingest With ffmpeg?
RTMP ingest load testing means simulating multiple publishers pushing streams to your server simultaneously, which is straightforward with ffmpeg since it can loop a local test file and push it as RTMP:
ffmpeg -re -stream_loop -1 -i test_source.mp4 \
-c:v libx264 -b:v 3000k -c:a aac -b:a 128k \
-f flv rtmp://your-vps-ip/live/test_stream_01
Wrap this in a loop that spins up 5, 10, then 20 concurrent instances against different stream keys to find the point where your engine’s CPU (for any transcoding/ABR ladder generation) or network ingest bandwidth becomes the constraint. Watch top/htop on the VPS itself while this runs, and check your engine’s admin console (Wowza Streaming Engine Manager, Ant Media’s dashboard) for per-stream health indicators like dropped frames or encoder buffer warnings.
How Do You Load Test HLS Delivery to Many Concurrent Viewers?
This is the test most people skip, and it’s the one that actually predicts your real launch-day capacity. Use a tool built for HTTP load generation — Locust (Python, easy to script realistic segment-fetching behavior) or k6 (JavaScript-based, good for CI integration) both work well:
# Locust example: simulate a viewer repeatedly fetching HLS segments
from locust import HttpUser, task, between
class HLSViewer(HttpUser):
wait_time = between(4, 6) # mimics real segment-fetch cadence
@task
def fetch_playlist(self):
self.client.get("/live/stream.m3u8")
@task(3)
def fetch_segment(self):
self.client.get("/live/segment_0042.ts")
Ramp concurrent simulated users up in steps (50, 150, 300, 500) rather than jumping straight to your target number, and record CPU, memory, and average response time at each step. In our testing, response time is usually the earliest warning sign — segment fetch times creeping from 50ms to 300ms+ typically show up 15-20% before CPU actually maxes out, giving you an early signal to scale up before things visibly break for viewers.
How Is WebRTC Load Testing Different?
WebRTC can’t be load tested with simple HTTP requests because each viewer requires a real peer connection, ICE candidate negotiation, and (often) a TURN relay — there’s no static file being fetched. Ant Media Server ships its own load-testing tool (ant-media-server-load-test) that spins up simulated WebRTC publishers and players against a target instance, which is the most reliable way to test this protocol specifically. Generic headless-browser automation (Puppeteer/Playwright driving real Chrome instances) is the fallback if you’re running a different WebRTC engine, though it’s far more resource-intensive to run the load generator itself — expect to need a separate, beefy VPS just to generate the synthetic WebRTC load.
What Should You Actually Watch During the Test?
| Metric | Warning threshold | Why it matters |
|---|---|---|
| CPU usage (sustained) | Above 75% | Leaves no headroom for keyframe bursts or transcoding spikes |
| Network throughput | Above 80% of provisioned bandwidth | Real launches often exceed test traffic by 20-30% |
| Dropped/late frames (engine console) | Any sustained increase | Early indicator of encoder or CPU contention |
| Segment/response latency | Rising trend, not just absolute value | Predicts failure before CPU/bandwidth caps are hit |
| Open file descriptors | Approaching ulimit -n | Silent killer — connections start failing with no clear error |
| Disk I/O (if DVR/recording enabled) | Sustained near 100% util | Recording writes compete with segment reads for the same disk |
FAQ
How many concurrent viewers should I simulate when load testing?
Simulate at least 1.5x your expected peak concurrent viewers to leave a safety margin for unexpected traffic spikes, and test in increments so you can identify the exact point where CPU, bandwidth, or latency starts to degrade rather than just confirming a single target number.
Can I load test HLS and RTMP the same way?
No. RTMP load testing simulates publishers pushing streams in, typically with ffmpeg, while HLS load testing simulates viewers pulling segments out via repeated HTTP GET requests, typically with a tool like Locust, wrk, or k6. You need both if your setup does ingest and delivery on the same VPS.
What CPU usage is safe during a load test?
Aim to keep sustained CPU usage under 70-75% at your expected peak load, leaving headroom for transcoding spikes, keyframe bursts, and OS-level overhead. Consistently running above 85% during testing means you’re one traffic spike away from dropped frames or crashed processes in production.
Do I need to load test WebRTC differently than RTMP or HLS?
Yes. WebRTC load testing requires simulating actual peer connections and ICE negotiation, not just HTTP requests, so it typically needs headless browser tools or an engine’s built-in load-testing utility rather than a generic HTTP load tool like wrk or Locust.
How long should a load test run?
Run a sustained load test for at least 20-30 minutes at target concurrency, not just a few seconds, because memory leaks, file descriptor exhaustion, and disk I/O bottlenecks from DVR recording often only appear after sustained load rather than at the initial connection spike.
Conclusion
A load test is the difference between discovering your VPS’s capacity ceiling on a spreadsheet beforehand versus discovering it live in front of your audience. Test ingest and delivery separately, ramp load in steps rather than jumping to your target number, watch latency trends as an early warning sign, and leave real headroom — 70-75% sustained CPU, not 95%.
StreamingVPS.com’s pre-installed engine plans come with the CPU and bandwidth headroom sized for real concurrent-viewer loads, not just clean single-stream demos, and our team can help you run a pre-launch load test before a big event. Get a pre-installed streaming VPS from StreamingVPS.com and go live in 60 seconds. For related guides, see how many concurrent viewers a streaming VPS can handle and how to monitor a streaming VPS.