11. 게임서버 관측성(Observability): 로깅·메트릭·트레이싱과 부하 테스트
난이도 중모범답안 — 게임서버 관측성: 로깅·메트릭·트레이싱과 부하 테스트
난이도: 중
1. 관측성의 세 기둥
- 로그(logs): 개별 사건의 시간순 기록. "이 시점에 무슨 일이 있었나?" 에 답한다. 디버깅·감사·사후 분석에 강하지만, 양이 많아 집계엔 부적합.
- 메트릭(metrics): 시간에 따라 집계된 수치(카운터/게이지/히스토그램). "전체적으로 얼마나 건강한가? 추세는?" 에 답한다. 저비용·고집계, 대시보드/알림의 기반. 대신 개별 요청의 세부는 잃는다.
- 트레이싱(traces): 한 요청이 여러 서비스/단계를 거치는 인과 경로를 span 으로 잇는다. "이 느린 요청이 어디서 시간을 썼나?" 에 답한다. 분산 시스템의 병목·실패 지점 규명.
구조적 로깅(structured logging): 로그를 평문 문자열이 아니라 키-값(JSON 등) 으로
남긴다({"evt":"reward_grant","player":123,"quest":45,"trace_id":"abc"}). 장점: 기계가
파싱·필터·집계·검색하기 쉽고(예: "player=123 의 모든 이벤트"), trace_id/요청 id 로 로그와
트레이스를 연결할 수 있다. 평문은 grep 은 되지만 구조화 질의·상관관계가 어렵다.
2. 게임서버 핵심 지표 (분포로 보기)
- 틱 타임 / 틱 예산 초과율: 한 틱(예: 50ms 목표) 처리 시간과, 예산을 넘긴 틱의 비율. 틱이 밀리면 모든 플레이어가 렉을 체감.
- RTT / 입력→반영 지연 분포: 네트워크 + 처리 지연. 체감 품질의 직결 지표.
- CCU(동시접속) / 존별 인원: 부하 분포와 핫스팟 파악.
- 패킷 처리율 / 드랍 / 송신 큐 적체: 백프레셔·과부하 신호.
- GC 일시정지(C#) 또는 할당률: 정지 시간이 틱을 잡아먹는다.
- (추가) 에러율 / 예외율 / DB·캐시 지연 / 큐 대기 시간.
왜 평균이 아니라 분포(p50/p95/p99)인가: 평균은 꼬리(tail)를 숨긴다. 평균 틱 20ms 라도 p99 가 120ms 면 상위 1% 틱에서 전체 존이 렉을 겪는다. 실시간 게임은 최악(꼬리) 지연이 체감을 좌우하므로 p95/p99/최댓값을 봐야 한다. 또 평균은 양봉 분포(정상 + 가끔 폭주)를 한 값으로 뭉개 오판을 부른다. 히스토그램/퍼센타일이 진실에 가깝다.
3. 분산 트레이싱: 전파
요청이 처음 들어오는 경계(게이트웨이)에서 trace id 를 생성하고, 각 단계는 span (시작/종료 시각, 태그)을 만들며 부모 span id 로 인과를 잇는다. 서버-서버 호출/메시지에는 trace context(trace id, span id)를 헤더/메타데이터로 전파한다(W3C Trace Context, OpenTelemetry 표준). 비동기 큐를 건너도 메시지에 컨텍스트를 실어 보내 끊기지 않게 한다.
예 — 결제 콜백 → 재화 지급: 결제 PG 콜백 수신 span → 멱등성 검사(DB) span → 지갑 갱신(DB 트랜잭션) span → 인벤토리/메일 발송 span. "아이템이 안 들어왔다" 문의가 오면 해당 플레이어의 trace 를 찾아, 어느 span 에서 실패/타임아웃/롤백이 일어났는지(예: 지갑은 커밋됐는데 메일 발송 span 이 에러) 즉시 좁힐 수 있다. trace_id 를 로그에도 박아두면 트레이스↔상세 로그를 오간다.
4. 부하 테스트 설계
- 목표 정의: "한계 CCU", "목표 CCU 에서의 꼬리 지연", "어느 자원이 먼저 포화되는가 (CPU/네트워크/DB/GC)" 를 명확히. 막연한 "터질 때까지" 보다 SLO(p99 지연 ≤ X) 기준으로.
- 부하 종류:
- 봇/합성 클라이언트: 실제 프로토콜로 접속해 이동·전투·채팅 등 현실적 행동 믹스를 생성. 가장 충실하지만 구현 비용↑.
- 리플레이: 실서비스 트래픽을 녹화·재생 → 현실적 패턴이지만 환경 차이/상태 의존 주의.
- 순수 합성 부하: 특정 경로만 두드림(예: 로그인 폭주, accept 폭주) → 특정 병목 격리에 유용.
- 측정 대상: 한계 CCU, 각 자원 사용률과 먼저 포화되는 병목, 틱 타임/지연의 분포(꼬리), GC 정지, 큐 적체, 에러율. 부하를 점진 증가(ramp) 시키며 무릎점(knee)을 찾는다.
- 흔한 함정:
- 비현실적 트래픽: 모든 봇이 한 존/한 행동에 몰리면 실제와 다른 병목을 본다. 행동·지역 분포를 실측에 맞춘다(핫스팟도 일부러 포함).
- 관측 도구 자체의 오버헤드(probe effect): 과한 로깅/트레이싱이 측정값을 왜곡. 운영과 같은 샘플링 비율로 테스트.
- 클라 측 병목: 부하 생성기가 먼저 포화돼 서버 한계를 과소평가. 생성기 자원/분산 확인.
- 워밍업 무시: JIT/캐시/커넥션 풀이 데워지기 전 수치를 한계로 오인.
결론: 로그·메트릭·트레이스를 trace_id 로 엮고, 핵심 지표를 분포(p95/p99) 로 보며, 부하 테스트는 현실적 행동 믹스 + 점진 증가 + 병목/꼬리지연 측정으로 설계한다. 관측성이 없으면 장애는 "재현 안 되는 미스터리" 가 되고, 있으면 "trace 한 번에 원인 한 줄" 이 된다.