게임 렉 백서 › L7 서버 OS (커널)
커널 소켓 버퍼 부족 Small socket buffers
원인 ID so-sockbuf · 주 담당 인프라팀·서버 인프라 · 함께 게임개발팀·서버 개발
그림과 실험이 있는 원본 카드로 열기 →
송수신 버퍼가 작으면 버스트 트래픽이 몰릴 때 UDP로 받은 패킷은 버려지고, TCP 송신은 버퍼에 여유가 없어 막힙니다.
왜 SO_SNDBUF·SO_RCVBUF가 기본값이거나 너무 작음 → 그러면 버스트나 받는 스레드가 잠깐 멈춘 사이 UDP 수신 버퍼가 넘쳐 폐기, TCP는 송신 버퍼에 여유가 없어 대기 → 화면에서는 순간이동(UDP 손실) 또는 몰아치기(TCP 대기)
- 증상
- 순간이동, 몰아치기
- 요인
- 손실, 정체
- 누가 겪나
- 서버 전체
- 언제
- 사람이 몰릴 때
- 담당
- 주 담당 인프라팀·서버 인프라 · 함께 게임개발팀·서버 개발
- 게임개발팀 할 일
- 트래픽에 맞춘 버퍼 크기(SO_SNDBUF·SO_RCVBUF)를 코드에서 설정, TCP는 크기를 직접 정하면 리눅스의 자동 크기 조절이 꺼지니 주의, 너무 크게 잡으면 오래된 데이터가 버퍼에 쌓여 지연이 늘어나니 적당히, 받는 스레드가 멈추지 않게.
- 인프라팀 할 일
- 커널 상한(rmem_max·wmem_max. 코드에서 정한 버퍼 크기도 이 값을 넘지 못함)과 기본값(rmem_default) 조정, 버퍼 넘침 카운터(RcvbufErrors) 감시.
- 수치 감각
- 리눅스 UDP 수신 버퍼 기본값은 약 208KB입니다. 작은 패킷도 한 개가 커널 메모리를 실제 크기보다 훨씬 많이 차지해 수십~수백 개면 찹니다. 초당 10만 개를 받는 서버라면 받는 스레드가 몇 ms만 멈춰도 넘칩니다.
- 그래프에서는
- 가끔 무작위로 튐 · UDP 수신 버퍼 넘침(UdpRcvbufErrors)
- 확인할 곳
- nstat -az의 UdpRcvbufErrors 증가량과 ss -uamn의 skmem(rb는 수신 버퍼 크기, d는 소켓에 넣지 못하고 버린 패킷 수)을 보고 TCP는 ss -tm의 skmem에서 송신 대기 메모리(w)가 송신 버퍼 크기(tb)에 닿았는지 봄
- 이러면 맞음
- 버스트나 받는 스레드가 멈춘 시각에 UdpRcvbufErrors(또는 소켓의 d)가 늘고, rb가 기본값(약 208KB) 근처. TCP는 w가 tb에 붙은 채 send가 막힘
- 이러면 아님
- 카운터가 그대로인데 손실이 있으면 NIC 단계(“링 버퍼 부족”)나 네트워크 구간
- 확인 수단
- 인프라 도구로 확인(게임 코드 불필요)
출처
- socket(7) — Linux manual page Linux man-pages
SO_RCVBUF·SO_SNDBUF 기본값은 rmem_default·wmem_default, 상한은 rmem_max·wmem_max, 설정값은 커널이 두 배로 잡음 - include/net/sock.h (Linux v6.18) Linux kernel
기본 소켓 버퍼를 sk_buff 오버헤드를 포함한 256바이트 패킷 256개분(SKB_TRUESIZE(256)×256)으로 정의, 작은 프레임도 sk_buff+MTU만큼 계산됨(약 208KB는 x86-64 기준 계산값) - IP Sysctl Linux kernel
tcp_rmem·tcp_wmem: SO_RCVBUF·SO_SNDBUF를 직접 정하면 그 소켓의 자동 크기 조절이 꺼짐 - net/ipv4/udp.c (Linux v6.12) Linux kernel
UDP 수신 대기열이 소켓 버퍼 크기를 넘으면 곧바로 버리고 RcvbufErrors를 올림 - net/ipv4/proc.c (Linux v6.12) Linux kernel
nstat이 보여 주는 카운터 이름: Udp 그룹의 RcvbufErrors·SndbufErrors - ss(8) — Linux manual page iproute2
-m의 skmem: rb 수신 버퍼 크기, tb 송신 버퍼 크기, w 송신 대기 메모리, d 소켓에 넣기 전 버린 패킷 수
함께 보면 좋은 원인
같은 층: L7 서버 OS (커널)
같은 증상(순간이동)의 다른 층 원인
그림과 실험이 있는 원본 카드 보기