1:21 · threads · tick loop · message queue · AOI

서버 안의 50ms, 무슨 일이 일어날까?

MMO 게임서버가 패킷을 받아 처리하고 다시 내보내는 스레드 구조와, 로직 스레드가 50ms마다 반복하는 틱 루프를 보여준다. 큐 적체, 인원 밀집, DB·락·GC 대기가 각각 어떻게 틱을 늦추는지 설명하고, 구간마다 어떤 지표를 봐야 하는지 정리한다. 틱 하나의 길이는 단계마다 걸린 시간의 합이고, 전체 처리량은 가장 느린 구간이 정한다.

01스레드 구조

받고, 줄 세우고, 처리하고, 보낸다 · ▶ 이 장면 보기

화면 왼쪽의 클라이언트에서 들어온 패킷은 I/O 스레드(IO #1~IO #4)가 받아 수신, 복호화, 역직렬화를 한다. 해석된 메시지는 존마다 하나씩 있는 메시지 큐에 쌓이고, 존당 1개인 로직 스레드(Zone A, Zone B, Zone C)가 틱 루프 안에서 이를 꺼내 처리한다. 처리 결과는 송신 큐에서 직렬화되고 묶인 뒤, I/O 송신 단계에서 암호화되어 오른쪽 클라이언트로 나간다.

DB 작업은 로직 스레드가 직접 기다리지 않는다. 별도의 DB · 비동기 워커에 요청을 넘기고, 결과는 다시 메시지 형태로 존 큐에 들어온다.

한 존의 상태는 한 스레드만 순서대로 만지므로 존 내부에서는 락이 필요 없다. 그 대신 그 스레드가 어떤 이유로든 막히면 존 전체가 같이 멈춘다. 뒤 챕터에서 다루는 지연은 대부분 이 특성과 연결된다.

02틱 루프

로직 스레드는 50ms마다 같은 일을 반복한다 · ▶ 이 장면 보기

틱레이트가 20Hz이면 틱 하나에 쓸 수 있는 예산은 50ms다. 화면에는 Tick N, N+1, N+2가 같은 패턴으로 반복된다.

마지막 대기 시간이 서버의 여유분이다. 이 값이 0이 되면 다음 틱이 제시간에 시작하지 못하고 밀리기 시작한다.

03큐가 밀릴 때

들어오는 속도가 처리 속도를 넘는 순간 · ▶ 이 장면 보기

왼쪽 패널은 Zone A의 메시지 큐다. 처음에는 유입 800/s, 처리 1,000/s로 큐 깊이가 40개 안팎에서 유지된다. 유입이 1,420/s로 늘면 처리량을 넘어서고, 큐 깊이가 수천 개로 계속 늘어난다. 화면의 대기 시간은 큐 깊이 ÷ 처리량으로 계산되며 약 3초까지 올라간다.

오른쪽 그래프는 틱 처리시간이다. 처음에는 50ms 예산선 아래인 30ms대에 있다가, 적체가 시작되면 예산을 넘어 최대 175ms까지 올라가고 틱레이트 표시는 20Hz에서 6Hz 수준으로 떨어진다.

틱이 늦게 시작하면 그 사이 메시지가 더 쌓이고, 다음 틱은 더 많은 일을 해야 한다. 유입이 처리량을 넘는 동안 이 악순환이 이어지면 존 전체 서버렉, 메모리 증가, 결국 서버 다운으로 간다. 이 상황은 큐 깊이, 큐 대기시간, 틱 p99, 틱레이트 지표로 드러난다.

04AOI · 브로드캐스트 폭발

모이는 인원의 제곱으로 늘어나는 비용 · ▶ 이 장면 보기

왼쪽은 시야 안 인원 N이 6명에서 60명까지 늘어나는 모습이고, 오른쪽은 틱당 브로드캐스트 갱신(메시지) 수를 N × (N − 1) 곡선으로 그린다. 각 플레이어의 변화를 나머지 모두에게 보내야 하므로, 60명이 모이면 틱당 3,540개, 20Hz 기준 초당 70,800개가 된다. 갱신은 세션마다 틱당 하나로 묶어 보내므로 패킷 수는 N × 20 수준이고, 인원의 제곱으로 느는 것은 바이트다. N이 40명을 넘으면 송신 큐 상태 표시가 송신 큐 적체로 바뀐다.

비용이 인원의 제곱으로 늘기 때문에 공성전이나 월드보스처럼 한곳에 사람이 몰릴 때 문제가 된다. 송신 버퍼가 차면 서버 메모리가 늘고, 수신이 느린 클라이언트부터 강제로 끊긴다.

화면에 나오는 대응은 시야 반경 축소, 거리별 갱신 빈도 차등, 델타 압축이다.

05틱을 막는 것들

틱이나 응답을 멈추게 하는 대기 · ▶ 이 장면 보기

로직 스레드 바깥에서 생기는 대기 네 가지를 카드로 보여준다. 각 카드 아래 막대는 해당 상황에서 스레드가 어떻게 막히는지 그린 것이다.

06어디를 보나

구간마다 따로 재야 병목이 보인다 · ▶ 이 장면 보기

구간별로 볼 지표와 이상 신호를 표로 정리한다.

틱은 단계 시간의 합이고 처리량은 가장 느린 구간이 정하므로, 전체 평균 하나로는 병목을 찾기 어렵다. 구간마다 지표를 따로 두어야 어디서 막혔는지 구분할 수 있다.

이 영상에 나온 용어는 용어집에 정리했다.