LLM WikiAccess-protected knowledge portal

WIKI

네트워크 성능 분석: iperf3, fio 연동, 병목 진단

대역폭은 10Gbps인데 왜 백업은 300MB/s에서 멈출까 새 데이터베이스 서버의 NIC와 스위치 포트는 모두 10Gbps로 연결됐다. 그런데 원격 백업은 300MB/s 부근에서 더 올라가지 않는다. ping 은 0.4ms이고 패킷 손실도 없다. 이때 곧바로 네트워크를 의심해 TCP 버퍼를 키우면 문제를 풀기보다 측정 조건만 바꿀 수 있다. 병목은 디스크 읽기, 단일 TCP 흐름, 한 CPU의 softirq, 가상 머신의 P

경로human/study/content/networking-fundamentals/06-network-performance-analysis.md
카테고리Study
태그#analysis #fundamentals #network #networking #performance #study

대역폭은 10Gbps인데 왜 백업은 300MB/s에서 멈출까

새 데이터베이스 서버의 NIC와 스위치 포트는 모두 10Gbps로 연결됐다. 그런데 원격 백업은 300MB/s 부근에서 더 올라가지 않는다. ping은 0.4ms이고 패킷 손실도 없다. 이때 곧바로 네트워크를 의심해 TCP 버퍼를 키우면 문제를 풀기보다 측정 조건만 바꿀 수 있다. 병목은 디스크 읽기, 단일 TCP 흐름, 한 CPU의 softirq, 가상 머신의 PPS 한도, 반대 방향 링크 중 어디에나 있을 수 있다.

네트워크 성능 분석의 핵심은 도구 하나가 아니라 경로를 분해하고, 한 번에 변수 하나만 바꾸고, 양 끝단을 동시에 관찰하는 절차다. 이 장에서는 iperf3로 순수 네트워크 상한을 측정하고, fio로 스토리지 상한을 분리한 뒤, 둘을 함께 실행해 공유 자원 병목을 찾는 방법을 다룬다.


먼저 구분해야 할 성능 지표

Gbps 숫자 하나로는 병목을 설명할 수 없다. 적어도 다음 지표를 나눠 봐야 한다.

지표의미운영에서 묻는 질문
Link speedNIC와 상대 장비가 협상한 물리 링크 속도정말 10Gbps로 링크가 올라왔는가
Throughput단위 시간에 경로가 처리한 전체 비트링크와 장비가 얼마나 운반했는가
Goodput애플리케이션이 실제로 받은 유효 데이터백업이나 복제가 실제로 얼마나 전진했는가
PPS초당 패킷 수작은 패킷에서 CPU나 클라우드 PPS 한도를 넘는가
RTT요청이 왕복하는 시간단일 흐름의 TCP window가 경로를 채우기에 충분한가
Jitter패킷 지연의 변동실시간·UDP 트래픽이 흔들리는가
Loss손실된 패킷 비율큐, 물리 링크, 정책, 클라우드 한도에서 드롭되는가
RetransmitTCP가 다시 보낸 세그먼트손실 때문에 congestion window가 줄어드는가
CPU/softirq패킷 처리를 위해 소비한 CPU네트워크보다 한 코어가 먼저 포화되는가

iperf3가 보여 주는 전송률은 애플리케이션 관점의 측정값이다. 이더넷, IP, TCP 헤더와 재전송 비용이 있으므로 물리 링크 속도와 정확히 같을 필요는 없다. 특히 작은 패킷에서는 비트 전송률보다 PPS와 CPU가 먼저 한계에 닿을 수 있다.

한 번에 한 경계씩 측정한다 1. 네트워크만 iperf3 생성 데이터 TCP/UDP, 정방향/역방향 2. 스토리지만 fio 전용 테스트 파일 BW, IOPS, p95/p99 latency 3. 결합 부하 iperf3와 fio 동시 실행 CPU, memory, NUMA, VM 한도 결과 해석 네트워크만 느림 → 경로, TCP, NIC, CPU, 클라우드 네트워크 한도 스토리지만 느림 → 디스크, 파일시스템, 캐시, I/O queue 각각은 빠르고 동시 실행만 느림 → 공유 CPU, memory bandwidth, NUMA, 가상화 한도 항상 양 끝단의 CPU·NIC 카운터·TCP 상태를 같은 시간축으로 수집한다.
병목을 분리하는 3단계 측정 모델

측정 전에 고정할 조건

