포트나이트

2.8.2018

340만 동접자 이후 서비스 다운 관련 사후 분석 내용

글쓴이 에픽팀

지난 일요일(미국시각) 포트나이트가 340만 동접자 수를 새롭게 기록했습니다. 그런데 문제가 없지는 않았죠! 이번 공지에서는 저희의 예상을 뛰어넘는 엄청난 속도로 성장하는 게임 서비스를 운영하면서 경험한 어려움과 기술적인 세부사항을 전달하고자 합니다.

또한, 에픽게임즈에서는 전문가를 찾고 있습니다! 이러한 문제를 해결할 수 있는 전문성을 가지고 있는 분들을 시애틀, 노스캐롤라이나, 솔트레이크시티, 산프란시스코, 영국, 스톡홀름, 서울 등의 지역에 위치한 에픽게임즈에 합류하세요! 자세한 내용은 OnlineJobs@epicgames.com으로 연락해주시기 바랍니다.

2월 3일, 4일 서비스 다운 관련 내용

토요일과 일요일 사이에 극단적인 과부하가 걸려서 6차례의 문제 현상이 발생했으며, 포트나이트 일부 혹은 전체 서비스 운영에 장애가 발생했습니다.

MCP 데이터베이스 지연

포트나이트에는 MCP라고 불리는 플레이어들이 게임 프로필, 전적, 아이템, 매치메이킹 등 다양한 정보를 확인할 수 있도록 해주는 시스템이 있습니다. 그리고 지속적으로 이런 데이터 정보를 보관하기 위해 여러 데이터베이스를 백업하고 있습니다. 포트나이트 게임 서비스는 현재 가장 큰 데이터베이스를 보유하고 있습니다.

기존 MCP 데이터베이스는 9개의 MongoDB 샤드로 구성되어 있고, 각 샤드에는 기록기 1개, 복제본 정보 읽기 2개, 그리고 여분의 숨겨진 복제본을 포함하고 있습니다. 사용자 지정 데이터는 8개의 샤드에서 보관하며, 매치메이킹 세션, 공유 서비스 캐시, 그리고 런타임 구성 데이터는 나머지 샤드에서 보관합니다. 

MCP는, 각 서비스가 사이드카 프로세스에 대한 DB 연결 풀을 가지며, 이를 통해 모든 샤드에 대한 연결 풀을 유지하도록 설계되었습니다. 초당 최대 12.4만 개의 클라이언트 요청을 처리할 수 있으며, 이는 초당 31.8만 번의 데이터베이스 읽기와 13.2만 번의 데이터베이스 쓰기, 더불어 평균 데이터베이스 응답시간이 10ms 이하임을 의미합니다. 그 중 매치메이킹 요청은 하나의 샤드에서 총 DB 쿼리의 약 15%와 총 읽기의 11%를 차지합니다. 게다가 현재 매치메이킹 실행을 위한 요구 데이터는 단일 컬렉션이어야 합니다.

피크 기간에는 매치메이킹 샤드가 사용 가능한 기록기 리소스가 생기길 기다리면서 쓰기 작업을 대기열에 올리는 문제를 발견했습니다. 이로 인해 작업별로 데이터베이스 업데이트 시간이 40k+ ms 범위로 급증해 MCP 스레드가 막히는 경우가 발생할 수 있습니다. 그리고 플레이어들은 매치메이킹을 하기 위해 평소보다 더 오래 기다려야 했으며, 다른 작업에서도 마찬가지 일이 벌어졌습니다. 이 현상에 대해 세부적으로 분석하고 있지만, 왜 쓰기 작업이 이런 식으로 대기열에 올라가는지 아직 명확하게 밝혀내지 못했습니다. 하지만 근본 원인을 밝히기 위해 계속 노력하고 있습니다.

