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

게임 렉 백서 › L9 서버 게임 프로세스

스레드 풀 고갈 Thread pool starvation

원인 ID sp-threadpool · 주 담당 게임개발팀·서버 개발

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

작업을 처리할 워커 스레드가 모두 느린 작업에 묶이면 새 요청은 무작정 기다립니다.

왜 워커 스레드들이 외부 API·DB 응답을 기다리며 묶임 → 그러면 새 요청이 배정받을 스레드가 없음 → 화면에서는 로그인·상점 등 특정 기능 무한 로딩

증상
접속 불가·무한 로딩, 입력 지연, 멈춤
요인
정체
누가 겪나
특정 기능만, 서버 전체
언제
사람이 몰릴 때, 접속·점검 직후
담당
주 담당 게임개발팀·서버 개발
게임개발팀 할 일
느린 호출에 타임아웃, 기능별 스레드 풀 분리, 비동기화.
그래프에서는
한도에 닿아 평평해짐 · 스레드 풀 스레드 수·대기열 길이, 요청 처리 시간
확인할 곳
.NET은 dotnet-counters monitor의 스레드 풀 스레드 수와 대기열 길이(.NET 9 이후 dotnet.thread_pool.thread.count·dotnet.thread_pool.queue.length, 8 이하 ThreadPool Thread Count·ThreadPool Queue Length)를 보고, dotnet-stack으로 워커 스레드들이 어디서 기다리는지 확인. JVM·네이티브 서버는 스레드 덤프로 같은 것을 확인
이러면 맞음
CPU 사용률은 100%보다 한참 낮은데 스레드 수가 천천히 계속 늘거나 상한에 붙어 있고, 대기열이 쌓이며 워커 대부분이 같은 외부 호출(DB·HTTP) 응답을 기다림
이러면 아님
대기열이 비어 있는데도 느리면 호출 대상 자체가 느린 것이라 연쇄 장애·외부 서비스 의존 쪽
확인 수단
인프라 도구로 확인(게임 코드 불필요)
더 알아보기
패킷 받기와 게임 로직이 같은 워커 스레드 풀을 나눠 쓰는 구조라면, 느린 작업 몇 개가 워커를 모두 점유하는 순간 서버 전체의 패킷 처리가 멈춥니다.
실제 사례
Riot Games 2021: League of Legends EUW 5시간 장애: 부가 DB 하나가 서버 전체를 멈춤

출처

  1. Debug ThreadPool Starvation Microsoft
    풀에 남은 스레드가 없어 새 작업이 대기하면 응답이 느려짐, 스레드를 점유하는 블로킹 코드가 원인. dotnet-counters에서 CPU는 100%보다 한참 낮은데 dotnet.thread_pool.thread.count가 천천히 계속 늘면 고갈 신호(dotnet.thread_pool.queue.length도 큰 경우가 많음), dotnet-stack으로 스레드가 기다리는 곳 확인
  2. Avoiding insurmountable queue backlogs AWS
    동시 처리 수 = 도착률 × 지연(리틀의 법칙). 초당 100건에서 지연이 100ms에서 10초로 늘면 스레드 10개가 1,000개로 늘어 풀이 고갈
  3. Bulkhead Pattern Microsoft Azure
    호출 대상마다 커넥션·스레드 풀을 따로 두면 한 대상의 장애가 그 풀만 막음
  4. .NET runtime metrics .NET
    dotnet.thread_pool.thread.count(스레드 풀 스레드 수)·dotnet.thread_pool.queue.length(대기 중인 작업 수)는 .NET 9부터
  5. Well-known EventCounters in .NET Microsoft
    .NET 8 이하의 ThreadPool Thread Count(threadpool-thread-count)·ThreadPool Queue Length(threadpool-queue-length)

함께 보면 좋은 원인

같은 층: L9 서버 게임 프로세스

같은 증상(접속 불가·무한 로딩)의 다른 층 원인

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