성능 테스트는 재현 가능해야 비교할 수 있다. 명령을 실행하기 전에 다음 조건을 기록한다.

프로덕션에서는 대역폭을 전부 쓰는 테스트를 바로 실행하지 않는다. 낮은 목표 속도부터 단계적으로 올리고, 변경 승인과 중단 기준을 정한다. iperf3의 UDP -b 0은 bitrate 제한을 없애므로 특히 위험하다.


iperf3로 순수 네트워크 상한 측정하기

기본 TCP 테스트

수신 측에서 서버를 실행한다. 기본 제어·데이터 포트는 TCP 5201이다.

# 수신 측
iperf3 -s

# 송신 측: 3초 워밍업을 통계에서 제외하고 30초 측정
iperf3 -c 10.20.0.12 -t 30 -O 3 -i 1 --get-server-output

-O 3은 TCP slow start 초반 3초를 통계에서 제외한다. 짧은 테스트는 순간 burst나 slow start의 영향을 크게 받으므로 30초 이상 실행하고 여러 번 반복한다. 결과에서 송신 측 Retr와 송신·수신 측 bitrate 차이를 함께 본다.

자동 수집에는 JSON을 사용한다.

iperf3 -c 10.20.0.12 -t 30 -O 3 -J \
  > iperf3-forward-$(date +%Y%m%d-%H%M%S).json

실시간 파이프라인에는 line-delimited JSON을 내보내는 --json-stream도 사용할 수 있다. 다만 옵션 지원 여부는 설치된 버전으로 확인한다.

방향과 흐름 수를 바꿔 병목을 좁힌다

# 서버가 클라이언트로 전송: 반대 방향 경로 확인
iperf3 -c 10.20.0.12 -R -t 30 -O 3

# 양방향을 동시에 사용
iperf3 -c 10.20.0.12 --bidir -t 30 -O 3

# 4개 TCP 흐름
iperf3 -c 10.20.0.12 -P 4 -t 30 -O 3

# 특정 출발 IP/인터페이스 경로 고정
iperf3 -c 10.20.0.12 -B 10.10.0.21 -t 30 -O 3

해석은 숫자의 크기보다 비교 관계가 중요하다.

iperf3 3.16부터는 테스트 스트림마다 별도 스레드를 사용한다. 그보다 오래된 버전은 단일 스레드 제약 때문에 고속 링크에서 한 CPU가 먼저 포화될 수 있다. 결과를 비교할 때 양 끝의 iperf3 --version을 반드시 남긴다.

UDP는 손실이 시작되는 지점을 찾는 테스트다

# 100Mbps부터 시작해 단계적으로 올린다
iperf3 -c 10.20.0.12 -u -b 100M -t 30 -O 3
iperf3 -c 10.20.0.12 -u -b 500M -t 30 -O 3
iperf3 -c 10.20.0.12 -u -b 1G   -t 30 -O 3

UDP의 기본 목표 bitrate는 1Mbit/s이므로 -b를 빠뜨리면 고속 경로를 거의 시험하지 못한다. 반대로 -b 0은 제한을 해제한다. 운영망에서는 목표 속도를 정해 올리면서 loss와 jitter가 어느 구간에서 증가하는지 찾는 편이 안전하다.

TCP와 UDP 결과는 같은 의미가 아니다. TCP는 손실을 재전송하고 congestion control로 속도를 줄인다. UDP는 재전송하지 않으므로 큐와 PPS 한계를 더 직접적으로 드러내지만 애플리케이션이 허용할 수 없는 손실을 만들 수 있다.


RTT와 TCP window: BDP를 계산해야 하는 이유

한 TCP 흐름이 경로를 가득 채우려면 ACK를 기다리는 동안 충분한 데이터를 전송 중 상태로 유지해야 한다. 필요한 양을 Bandwidth-Delay Product라고 한다.

BDP(bytes) = bandwidth(bits/s) × RTT(seconds) ÷ 8

예를 들어 10Gbps 경로의 RTT가 20ms라면 BDP는 25,000,000bytes, 약 25MB다. 송수신 socket buffer나 TCP가 확장할 수 있는 window가 이보다 작으면 패킷 손실이 없어도 단일 흐름은 10Gbps를 채우지 못한다.

# 실제 연결의 RTT, rttvar, cwnd, pmtu, retrans 상태
ss -tin dst 10.20.0.12

