게임 렉 백서 › L8 소켓과 프로토콜
느린 클라이언트로 인한 블로킹 전송 Blocking send on a full socket
원인 ID sk-block-send · 주 담당 게임개발팀·서버 개발
그림과 실험이 있는 원본 카드로 열기 →
회선이 느린 한 명의 송신 버퍼가 가득 찼는데 블로킹 방식(버퍼에 여유가 생길 때까지 호출이 반환되지 않는 전송)으로 보내면, 서버 스레드가 그 한 명을 기다립니다.
왜 느린 클라이언트의 송신 버퍼가 가득 → 그러면 블로킹 전송이라 서버 스레드가 버퍼에 여유가 생길 때까지 대기 → 화면에서는 그 스레드가 맡은 모두가 멈춤·슬로우모션
- 증상
- 멈춤, 슬로우모션
- 요인
- 정체
- 누가 겪나
- 특정 장소·채널, 서버 전체
- 언제
- 가끔 무작위로, 사람이 몰릴 때
- 담당
- 주 담당 게임개발팀·서버 개발
- 게임개발팀 할 일
- 논블로킹 전송, 클라이언트별 송신 대기열 상한, 오래된 업데이트 버리기.
- 그래프에서는
- 가끔 무작위로 튐 · 서버 틱 시간, 연결별 Send-Q
- 확인할 곳
- ss -tn으로 연결별 Send-Q(ACK를 받지 못했거나 아직 못 보낸 바이트)가 송신 버퍼만큼 찬 연결을 찾고, 틱이 튄 순간 게임 서버의 스레드 덤프(스택)에서 send 호출에 멈춘 스레드가 있는지 봄
- 이러면 맞음
- Send-Q가 가득 찬 느린 연결이 있을 때 그 연결을 맡은 스레드가 send에서 멈춰 있고, 같은 스레드가 맡은 사람들만 함께 멈춤
- 이러면 아님
- 멈춘 스레드가 send 밖(락, DB 호출)에서 기다리면 “락 경합”, “게임 스레드의 동기 호출”
- 확인 수단
- 인프라 도구로 확인(게임 코드 불필요)
출처
- send(2) — Linux manual page Linux man-pages
송신 버퍼에 자리가 없으면 send()가 블록되고 논블로킹 모드면 EAGAIN으로 바로 돌아옴 - send function (winsock2.h) Microsoft
Winsock도 버퍼 공간이 없으면 논블로킹 모드가 아닌 한 send가 블록 - net/ipv4/tcp_diag.c (Linux v6.12) Linux kernel
ss의 Recv-Q·Send-Q 값: 리슨 소켓은 accept를 기다리는 접속 수와 backlog 한도, 연결된 소켓은 앱이 아직 안 읽은 바이트와 ACK를 받지 못한 송신 바이트
함께 보면 좋은 원인
같은 층: L8 소켓과 프로토콜
같은 증상(멈춤)의 다른 층 원인
그림과 실험이 있는 원본 카드 보기