만일 이 현상이 수정되지 않으면 DB 프로세스도 응답하지 않게 되어 수동 장애 조치 기능을 복구시켜야 하는 상황이 올 수도 있습니다. 서비스가 내려간 동안 이런 작업이 매시간 여러 번 반복되었습니다. 장애 조치가 진행될 때마다 시스템이 복구되기 전에 잠깐 매치메이킹 현상이 불안정해지기도 했습니다.

MCP 스레드 구성

포트나이트를 런칭하기 전에 MCP 패키징을 변경했는데, 이로 인해 사용 가능한 서비스 스레드 수가 당시 안전할 것으로 생각한 기준 이하로 제한되는 버그가 발생했습니다. 이 부분은 최근 수정 작업을 통해 이전의 수치로 되돌림으로써 수정되었습니다.

하지만 라이브 환경에 적용한 결과, 테스트 환경에서는 나타나지 않았던 데이터 요구 지연현상(평균 double ms에서 double second까지)이 발생했습니다. 이는 진단 끝점을 통한 실시간 CPU 샘플링 방법을 사용하여 db 연결 풀 결핍 현상임을 알아냈습니다. 이 이슈를 빠르게 해결하기 위해 이전 스레드 풀 구성으로 되돌렸습니다.

성능을 개선하기 위한 작업이었지만 결과는 오히려 그 반대였고, 작업량이 최대치에 도달하고 나서야 문제점을 발견했습니다.

토요일에 발생한 상기의 MCP 문제 현상은 아래 표에서도 확인할 수 있습니다. 표에서 솟아오른 선들은 매치메이킹 db 오류, db 스레드 풀 결핍 및 점진적 롤링 배포 때문에 발생한 전반적인 성능 저하를 나타냅니다.



일요일 매치메이킹 db 오류 관련해서는 아래 표에서 확인할 수 있습니다. 

계정 서비스 중단

계정 서비스는 유저 계정 데이터와 본인인증의 마지막 단계를 담당하는 에픽의 주요 서비스입니다.
수치로 보는 서비스:
  • 처리량: 4만 - 10만 요청/초 (250만 - 600만 rpm). 데이터가 매우 많을 때는 최대 16만/초 
  • 지연시간:
    • 모든 API: 평균 < 10ms, p99 < 100ms, p99.9 < 400ms
    • 로그인: 평균 < 100ms
    • 본인인증: 평균 < 5ms
  • 계정생성: 분당 1천 - 3천
  • 로그인/로그아웃: 500 - 1000 로그인/초. 그리고 700 - 1500 새로고침/초 (시간 연장).

계정 서비스는 JAXRS 기반의 웹 서비스 구성 요소와 여러 사이드카 프로세스가 포함된 복잡한 애플리케이션으로, 그 중 하나가 바로 Nginx 프록시입니다.

이 프록시의 주된 목적은 액세스 토큰 검증 경로를 단축시키는 것입니다. 이 프록시를 통해서만 모든 트래픽이 라우팅되며, 위에 표시된 캐시에 대해서만 액세스 토큰 검증 트래픽이 확인됩니다. 다른 모든 호출은 간단하게 메인 애플리케이션으로 전달됩니다.

일요일에는 멤캐시드의 불안정성이 Nginx 수용량(주로 사용 가능한 모든 작업자 스레드를 점유)을 포화 상태로 만들어 다른 트래픽이 메인 애플리케이션에 연결되지 못하게 하는 상황이 발생했습니다.