# iperf3에서 socket buffer/window를 실험적으로 지정
iperf3 -c 10.20.0.12 -w 32M -t 30 -O 3

-w는 양쪽 socket buffer 크기에 영향을 준다. Linux에서는 요청값과 커널이 보고하는 유효 크기가 다를 수 있으므로 ss -tisysctl net.ipv4.tcp_rmem net.ipv4.tcp_wmem을 함께 확인한다. 한 번의 결과만 보고 전역 TCP buffer를 크게 올리지 않는다. 메모리 소비와 수많은 동시 연결에 미치는 영향을 먼저 계산해야 한다.


fio와 연동해 네트워크와 스토리지를 분리한다

백업, 복제 초기 적재, 오브젝트 업로드는 디스크와 네트워크를 동시에 사용한다. 애플리케이션 처리량만 측정하면 어느 쪽이 병목인지 알 수 없다.

1단계: 생성 데이터로 네트워크만 측정

일반적인 iperf3는 메모리에서 테스트 데이터를 생성하고 수신 측에서 버린다. 이 결과를 네트워크 경로의 기준선으로 삼는다.

iperf3 -c 10.20.0.12 -t 60 -O 5 -P 4 -J > network-only.json

2단계: fio로 스토리지 상한 측정

다음 예시는 미리 생성한 전용 테스트 파일을 순차 읽기한다. 프로덕션 데이터 파일이나 raw block device를 대상으로 실행하지 않는다. 테스트 전에 파일 크기, 여유 공간, 캐시 효과, 스토리지 비용을 확인한다.

fio --name=seqread \
  --filename=/mnt/benchmark/fio-test.bin \
  --size=20G \
  --rw=read \
  --bs=1M \
  --ioengine=libaio \
  --iodepth=32 \
  --direct=1 \
  --time_based=1 \
  --runtime=60 \
  --group_reporting \
  --output-format=json \
  --output=fio-storage-only.json

direct=1은 가능한 환경에서 page cache 우회를 요청해 디바이스 성능을 보기 쉽게 한다. 그러나 파일시스템과 엔진에 따라 지원과 의미가 다르므로 fio 출력과 오류를 확인한다. 평균 bandwidth뿐 아니라 completion latency의 p95, p99, p99.9와 시간대별 변동을 본다.

3단계: 파일 경로 또는 동시 부하로 경계를 연결

iperf3 -F는 생성 데이터 대신 파일을 송신 source 또는 수신 sink로 사용한다. 공식 문서는 이 기능을 스토리지가 파일 전송의 병목인지 확인하는 용도로 설명하면서, 완전한 파일 전송 도구가 아니며 길이·속성·내용이 원본과 일치한다고 보장하지 않는다고 명시한다.

# 송신 측 파일 읽기와 네트워크를 한 경로에 포함
iperf3 -c 10.20.0.12 -F /mnt/benchmark/fio-test.bin -t 60

더 명확한 방법은 fio와 iperf3를 각각 JSON으로 기록하면서 동시에 실행하는 것이다.

# 터미널 A: 네트워크 부하
iperf3 -c 10.20.0.12 -t 120 -O 5 -P 4 -J > combined-iperf3.json

# 터미널 B: 같은 시간에 스토리지 부하
fio --name=seqread --filename=/mnt/benchmark/fio-test.bin \
  --size=20G --rw=read --bs=1M --ioengine=libaio --iodepth=32 \
  --direct=1 --time_based=1 --runtime=120 --group_reporting \
  --output-format=json --output=combined-fio.json

비교 순서는 다음과 같다.

  1. iperf3만 실행한 goodput
  2. fio만 실행한 bandwidth와 latency
  3. 둘을 동시에 실행했을 때 두 결과의 변화

각각 실행할 때는 빠른데 동시 실행에서 둘 다 느려지면 NIC나 디스크만의 문제가 아닐 가능성이 높다. 같은 CPU socket에 몰린 interrupt, NUMA 원격 메모리, memory bandwidth, 가상 머신의 aggregate bandwidth, cgroup CPU quota를 확인한다.

fio에는 net과 Linux의 splice(2)를 사용하는 netsplice I/O engine도 있다. TCP, UDP, UNIX socket 등을 job 형태로 구성할 수 있지만, 네트워크 기준선에는 TCP/UDP 진단 출력이 풍부한 iperf3가 보통 더 적합하다. fio의 network engine은 스토리지·네트워크 작업을 동일한 fio job 모델로 자동화해야 할 때 제한적으로 사용한다.


