Linux 네트워크 성능 분석 순서: TCP 큐·오프로드·qdisc 확인하기

반응형

Linux 네트워크가 느릴 때는 용어를 많이 아는 것보다 데이터가 어느 큐에서 기다리고 어느 계층에서 다시 보내지는지를 순서대로 확인하는 편이 유용하다. 애플리케이션 → 소켓 → TCP → qdisc → NIC → 네트워크 경로로 내려가며 같은 시각의 지표를 모으면 “네트워크가 느리다”는 증상을 구체적인 후보로 바꿀 수 있다.

브렌던 그렉의 시스템 성능 관점으로 네트워크 용어를 정리하다 보니 ICMP, CIDR, 쿠키, backlog와 오프로드가 한 글에 섞였다. 다시 보니 이 개념들은 같은 진단 단계에 있지 않았다. 여기서는 Linux 호스트의 지연·손실·연결 실패를 좁히는 흐름에 필요한 내용만 남긴다.

증상을 먼저 네 종류로 나눈다

측정 전에 사용자가 겪는 실패를 구분한다.

  1. 연결 자체가 느리거나 실패한다: SYN queue, accept queue, 방화벽, DNS와 경로를 본다.
  2. 연결 뒤 응답이 느리다: 애플리케이션 off-CPU, socket buffer, RTT와 재전송을 본다.
  3. 처리량만 낮다: cwnd·rwnd, 손실, RTT, NIC와 qdisc를 본다.
  4. 부하가 있을 때만 지연이 튄다: queueing delay와 bufferbloat를 의심한다.

평균 응답 시간 하나만 보면 이 네 문제가 섞인다. 요청 시작 시각, 연결 시간, 첫 바이트와 전체 전송 시간을 나눠 기록한다.

전체 데이터 경로를 한 번에 그린다

송신 경로를 단순화하면 다음과 같다.

애플리케이션 write()
→ TCP 송신 버퍼
→ 혼잡·수신 윈도우
→ qdisc
→ NIC 드라이버와 하드웨어 큐
→ 링크와 라우터
→ 상대 호스트

수신 쪽은 반대 방향으로 NIC에서 커널 socket receive buffer를 거쳐 애플리케이션의 read()로 올라온다.

계층 대표 질문 먼저 볼 도구
애플리케이션 CPU를 쓰는가, I/O·락을 기다리는가 profiler, tracing, off-CPU 분석
listen socket 연결을 accept하지 못하고 쌓였는가 ss -lntp
established TCP RTT·재전송·윈도우가 어떻게 변하는가 ss -tin
qdisc 송신 큐에 backlog·drop이 생기는가 tc -s qdisc
NIC error·drop·offload 상태가 어떤가 ip -s link, ethtool
경로 손실·MTU·홉 변화가 있는가 ping, tracepath, packet capture

한 도구의 한 시점 출력만으로 원인을 확정하지 않는다. 같은 부하 구간에서 애플리케이션 지연과 호스트·네트워크 지표의 변화가 맞물리는지 본다.

연결 실패는 listen queue부터 본다

ss -lntp

LISTEN socket에서 queue가 설정된 한계에 계속 가까워지면 애플리케이션이 완성된 연결을 충분히 빨리 accept()하지 못하는지 확인한다. listen()의 backlog는 Linux에서 주로 완성된 연결의 대기열에 영향을 받고 net.core.somaxconn의 상한을 받는다. SYN이 아직 완성되지 않은 연결은 별도의 정책과 tcp_max_syn_backlog 영향을 받는다.

sysctl net.core.somaxconn
sysctl net.ipv4.tcp_max_syn_backlog
sysctl net.ipv4.tcp_syncookies

queue가 찬다고 설정값만 늘리면 대기 공간이 커질 뿐 처리율 병목은 남을 수 있다. 다음을 함께 확인한다.

  • accept loop와 worker가 CPU·락·GC에 막히는가
  • 프로세스 file descriptor 제한에 닿았는가
  • upstream load balancer의 재시도와 연결 폭주가 있는가
  • SYN flood 또는 비정상적인 연결 패턴인가

SYN cookie는 SYN queue 고갈을 완화하는 방어 수단이지 완성된 연결 폭주나 느린 애플리케이션을 해결하는 기능은 아니다.

연결된 TCP는 ss -tin으로 읽는다

ss -tin dst 203.0.113.10

ss -i는 Linux TCP 내부 정보에서 다음 값을 보여 줄 수 있다.

  • rttrttvar: 왕복 시간과 변동
  • rto: 재전송 timeout
  • retrans: 재전송 관련 상태
  • cwnd: 혼잡 윈도우
  • ssthresh: slow start threshold
  • wscale: 송·수신 윈도우 scale
  • pmtu: 추정한 path MTU
  • send: 추정 송신률

송신자가 새로 보낼 수 있는 양은 수신자가 광고한 윈도우와 혼잡 제어가 허용하는 윈도우의 제약을 모두 받는다.

실제 전송 가능량 ≈ min(rwnd, cwnd)에서 이미 미확인인 데이터 제외

cwnd가 작다고 혼잡 제어만 탓하지 않는다. 애플리케이션이 데이터를 충분히 쓰지 않는지, 수신 윈도우가 닫히는지, RTT·손실과 재전송이 같이 변하는지 봐야 한다. TCP 혼잡 제어의 단계는 cwnd·slow start·fast recovery에서 더 자세히 정리했다.

qdisc에서 대기와 drop을 확인한다

Linux 송신 경로의 queueing discipline(qdisc)은 패킷을 언제 NIC로 보낼지 결정한다.

tc -s qdisc show dev eth0