상황 요약:
  • 타임라인:
    • 2018-02-04 18:30 UTC - 2018-02-04 20:20 UTC
  • 근본 원인:
    • 자바 애플리케이션 앞에 있는 Nginx의 트래픽은 포화 상태였고, 트래픽이 애플리케이션으로 제한되었습니다. 그래서 이런 상황에 대비한 JVM 수준의 보호 장치는 도움이 되지 않았습니다.
  • 사건 세부내용:
    • 네트워크 및 연결이 포화하면서, 멤캐시드 구성 요소가 엄청난 처리량으로 인해 오류가 발생하기 시작했습니다.
    • 그 다음으로 Nginx가 멤캐시드 호출(100ms) 타임아웃에 의해 막히면서 다른 트래픽을 처리할 수 없게 되었습니다(상태 점검 호출 포함).
    • 모든 확인 호출이 불발되면서 JVM 레이어로 전달되었고, 레디스 로드와 멤캐시드 타임아웃 +100ms이 추가되었습니다.
    • 상태 점검 요청이 누락되면서 부하 분산 장치가 모든 노드를 로테이션에서 제외시켰고, 이로 인해 전체 서비스가 중지되는 상황이 발생했습니다.
  • 영향:
    • 그래도 다행이었던 점은 저희가 준비해놓은 복구 장치들로 인해 매치를 진행 중이던 플레이어들에게 큰 피해를 주지 않을 수 있었습니다.
    • 로그인 및 로그아웃이 대부분 막혔고, 오류로 인해 플레이어들이 에픽게임즈 런처에서 로그아웃되는 현상이 발생했습니다.
  • 다음 작업:
    • ALB에서 레벨 7 라우팅을 활용하여 검증되지 않은 모든 트래픽을 Java 애플리케이션으로 직접 전달합니다. 그리고 Java 애플리케이션에는 이와 같은 포화 상태에 대비하여 여러가지 보호 조치를 구현합니다.
    • 이로 인해 멤캐시드 수용량을 크게 증가시킬 수 있습니다.
    • 그 다음에는 Nginx와 멤캐시드를 동시에 완전히 정리하는 것입니다.
    • 여전히 풀어야 할 흥미진진한 문제가 많이 남아 있습니다. 예를 들어, 보관이 필요한, 복잡한 보조 지표를 포함한 영구 데이터를 효과적으로 샤딩할 수 있는 작업을 구현하는 것입니다.

XMPP 중단

XMPP는 온라인 상태, 문자 메시지와 그 외 파티 같은 여러 소셜 기능들의 기반이 되는 서비스로 플레이어들이 최고의 소셜 경험을 할 수 있도록 중요한 역할을 합니다. 그렇기 때문에 XMPP 중단으로 인해 모든 XMPP의 서비스가 불안정해지면 이는 커뮤니티에 다 드러나게 되어 있습니다.

XMPP 서비스는 XMPP 프로토콜 및 프로토콜 확장의 부분집합을 플랫폼 요구에 따라 지원하기 위해 사용자 지정된 인스턴트 메시징 솔루션입니다.

수치로 보는 XMPP 서비스:
  • 온라인 연결: 300만++
  • 패킷 처리량:
    • 총: ~60만/초 (보조 트래픽, 포워딩 및 브로드캐스트 효과 포함)
    • 상태: ~18만/초
    • 알림: ~5만/초
    • 메시지: ~4만/초
다음과 같은 기능/현상을 위해 XMPP를 사용합니다:
  • 온라인 상태
  • 푸시 알림
  • 귓속말
  • 그룹 채팅 - 전체 방에서 파티 및 팀 채팅

다른 여러 인스턴트 메시징 서비스처럼, XMPP의 본질은 메시지, 상태, 명령, 다양한 보조 데이터와 같은 패킷을 클러스터를 통해 발신기에서 (여러) 수신기로 전달하는 비동기 발행-구독 시스템입니다.

XMPP는 다중 최종 사용자 연결 프로토콜을 지원합니다. 저희 서비스는 TCP와 Websockets 두 가지를 사용하고, 클라이언트와 지속적이고 비교적 오래 접속이 유지되는 TCP 연결 수 백만 개를 동시에 관리하고 있습니다. 그렇기 때문에 시스템이 복잡해질 수밖에 없고, 다른 일반적인 REST 웹 서비스와는 차원이 다릅니다.

에픽 XMPP는 소셜 웹 서비스 중 한 요소로, XMPP에 친구 관련 정보를 제공하는 친구 서비스 등 다른 서비스의 영향을 받습니다. 그리고 저희는 이 정보들을 활용하여 플레이어들 간 상태를 확인할 수 있도록 합니다. 