양 끝단에서 동시에 수집할 증거

테스트 결과 파일만 보면 원인을 놓친다. 송신·수신 호스트에서 다음 명령을 같은 시간에 실행한다.

TCP 상태

# rtt/rttvar, cwnd, pmtu, congestion algorithm, retrans 확인
ss -tin '( dport = :5201 or sport = :5201 )'

# 시스템 TCP 재전송과 오류
sar -n TCP,ETCP 1

# 프로토콜 카운터 변화
nstat -az | grep -E 'TcpRetransSegs|TcpExtTCPTimeouts|IpReasmFails'

ss -i는 커널 내부 TCP 정보인 RTT, RTT 편차, congestion window, path MTU 등을 노출한다. Retr가 증가하면 경로 손실만 보지 말고 NIC drop, qdisc drop, MTU, 클라우드 allowance를 함께 확인한다.

인터페이스와 큐

# 인터페이스 drop/error
ip -s link show dev eth0
sar -n DEV,EDEV 1

# NIC 드라이버별 상세 통계
ethtool -S eth0

# link, offload, channel, ring, coalescing 설정
ethtool eth0
ethtool -k eth0
ethtool -l eth0
ethtool -g eth0
ethtool -c eth0

# qdisc drop과 backlog
tc -s qdisc show dev eth0

ethtool -S의 카운터 이름은 드라이버마다 다르다. 절대값 하나보다 테스트 전후 delta를 기록한다. CRC·frame error는 물리 계층을, missed·no buffer·FIFO drop은 수신 큐나 처리 지연을, qdisc drop은 송신 queue 압력을 의심하게 한다.

CPU, interrupt, RSS

mpstat -P ALL 1
sar -n SOFT 1
cat /proc/interrupts
cat /proc/net/softnet_stat

Linux의 RSS는 NIC가 flow hash를 사용해 여러 receive queue와 CPU로 패킷 처리를 분산한다. RPS는 소프트웨어에서 CPU를 선택하고, RFS는 애플리케이션이 실행되는 CPU와 flow 처리를 가깝게 하며, XPS는 송신 queue 선택을 조정한다. 전체 CPU 사용률이 25%여도 한 코어의 softirq가 100%면 단일 흐름이나 queue가 병목일 수 있다.

설정 변경 전에는 다음을 비교한다.

