네트워크 성능 — 대역폭은 왜 빠름이 아닌가 (RTT·BDP·처리량의 진실)
대역폭과 지연·RTT의 차이(파이프 굵기 vs 길이), BDP=대역폭×RTT, 윈도우와 처리량의 관계, Mathis 공식, 버퍼블로트, iperf3·traceroute·mtr 측정까지 네트워크 성능을 분석합니다.
“기가비트인데 왜 느리죠?”
회선을 1 Gbps로 올렸는데 서울↔프랑크푸르트 파일 전송이 여전히 답답합니다. 대역폭을 더 사도 안 빨라집니다. 이건 버그가 아니라 대역폭과 지연이 서로 다른 축이기 때문입니다. 이 글의 목표는 “느리다”는 막연한 말을 대역폭 / 지연 / RTT / BDP / 손실이라는 측정 가능한 양으로 분해하고, 왜 어떤 경우엔 더 넓은 파이프가 1바이트도 도움이 안 되는지를 끝까지 밝히는 것입니다.
패킷 교환 글에서 본 4가지 지연(전송·전파·처리·큐)이 여기서 성능 공식으로 합쳐집니다.
파이프 비유: 굵기 vs 길이
네트워크 경로를 물 파이프로 생각하면 모든 게 맞아떨어집니다.
- 대역폭(bandwidth) = 파이프의 굵기. 단위 시간당 밀어 넣을 수 있는 비트(bps).
- 지연(latency) = 파이프의 길이. 비트 하나가 끝까지 가는 시간. 주로 거리÷광속(전파 지연)이 지배.
- RTT(왕복 시간) = 보내고 응답이 돌아오기까지 = 대략 2 × 편도 지연.
핵심은 이것입니다. 파이프를 굵게 해도 길이는 안 줄어듭니다. 서울↔프랑크푸르트 편도 전파는 광속 한계상 ~120 ms이고, 회선을 10배 넓혀도 첫 바이트 도착 시간은 그대로입니다. “빠르다”가 지연을 뜻하면 대역폭은 답이 아닙니다 — 답은 거리를 줄이는 것(CDN·엣지)입니다(CDN 글).
BDP — 파이프 안에 동시에 떠 있는 비트의 양
여기서 가장 중요한 양이 나옵니다. 대역폭-지연 곱(Bandwidth-Delay Product):
1
BDP (비트) = 대역폭(bps) × RTT(초)
이건 “전송했지만 아직 ACK를 못 받은, 즉 파이프 안에 떠 있을 수 있는 데이터의 최대량”입니다. 파이프의 부피라고 생각하면 됩니다.
예시 — 왜 100 Mbps 회선이 12 Mbps밖에 안 나오나. 대역폭 100 Mbps, RTT 80 ms 경로. BDP = 100 Mbps × 0.08 s = 8 Mbit = 1 MB. 파이프를 가득 채우려면 송신 측이 ACK 없이 1 MB를 앞서 보낼 수 있어야 합니다. 그런데 TCP 윈도우가 64 KB(옛 기본)라면? 64 KB 보내고 ACK를 기다리느라 멈춥니다. 실효 처리량 = 윈도우 ÷ RTT = 64 KB ÷ 0.08 s ≈ 6.4 Mbps. 대역폭의 6%만 씁니다.
이게 LFN(Long Fat Network, 고대역폭·고지연 경로) 의 함정입니다. 대역폭이 아니라 윈도우가 병목입니다.
윈도우가 BDP보다 작으면 — 파이프가 빈다
아래 위쪽은 윈도우가 BDP와 같아 파이프가 꽉 찬 경우, 아래쪽은 윈도우가 작아 보내고 멈추고(ACK 대기) 다시 보내며 파이프에 빈 구간이 생기는 경우입니다. 같은 회선인데 아래는 처리량이 절반 이하입니다.
그래서 처리량의 근본 공식은 이렇습니다.
1
실효 처리량 ≈ 윈도우 크기 / RTT (윈도우가 병목일 때)
해법은 윈도우를 BDP 이상으로 키우는 것입니다. 리눅스는 tcp_window_scaling(RFC 1323)으로 64 KB 한계를 넘기고, 버퍼 자동 튜닝(tcp_rmem/tcp_wmem의 max)으로 BDP에 맞춰 윈도우를 키웁니다. 송신 윈도우는 혼잡 제어의 cwnd와 수신 윈도우 중 작은 쪽으로 정해지고, 이 버퍼는 소켓 글의 SO_RCVBUF와 같은 것입니다.
손실이 끼면 — Mathis 공식
패킷 손실이 있으면 이야기가 더 나빠집니다. AIMD 기반 TCP의 처리량 상한은 근사적으로:
1
처리량 ≲ (MSS / RTT) × (1 / √p) (p = 패킷 손실률)
손실률 p가 처리량을 제곱근으로 깎습니다. RTT 100 ms, MSS 1460 B에서 손실 0.01%(p=0.0001)면 상한은 약 117 Mbps지만, 손실이 1%로 오르면 같은 식이 약 12 Mbps로 떨어집니다. 고RTT 경로에서 약간의 손실이 처리량을 붕괴시키는 이유입니다 — 그래서 장거리 전송에선 손실률 0.01%도 큰 문제입니다.
| 양 | 정의 | 키우면/줄이면 | 측정 |
|---|---|---|---|
| 대역폭 | 단위시간 비트(bps) | 처리량 상한↑ | iperf3 -c |
| RTT | 왕복 시간 | 작을수록 처리량↑·반응성↑ | ping, ss -i(rtt) |
| BDP | 대역폭×RTT | 필요한 윈도우 크기 | 계산 |
| 윈도우 | ACK 없이 보낼 양 | ≥BDP라야 파이프 채움 | ss -i(cwnd, wscale) |
| 손실률 p | drop 비율 | √p로 처리량 깎임 | ss -i(retrans), mtr |
| 지터 | RTT 변동 | 작을수록 실시간 품질↑ | ping, iperf3 -u |
버퍼블로트 — 큐가 너무 커서 생기는 지연
직관과 반대로, 라우터 버퍼가 너무 크면 성능이 나빠집니다. 큐에 패킷이 잔뜩 쌓여도 drop이 안 나니 TCP가 혼잡을 늦게 알아채고, 그 사이 큐 대기 시간이 수백 ms~초로 폭증합니다 — 버퍼블로트(bufferbloat). 다운로드 중에 화상통화가 끊기는 전형적 원인입니다. 해법은 AQM(CoDel·FQ-CoDel·CAKE)으로, 큐가 오래 머문 패킷을 일찍 떨궈 지연을 낮춥니다.
측정 도구 — 추측 금지
1
2
3
4
5
6
ping -c 20 host # RTT 평균/최소/최대 + 지터(mdev)
mtr --report --report-cycles 50 host # 홉별 손실률·RTT (traceroute+ping)
iperf3 -c host -t 30 # 실효 처리량(TCP), -u로 UDP 지터/손실
iperf3 -c host -P 8 # 병렬 8스트림 — 단일 윈도우 병목 우회 확인
ss -tin dst host # cwnd, rtt, retrans, wscale 실시간
tcpdump -i eth0 -w cap.pcap # 재전송·중복 ACK를 패킷 수준에서
진단 사고법: ①
iperf3 -P 1처리량이 낮은데-P 8이 빠르면 → 윈도우/BDP 병목(버퍼 키워라). ②mtr에서 특정 홉부터 손실 누적 → 그 구간 혼잡/장애. ③ 다운로드 시pingRTT가 급등 → 버퍼블로트(AQM 적용).
traceroute — RTT가 홉마다 쌓인다
traceroute는 TTL을 1,2,3…으로 늘려 각 홉이 보내는 ICMP Time Exceeded로 경로와 누적 RTT를 그립니다. 아래는 프로브가 한 홉씩 더 멀리 가며 RTT가 누적되는 모습입니다.
면접/리뷰 단골 질문
- Q. 대역폭을 늘렸는데 안 빨라진다. 왜? → “빠름”이 지연이면 대역폭 무관(거리÷광속). “빠름”이 처리량인데 안 오르면 윈도우<BDP 병목이거나 손실이다.
- Q. BDP를 한 줄로? → 대역폭×RTT. 파이프에 떠 있을 수 있는 비트량. 윈도우가 이보다 작으면 파이프를 못 채운다.
- Q. 처리량 공식은? → 윈도우 병목 시 윈도우/RTT. 손실 있으면 Mathis로 (MSS/RTT)·(1/√p) 상한. RTT와 손실이 같이 처리량을 누른다.
- Q. 버퍼가 큰데 왜 느려지나? → 버퍼블로트. 큰 큐가 drop을 늦춰 혼잡 신호가 늦고 큐 지연이 폭증. AQM(CoDel)으로 해결.
- Q. 단일 스트림은 느린데 병렬은 빠르다. 진단은? → 윈도우/BDP 병목. 윈도우 스케일링·버퍼 자동튜닝으로 단일 스트림 윈도우를 키운다.
정리
- 대역폭(굵기) ≠ 지연(길이) ≠ 처리량(실제 흐른 양). 셋을 분리 못 하면 원인을 못 찾는다.
- BDP = 대역폭 × RTT. 윈도우가 BDP보다 작으면 파이프가 비어 처리량 = 윈도우/RTT로 묶인다(LFN 함정).
- 손실은 √p로 처리량을 깎는다(Mathis). 고RTT에선 작은 손실도 치명적.
- 버퍼는 작아도(채움 부족) 커도(버퍼블로트) 문제다 → 윈도우는 BDP에 맞추고, 큐는 AQM으로.
- 추측 말고
ping/mtr/iperf3/ss -i로 측정하라.
이 성능 원리는 패킷 교환의 4지연에서 출발해, TCP 혼잡 제어의 cwnd, 소켓 버퍼, 거리를 줄이는 CDN과 한 몸으로 묶입니다.