일요일에는 불안정 문제를 개선하던 중에 오히려 다운스트림 시스템 구성요소가 과부하 되면서 상태 정보 흐름을 마비시키는 일이 발생했습니다. 상태 정보 흐름이 없으면 친구의 상태를 알 수 없게 되며, 파티를 형성하는 것과 같은 소셜 기능을 사용할 수 없게 됩니다.

표:
  • 상단 - 불안정과 연결 마이그레이션이 파란색 영역에서 초록색 영역으로 변동(UTC시간)
  • 좌측 - 친구 서비스로 보낸 대기 XMPP 클러스터의 호출 수. XMPP 관점.
  • 우측 - Friends 부하 분산 장치에서 처리하는 트래픽. 일단 복구되면,  대기 중인 모든 트래픽을 처리할 수 있었습니다.



상황 요약:
  • 타임라인:
    • 2018-02-04 22:00 UTC - 2018-02-05 00:15 UTC
  • 근본 원인:
    • 친구 서비스 내부 부하 분산 장치(XMPP의 중요 경로)가 과부하 되면서 오류 현상이 나타났습니다.
    • ELB가 장애 조치 프로세스 및 오래된 네트워크 구성의 세부 사항으로 인해 신속하게 복구할 수가 없었습니다. ELB서브넷에 교체할 수 있는 무료 IP가 부족했습니다.
  • 사건 상세내용:
    • 최근에 도입된 메모리 누수로 인해 XMPP는 모니터링되는 경로에서 불안정한 상태로 전환했습니다.
    • 누수는 해결되었으며, 다른 준비된 대기 클러스터로 교체할 계획입니다. 
    • 평일에 제대로 된 유지 보수 작업을 진행하고 그 전에 주말까지는 클러스터가 유지될 것으로 생각했습니다. 
    • 하지만 게임 서비스와 계정 서비스의 불안정으로 인해 누수 현상이 더 커졌고, 일요일 22:00 UTC부터 클러스터 노드를 잃기 시작하면서 플레이어들과의 연결이 끊겼습니다.
    • 모든 트래픽을 즉각적으로 다른 끝점으로 넘기게 되면서 바로 대기 클러스터로 장애 조치를 진행할 결정(초록/파랑 전개)이 내려졌습니다.
    • 하지만, 당시 재연결을 시도하는 사람들이 몰려들었고, 친구 서비스 부하 분산 장치가 마비되면서 새롭게 연결됐을 때 상태 정보 흐름을 설정할 수 있는 기능이 중단되었습니다.
  • 영향:
    • 결과적으로, 실제 XMPP에 연결되었음에도 불구하고 UI는 상태 정보가 누락되어 모든 사용자가 오프라인으로 표시되었습니다.
    • 한마디로, "어두운 방"과 같은 상황이었습니다.
  • 다음 작업:
    • 저희는 친구 서비스 문제를 해결하기 위해 부하 분산 장치를 업그레이드하고, 다른 플랫폼 서비스로 이러한 문제를 처리할 수 있도록 작업을 진행하고 있습니다. 
    • 서브넷 수용량을 보장하기 위해 VPC 환경 설정을 수정하고 있습니다.
    • 또한 적극적으로 수정하고 있는 장기적인 문제도 있습니다. 예를 들어, 현재 XMPP 클러스터의 아키텍처는 전체 메시를 나타냅니다. 각 클러스터 노드는 서로 10번씩 연결되어 있으며, 클러스터에 101개의 노드가 있다고 생각하면 클러스터 연결에만 노드당 1k 소켓을 사용해야 합니다.  
    • 현재 솔루션으로는 각 XMPP 노드가 최대 N 번만 연결할 수 있기 때문에 이론적으로 새로운 솔루션을 설계하기 전까지는 저희가 유지할 수 있는 적정 클러스터 노드의 수에 제약이 있을 수밖에 없습니다.

클라우드 수용량 한계 및 스로틀링