ethtool -l eth0                  # 현재/최대 channel 수
ethtool -x eth0                  # RSS indirection table
cat /proc/irq/*/smp_affinity_list

channel, ring, coalescing, offload를 한꺼번에 바꾸지 않는다. 한 항목씩 변경하고 동일한 테스트를 반복해야 인과관계를 설명할 수 있다.

클라우드 인스턴스 한도

AWS ENA 드라이버는 ethtool -S를 통해 allowance 초과 카운터를 제공한다.

ethtool -S eth0 | grep -E \
  'bw_(in|out)_allowance_exceeded|pps_allowance_exceeded|conntrack_allowance'

NIC link가 10Gbps로 보이더라도 인스턴스 타입의 baseline, burst, 방향별·aggregate 한도는 더 낮을 수 있다. 클라우드에서는 guest OS 지표와 provider allowance 지표를 같은 사건의 증거로 묶어야 한다.


증상별 병목 판단표

관찰가능성이 높은 원인다음 확인
단일 TCP만 느리고 -P 4는 빠름BDP/window, 한 흐름 CPU, RSS 분산ss -ti, 코어별 softirq, iperf3 버전
정방향만 느리고 역방향은 정상방향별 경로·한도, 송신/수신 NIC 설정 차이-R, 양쪽 ethtool -S, route
TCP retransmit가 급증하며 goodput 하락loss, queue drop, MTU, congestionsar -n EDEV,ETCP, tc -s, pmtu
UDP bitrate를 올릴 때 loss가 갑자기 시작bandwidth 또는 PPS ceiling, queue 부족패킷 크기 변경, ENA allowance, ring drop
iperf3는 빠르고 fio만 느림스토리지·파일시스템 병목fio latency, iostat, device queue
fio와 iperf3가 각각은 빠르고 동시 실행만 느림CPU, NUMA, memory bandwidth, VM aggregate 한도mpstat, interrupts, NUMA 배치, cgroup
ping은 정상인데 TCP 처리량이 낮음ICMP와 다른 queue/policy, BDP, 단일 흐름iperf3 정·역방향, ss -ti, firewall/qdisc
retransmit 없이 앱만 느림DB query, TLS, connection pool, 애플리케이션 backpressure앱 tracing, DB wait, pool queue

ping 성공은 경로가 완전히 건강하다는 뜻이 아니다. ICMP가 애플리케이션 TCP와 다른 정책·queue를 통과하거나 낮은 부하에서만 정상일 수 있다. 반대로 ICMP가 rate limit되어도 TCP는 정상일 수 있다.


MTU와 offload를 의심할 때

큰 전송만 실패하거나 VPN·overlay 경로에서 처리량이 불안정하면 path MTU를 확인한다.

# 커널이 현재 연결에 추정한 pmtu
ss -tin dst 10.20.0.12

# IPv4에서 단편화 금지 상태로 크기를 단계적으로 확인
ping -M do -s 1472 10.20.0.12

# iperf3 MSS를 낮춰 비교
iperf3 -c 10.20.0.12 -M 1360 -t 30 -O 3

표준 Ethernet MTU 1500에서 IPv4 ICMP payload 1472는 IP 20bytes와 ICMP 8bytes를 더해 1500이 된다. 터널 헤더가 추가되면 허용 payload는 더 작아진다. 숫자를 그대로 복사하지 말고 실제 overlay와 IPv4/IPv6 헤더를 기준으로 계산한다.

TSO/GSO/GRO 같은 offload는 CPU 사용량을 줄이고 처리량을 높일 수 있다. 패킷 캡처에서 큰 세그먼트가 보인다는 이유만으로 장애라고 판단하지 않는다. 테스트를 위해 offload를 끌 때는 영향 범위와 원복 명령을 준비하고 한 기능씩 비교한다.

ethtool -k eth0
# 예: 검증된 점검 창에서만 한 항목 변경
ethtool -K eth0 tso off
# 반드시 원복
ethtool -K eth0 tso on

재현 환경에서 지연과 손실을 주입하기

복제나 백업이 지연·손실에 어떻게 반응하는지 확인할 때 Linux netem으로 test namespace 또는 전용 테스트 호스트에 조건을 만들 수 있다.

# 테스트 환경 전용: 20ms 지연, 5ms jitter, 0.1% loss
sudo tc qdisc add dev eth0 root netem delay 20ms 5ms loss 0.1%

# 상태 확인
sudo tc -s qdisc show dev eth0

# 즉시 원복
sudo tc qdisc del dev eth0 root

netem은 delay, loss, corruption, duplication, reordering, rate 제한을 지원한다. SSH 관리 인터페이스에 잘못 적용하면 접속을 잃을 수 있으므로 프로덕션에서 즉흥적으로 실행하지 않는다. 테스트 namespace, 별도 NIC, 콘솔 접근, 자동 원복 타이머를 준비한다.


30분 병목 진단 런북

0~5분: 범위 고정

5~12분: 네트워크 기준선

12~20분: 경계 분리

20~27분: 가설 검증

27~30분: 원복과 기록


흔한 실패 패턴

iperf3 -P 16 결과만 보고 링크가 정상이라고 결론

다중 흐름은 aggregate 상한을 보여 주지만 실제 DB 복제나 한 개 백업 stream의 성능을 보장하지 않는다. 단일 흐름과 다중 흐름을 둘 다 남긴다.

평균 처리량만 저장

60초 평균이 같아도 5초간 0에 가까운 구간이 있으면 복제 lag와 tail latency는 크게 증가한다. 1초 interval, JSON, 시스템 metric을 함께 저장한다.

양 끝 중 한쪽만 본다

송신 측 retransmit만으로 drop 위치를 알 수 없다. 수신 NIC의 no-buffer, 중간 qdisc, 클라우드 allowance, 반대편 CPU를 함께 봐야 한다.

fio 결과를 네트워크 성능으로 해석

fio는 storage workload를 정밀하게 만드는 도구다. net engine이 있어도 TCP 경로 진단은 iperf3가 더 직접적이다. 두 도구의 역할을 섞지 말고 경계를 분리한 뒤 결합한다.

테스트가 프로덕션 장애를 만든다

대역폭·PPS·디스크 queue를 모두 채우는 테스트는 실제 서비스와 복제 트래픽을 밀어낼 수 있다. 목표 bitrate, 실행 시간, 중단 조건, 원복 절차를 먼저 정한다.


핵심 요약


References