8 vCPU、32 GB 伺服器運行 LiveKit 三人 1080p 通話,瓶頸是 10 Mbps 對外頻寬
An 8-vCPU, 32 GB server choked on a 3-person 1080p LiveKit call — the bottleneck was outbound bandwidth
作者自建 LiveKit 影片會議時發現,配置為 8 vCPU、32 GB RAM、10 Mbps 固定公網頻寬的伺服器,加入第三名開啟鏡頭的 1080p 參與者後便出現畫面凍結。
I recently added self-hosted video meetings to an internal product using LiveKit on Docker.
The VM looked generous on paper: 8 vCPUs, 32 GB RAM, and a fixed 10 Mbps public bandwidth plan.
In practice, 1080p worked fine with two people in a room. The moment a third person joined with their camera on, video froze.
Here is what happened, why I picked LiveKit **over **Jitsi, and the bandwidth math I should have done before buying a fixed-bandwidth VM.
Why LiveKit instead of Jitsi
Before deploying, I compared Jitsi + Jibri against LiveKit Server + Egress, specifically looking at protocol design and recording:
-
Jitsi + Jibri: Jibri records a room by spinning up a headless Chrome instance to render the meeting page and capturing it with
ffmpeg. The output looks just like a real meeting, but one Jibri instance only records one meeting at a time—scaling concurrent recordings means running one Jibri per active recorded room on top of the XMPP stack. -
LiveKit: Uses WebSocket signaling + WebRTC SFU, separates media routing (
livekit-server) from recording/streaming (livekit/egress), and has an officialagentsframework if you later add voice AI. Note that LiveKit's full-room composite Egress also runs headless Chrome inside its container (requiringSYS_ADMINcapability and roughly 2–6 vCPUs per active recording), and one Egress instance still records one room at a time—so you still size Egress per concurrent recorded room, without carrying the rest of Jitsi's stack.
Deployment was smooth (if you stick to official templates)
Getting LiveKit Server and Egress running via Docker was straightforward. One takeaway if you use coding agents to help wire up configs: anchor strictly on LiveKit's official config generator (livekit/generate) and sample templates. Letting an LLM improvise WebRTC/TURN/Caddy configs from scratch is a fast way to break UDP media routing (50000-60000/udp, 3478/udp, 7881/tcp) or TLS certificates.
Where it actually broke: SFU outbound math
LiveKit is a Selective Forwarding Unit (SFU). Every participant uploads their camera stream once to the server, and the server forwards separate copies down to everyone else in the room.
If everyone has a 1080p camera on at ~4 Mbps (ignoring simulcast downscaling for a worst-case ceiling), the server's outbound (egress) bandwidth grows as N × (N - 1) × 4 Mbps:
| Participants (all cameras on) | Server outbound bandwidth |
|---|---|
| 1 publishing, 1 watching | ~4 Mbps |
| 2 people (1-on-1) | ~8 Mbps |
| 3 people | ~24 Mbps |
| 4 people | ~48 Mbps |
| 10 people | ~360 Mbps |
On a cloud VM with a 10 Mbps outbound cap:
- A 1-on-1 call uses ~8 Mbps—just under the ceiling.
- A 3rd person pushes outbound demand to ~24 Mbps—instant packet loss and frozen frames, while the 8 vCPUs and 32 GB RAM sit mostly idle.
Before going to production, LiveKit's CLI includes lk load-test to simulate publishers and subscribers against your actual box instead of guessing.
Takeaway: bill video servers by metered traffic, not fixed bandwidth
For self-hosted video meetings, outbound network cap matters long before CPU or RAM.
Traffic for meetings is spiky: heavy while rooms are active, near zero the rest of the day. Paying for a high fixed-Mbps pipe 24/7 is expensive, while a cheap 10 Mbps fixed pipe chokes on the third caller. Using pay-per-GB (metered egress traffic) with a high burst bandwidth ceiling fits SFU workloads much better than a flat low-bandwidth cap.
I maintain a plain-English checklist of self-hosting requirements, license terms, and real server/cloud costs for LiveKit and 18 other open-source business apps at BuilderStack.
來源:DEV Community · dev.to