저희는 포트나이트 전용 게임 서버는 수 천 개의 c4.8xlarge AWS 인스턴스를 바탕으로 운영되어, 일일 최대 플레이어 수에 따라 높아졌다가 낮아지게 됩니다. 그렇기 때문에 인스턴스 수가 항상 변동적이고 비선형적으로 증가합니다.

수용량 제한으로 인해 게임이 중단되지는 않았지만, 몇 가지 서비스 제한과 관련하여 신속하게 조정해야 했습니다. 다행히도 모니터링을 통해 필요한 내용을 신속하게 알 수 있었고 필요한 조치를 취할 수 있었습니다. 여기서의 제한은 해당 지역의 인스턴스 최대 한계를 도달한 것으로 모든 지역에 서비스하는데 영향을 주기도 했습니다. 더 나아가 API 속도 제한이 여러 번 발생했습니다. '다음 작업' 항목에서 이와 관련된 수정 작업과 내용을 설명했습니다. 

사용가능한 IP 부족

저희는 핵심 서비스를 위해 여러 클라우드 제공업체의 가용 영역에서 게임을 운영하고 있고, 표준 서브넷은 /24로 각 서브넷마다 251개의 사용 가능한 IP가 제공됩니다. 공유 서브넷, 인스턴스 변경 그리고 많은 서비스 확장과 같은 많은 요인으로 인해 IP가 부족한 상황이 나타났습니다. 위에서 설명한 것처럼 장애 없이 많은 구성 요소들을 옮길 수는 있었지만 부하 분산 장치가 회복되는 시간이 길어졌습니다. 
  

다음 작업 및 업데이트

현재 가장 중요시하는 것은 서비스 가용성을 보장입니다. 이후 작업은 다음과 같습니다.
  • DB성능 문제의 근본 원인 식별 및 해결. 저희는 Mongo 전문가를 현장에 파견하여 DB와 사용량을 분석하고 주말에 과중한 업무량을 처리할 수 있도록 실시간으로 지원했습니다.
  • 클라이언트 또는 서버에서 백엔드에 대한 불필요한 모든 호출을 최적화, 축소 및 제거. 하나의 예를 들자면, 각 게임 서비스 호출에서 이미 암시적으로 사용자 권한 확인 작업이 이루어지고 있는 상황에 서 다시 정기적으 로 작업하는 것입니다. 한번에 수행하면 더 효과적으로 처리할 수 있는 작업임에도 불구하고, 게임 플레이 세션에 개별 플레이어를 등록하고 취소하면서 로그인/로그아웃 시나리오에서 스래싱을 방지하기 위해 XMPP 연결을 지연시키고 있었습니다.  
  • 매치메이킹 세션 데이터를 DB에 저장하는 방법 최적화. 현재 쓰기 대기열 문제에 대한 근본 원인을 찾지 못해도 삭제 데이터를 저 장하는 방법을 변경하여 성능을 높일 수 있습니다. 저희는 이 상황에 더 적합할 수 있는 메모리 내 데이터베이스 솔루션을 프로토 타입으로 제작하고 있고, 현재 데이터가 제대로 샤딩이 가능하도록 데이터를 재구성하는 방법을 찾고 있습니다. 
  • 생산 및 개발 프로세스 중심으로 내부 운영 개선. 생산 및 개발 프로세스 중심으로 내부 운영 개선. 그러기 위해서는 매주 성능에 대한 집중 검토, 모니터링 및 알림 시스템 확대, 사후 분석 프로세스의 지속적인 개선과 같은 설계/구축 간의  API호출 패턴을 비교하는 새로운 툴을 개발 해야 합니다.  
  • 확인된 클라우드 공급자 제한 및 서브넷 IP 활용에 대한 위험 경고 및 모니터링 시스템을 개선. 
  • 이슈 발생에 따른 피해 반경 감소. 여러 가지 코어 서비스가 전 세계적으로 모든 플레이어에게 영향을 주고 있습니다. 에픽은 전 세계에 걸쳐 게임 서버를 운영하는데, 여러 클라우드 공급자를 활용한 서비스를 통해 여러 지역에 핵심 서비스를 지원하고 있습니다. 그러므로 서비스에 장애가 생길 경우 플레이어의 미치는 영향을 줄일 수 있습니다. 서비스 범위를 확대하는 것은 운영 오버헤드와 복잡성을 증가시킵니다. 전 세계의 대규모 멀티 클라우드 서비스 및/또는 인프라를 운영한 경험이 있으시면 꼭 의견을 듣고 싶습니다. 
  • 핵심 메시징 스택 재구성. 현재 스택은 거대한 규모를 처리할 수 있도록 설계되지 않았으며 지속적인 성장을 지원하기 위해 아키텍처에서보다 큰 변화를 추구할 필요가 있습니다.
  • Epic의 데이터와 DB 스토리지에 대한 전문성. 서비스가 성장하고 데이터 세트와 사용 패턴이 날마다 점점 더 커지면서 새롭고 흥미로운 변화를 맞이하고 있습니다. 우리는 게임의 지속적인 성장을 위해 확장 병목 현상을 해결할 수 있도록 지원할 수 있는 숙련된 DBA를 찾고 있습니다.
  • 내부 인프라스트럭쳐 확장. 게임 서비스의 규모가 커지면 내부 모니터링, 메트릭 및 로깅도 그리고 기타 내부 요구사항까지 부담이 증대됩니다. 우리의 서비스 범위가 확장되면서 더욱 진보된 장치 배치, 구성 도구, 그리고 인프라 또한 증가하게 됩니다. 경험을 축적하고 내부 시스템을 개선하고 Epic에서 진행 중인 작업에 관심이 있다면 저희에게 연락을 부탁드립니다.
  • 성능. 언급된 여러 가지 사항과 함께 N 노드를 통한 작은 성능의 변경만으로도 서비스와 플레이어 경험에 커다란 영향을 줍니다. 대규모 성능 튜닝에 대한 경험이 있고 플레이어에게 직접적인 영향을 줄 수 있는 개선 작업을 원할 경우 문의 바랍니다.
  • MCP 리아키텍처
    • 특정 기능을 MCP에서 마이크로 서비스로 이동
    • 사용자 데이터를 위한 이벤트 소싱 데이터 모델
    • 사용자 세션의 액터 기반 모델링

