한국어English日本語简体中文繁體中文DeutschไทยTiếng ViệtРусскийPortuguês (Brasil)EspañolBahasa Indonesia

게임 렉 백서 › TCP 재전송의 근본 원인

thin stream의 느린 복구 Thin streams fall back to RTO

원인 ID rt-thin · 주 담당 게임개발팀·서버 개발 · 함께 인프라팀·서버 인프라, 게임개발팀·클라이언트 개발

그림과 실험이 있는 원본 카드로 열기 →

게임처럼 작은 패킷을 드문드문 보내면 “뒤따르는 패킷 3개”가 모이기 전에 RTO가 먼저 옵니다. 대용량 전송보다 같은 손실에 훨씬 오래 멈춥니다.

왜 패킷 간격이 100ms 안팎이라 아직 ACK를 받지 못한(in-flight) 패킷이 몇 개 없음 → 그러면 중복 ACK 3개가 모이려면 300ms 넘게 걸려 RTO(핑 + 200ms)가 먼저 발동, 연속 손실이면 두 배씩 → 화면에서는 손실 한 번에 0.3초 안팎 멈춤, 다시 보낸 것까지 잃으면 1초 가까이 멈춘 뒤 몰아치기

증상
멈춤, 몰아치기
요인
손실, 정체
누가 겪나
나만, 서버 전체
언제
가끔 무작위로
담당
주 담당 게임개발팀·서버 개발 · 함께 인프라팀·서버 인프라, 게임개발팀·클라이언트 개발
게임개발팀 할 일
서버: TCP_NODELAY 켜기(Nagle이 켜져 있으면 RACK이 판단에 쓸 뒤따르는 패킷이 없음), 실시간 패킷은 UDP 위의 자체 재전송으로. 클라이언트: TCP_NODELAY 켜기, 실시간 패킷은 서버와 같은 방식(UDP)으로.
인프라팀 할 일
RACK-TLP 사용(최신 리눅스 기본), tcp_thin_linear_timeouts로 연속 RTO가 두 배로 늘지 않게.
수치 감각
패킷 간격 100ms, 핑 60ms면 빠른 재전송까지 약 360ms(뒤 패킷 3개가 도착하고 그 확인이 돌아올 때까지), RTO는 약 260ms. RACK을 쓰면 다음 패킷의 확인이 돌아오는 약 160ms에 바로 다시 보냅니다. 패킷 간격이 200ms를 넘으면 RACK도 RTO보다 빠르지 않습니다.
그래프에서는
끊겼다가 몰아서 · 연결별 수신량, RTO 만료 수
확인할 곳
nstat의 TcpExtTCPTimeouts(RTO 만료)·TcpExtTCPFastRetrans(빠른 재전송)·TcpExtTCPLossProbes·TcpExtTCPLossProbeRecovery(TLP) 증가분을 비교하고, 게임 연결을 ss -ti로 보아 rto·backoff를 봄. 서버의 net.ipv4.tcp_recovery·tcp_early_retrans·tcp_sack 값도 확인함
이러면 맞음
재전송 가운데 RTO 만료가 빠른 재전송보다 많고 게임 연결에서 backoff가 0보다 큰 경우(RTO를 겪는 중)가 자주 보임. 멈춘 동안 받은 양이 0이다가 복구되면 한꺼번에 몰려옴
이러면 아님
같은 서버의 대용량 전송도 똑같이 오래 멈추면 연결 모양과 상관없는 손실 문제. SACK·타임스탬프가 빠진 연결에 몰리면 “중간 장비의 TCP 옵션 제거”
확인 수단
인프라 도구로 확인(게임 코드 불필요)
더 알아보기
리눅스에는 예전에 thin stream용 중복 ACK 1개 재전송 옵션(tcp_thin_dupack)도 있었지만 2017년에 없어졌고, 지금은 RACK이 그 역할을 대신합니다. Nagle이 켜져 있으면(TCP_NODELAY 꺼짐) 잃은 패킷의 확인을 기다리는 동안 새 패킷도 보내지 않습니다. RACK이 판단에 쓸 뒤따르는 패킷이 없으니 RTO까지 기다립니다.

출처

  1. Thin-streams and TCP Linux kernel
    게임처럼 드문드문 보내는 thin stream은 빠른 재전송이 잘 작동하지 않아 긴 타임아웃에 기댐, 아직 ACK를 받지 못한 패킷(in-flight) 4개 미만이 기준
  2. RFC 5681: TCP Congestion Control IETF
    세 번째 중복 ACK에서 빠른 재전송
  3. RFC 8985: The RACK-TLP Loss Detection Algorithm for TCP IETF
    RACK은 뒤에 보낸 패킷이 전달된 것으로 손실을 판단, TLP 대기는 2·SRTT(확인받지 못한 패킷이 하나뿐이면 지연 ACK 여유를 더함)
  4. include/net/tcp.h Linux kernel
    TCP_RTO_MIN 200ms, thin stream 판정(in-flight 패킷 4개 미만)과 선형 재시도 6번
  5. tcp: remove thin_dupack feature Linux kernel
    2017년 1월 thin_dupack 삭제(리눅스 4.11), RACK이 그 역할을 대신한다는 설명
  6. IP Sysctl Linux kernel
    tcp_thin_linear_timeouts: thin stream이면 최대 6번까지 RTO를 두 배로 늘리지 않음(기본 꺼짐)
  7. tcp(7) — Linux manual page Linux man-pages
    TCP_NODELAY는 Nagle 알고리즘을 끔
  8. net/ipv4/proc.c Linux kernel
    nstat에 나오는 카운터 이름 TCPTimeouts·TCPFastRetrans·TCPLossProbes·TCPLossProbeRecovery
  9. net/ipv4/tcp_timer.c Linux kernel
    TCPTimeouts는 재전송 타이머(RTO)가 만료될 때 증가
  10. SNMP counter Linux kernel
    TcpExtTCPFastRetrans(Loss 상태가 아닐 때의 재전송), TcpExtTCPLossProbes(TLP를 보냄)·TcpExtTCPLossProbeRecovery(TLP로 손실을 복구)
  11. ss(8) — Linux manual page iproute2
    ss -i의 rto(ms), backoff(RTO가 두 배로 늘어난 횟수)

함께 보면 좋은 원인

같은 층: TCP 재전송의 근본 원인

같은 증상(멈춤)의 다른 층 원인

그림과 실험이 있는 원본 카드 보기