부하 전후의 backlog, dropped, overlimits, requeues를 비교한다. 출력 필드와 의미는 qdisc 종류에 따라 다르므로 숫자 하나를 모든 환경에서 같은 뜻으로 해석하지 않는다.

부하가 없을 때 RTT가 낮은데 업로드나 다운로드 중 RTT가 크게 오르면 bufferbloat 후보가 된다. 큰 unmanaged queue는 손실을 늦추는 대신 패킷을 오래 기다리게 할 수 있다.

FQ-CoDel은 flow queueing과 CoDel active queue management를 결합한다. CoDel은 queue 길이만이 아니라 패킷이 머문 시간을 이용해 지속적인 지연을 감지한다. Linux의 BQL(Byte Queue Limits)은 더 아래의 device driver ring에 과도한 바이트가 쌓이지 않도록 돕는다.

그렇다고 모든 서버에 fq_codel을 즉시 설정하면 되는 것은 아니다. 실제 병목 링크가 호스트 바깥에 있거나, 클라우드 가상 NIC·traffic shaping 구조가 다르면 효과와 설정 지점이 달라진다. 먼저 어느 인터페이스와 계층에서 queue가 생기는지 측정한다.

NIC error와 drop을 분리한다

ip -s link show dev eth0
ethtool -S eth0

확인할 항목은 드라이버와 장치마다 이름이 다르지만 다음 범주로 나눌 수 있다.

  • RX/TX packet과 byte 증가량
  • error, dropped, missed, timeout
  • ring buffer 또는 queue별 drop
  • link speed·duplex와 carrier 변화

counter는 누적값이다. 값이 0이 아닌 사실보다 문제 구간에서 증가하는 속도가 중요하다. 컨테이너·bond·bridge·가상 NIC를 쓰면 애플리케이션이 보는 인터페이스와 실제 물리 NIC를 모두 따라가야 한다.

오프로드 때문에 packet capture가 다르게 보일 수 있다

ethtool -k eth0

TSO(TCP Segmentation Offload)는 큰 TCP payload를 NIC가 실제 송신 직전에 여러 frame으로 나누도록 맡긴다. GSO는 소프트웨어에서 비슷한 분할을 늦추고, GRO는 수신한 여러 패킷을 커널에서 큰 단위로 합친다.

이 때문에 호스트에서 캡처한 tcpdump에 MTU보다 큰 TCP segment처럼 보이는 데이터가 있어도 wire에 그 크기 그대로 나갔다고 단정할 수 없다. 캡처 지점이 분할 전이거나 병합 후일 수 있다.

tcpdump -ni eth0 host 203.0.113.10

오프로드를 끈 비교는 진단에 도움이 될 수 있지만 처리량과 CPU 사용에 영향을 준다. 운영 인터페이스에서 무심코 변경하지 말고 검증 환경이나 짧고 통제된 창에서 적용한다.

MTU와 경로 문제는 ICMP까지 본다

일반 Ethernet MTU 1500에서 IPv4·옵션 없는 TCP header를 빼면 흔히 MSS 1460을 떠올린다. 하지만 IPv6, TCP option, tunnel과 VPN encapsulation이 있으면 실제 값이 달라진다. 고정된 1460만 기준으로 삼지 않는다.

tracepath example.com
ping -c 10 example.com

Path MTU Discovery는 ICMP 메시지에 의존할 수 있다. ICMP를 일괄 차단하면 큰 패킷에서만 통신이 멈추는 black hole 문제가 생길 수 있다. ping 성공이 TCP 서비스의 정상 동작을 보장하지도 않는다. 실제 서비스의 주소·포트와 packet size를 기준으로 본다.

traceroute 결과도 경로의 힌트다. ECMP, 정책 라우팅, ICMP rate limit과 비대칭 경로 때문에 요청마다 또는 방향마다 다를 수 있다. IP 경로 선택 자체는 라우팅과 포워딩 차이에서 이어서 볼 수 있다.

on-CPU와 off-CPU를 네트워크 지표와 맞춘다

요청이 200ms이고 CPU time이 5ms라면 남은 시간을 모두 네트워크라고 부를 수는 없다. socket read, DNS, TLS, connection pool, lock, scheduler run queue와 downstream 응답 대기가 섞일 수 있다.

trace에서 다음 구간을 나눈다.

DNS
→ TCP connect
→ TLS handshake
→ connection pool 대기
→ 요청 전송
→ first byte 대기
→ body 수신
→ 애플리케이션 처리

호스트의 ss, tc, NIC counter를 같은 시간축에 놓았을 때 RTT·재전송·queue 증가가 보이지 않으면 애플리케이션이나 downstream 처리부터 다시 본다. 시스템 성능의 관측·실험 순서는 시스템 성능 엔지니어링 1장 노트와 연결된다.

최소 진단 체크리스트

# listen queue와 프로세스
ss -lntp

# 연결별 RTT, RTO, cwnd, 재전송
ss -tin

# qdisc 상태
tc -s qdisc show dev eth0

# 인터페이스·드라이버 통계
ip -s link show dev eth0
ethtool -S eth0

# offload 상태
ethtool -k eth0

# 경로와 MTU 힌트
tracepath example.com

이 명령은 원인을 자동으로 알려 주는 체크박스가 아니다. 문제 전후의 변화, 애플리케이션 trace와 요청 특성을 함께 모을 때 의미가 생긴다. 네트워크 성능 분석의 핵심은 모든 용어를 한 번에 외우는 것이 아니라 기다림이 시작되는 첫 계층을 찾는 것이다.

참고 자료

반응형
KEEP READING
카테고리 전체 보기 →

댓글