서비스 가용성에 영향을 주는 문제를 최우선으로 해결하려고 합니다. 저희는 모든 서비스 중단을 심각하게 생각하고 있으며, 각 내용에 대해 심층적인 검증을 하여 근본 원인을 파악하고 최선의 방안을 마련하기 위해 노력하고 있다는 것을 말씀드리고 싶습니다. 온라인 팀은 지난 몇 개월 동안 주간 단위로 빠르게 성장하고 있는 수요를 따라잡기 위해 부단히 노력하고 있습니다.

포트나이트 서비스 이용자가 최대치에 도달함에 따라서 미래에 동일한 이슈가 없을 것이라고 약속할 수는 없지만 Futurama의 위대한 인용문구와 같이 서비스를 유지하고자 합니다. "일을 올바르게 처리하면 사람들은 어떤 일이 있었는지 전혀 모를 것이다."
 

저희는 당신이 필요합니다! 


포트나이트가 단기간 안에 60만 동접자에서 340만 동접자가 즐기는 게임으로 성장하기까지는 즐겁고 엄청난 경험이었습니다. 이것으로 포트나이트가 어쩌면 전 세계에서 가장 큰 PC/콘솔 게임이 될 수도 있습니다! 이 모든 것은 베테랑 온라인 개발자들이 작은 팀을 꾸려 몇 달 만에 만들어낸 결과물이고, 계속될 여정에서 에픽게임즈와 함께할 가족을 찾고 있습니다!
 
에픽의 수준 높은 개발팀와 함께 하기를 희망하시는 분들은 OnlineJobs@epicgames.com으로 연락해주시기 바랍니다.