UEFN Session Launch Timeout 악몽? Unreal Engine Network Drivers 진단하기
모든 기술 게임 개발자라면 3분 동안 로딩 화면만 바라보다가 갑작스러운 연결 끊김을 당했을 때의 그 끓어오르는 좌절감을 잘 알고 있을 것입니다. "Launch Session"을 누르고, 유효성 검사 및 업로드 단계가 끝나기를 기다리고, 에셋이 컴파일되는 동안 크리에이티브 허브에 앉아 있다가, 엔진이 치명적인 로그 메시지와 함께 아무런 예고 없이 에디터로 튕겨낼 때의 기분 말이죠.
복잡한 멀티플레이어 경험을 구축하고 있다면 UEFN session launch timeout을 겪는 것은 거의 통과의례와 같습니다. 에디터 로그에는 보통 다음과 같은 내용이 출력됩니다.
LogNet: Warning: UNetConnection::Tick: Connection TIMED OUT. Closing connection.. Elapsed: 30.00, Real: 30.00, Good: 30.00, DriverTime: 151.46, Threshold: 30.00, [UNetConnection] RemoteAddr: 18.156.253.228:15009, Name: IpConnection_0, Driver: Name:IpNetDriver_0 Def:BeaconNetDriver IpNetDriver_0, IsServer:
이것은 단순한 무작위 네트워크 오류가 아닙니다. Unreal Engine의 엄격한 네트워킹 임계값(Threshold)과 커스텀 에셋을 컴파일하고 동기화하는 데 필요한 무거운 블로킹 작업 사이의 매우 구체적인 아키텍처 충돌입니다.
이 기술 분석에서는 이 로그가 정확히 무엇을 의미하는지, Unreal Engine 네트워킹 스택이 왜 이렇게 동작하는지, 그리고 UEFN의 제약 내에서 작업하든 UE5에서 커스텀 dedicated servers를 구축하든 이러한 타임아웃을 방지하기 위해 프로젝트를 어떻게 설계해야 하는지 분석해 보겠습니다.
UNetConnection 타임아웃 로그 해부
문제를 해결하려면 먼저 Unreal Engine이 제공하는 텔레메트리를 이해해야 합니다. LogNet 경고의 정확한 변수들을 분석해 보겠습니다.
- Elapsed: 30.00: 이것은 핵심 지표입니다. 클라이언트가 서버로부터 마지막으로 유효한 네트워크 패킷(또는 heartbeat)을 받은 후 정확히 30초가 지났음을 의미합니다.
- Threshold: 30.00: 이것은 엔진의 네트워크 드라이버 구성에서
ConnectionTimeout변수에 의해 정의된 하드코딩된 제한입니다.Elapsed가Threshold에 도달하면 연결은 무자비하게 종료됩니다. - DriverTime: 151.46: 네트워크 드라이버가 총 약 2.5분 동안 실행되었습니다. 이는 초기 연결은 성공했지만, 이후의 블로킹 작업으로 인해 30초 동안 응답이 없었음을 알려줍니다.
- Def:BeaconNetDriver: 이것이 결정적인 증거입니다. Unreal Engine은 게임플레이를 위한 메인
IpNetDriver로 전환하기 전에 플레이어 슬롯 예약이나 버전 호환성 확인과 같은 가벼운 사전 연결 통신을 처리하기 위해BeaconNetDriver를 사용합니다.
UEFN 프로젝트가 커스텀 에셋을 라이브 편집 서버에 업로드할 때 클라이언트는 비콘을 통해 연결합니다. 그러나 로컬 머신이나 원격 서버가 최적화되지 않은 셰이더를 컴파일하거나 무거운 Verse 코드를 검증하느라 완전히 점유되면 메인 스레드(main thread)가 차단됩니다. 스레드가 30초 이상 차단되면 keep-alive 패킷이 전송되지 않습니다. 비콘은 클라이언트가 충돌한 것으로 간주하고 연결을 끊습니다.
Live Edit가 문제를 악화시키는 이유
UEFN의 Live Edit 아키텍처는 현대 게임 엔진 설계의 경이로움이지만, 엄청난 제약 하에 작동합니다. 세션을 시작하면 에디터는 수정된 에셋을 패키징하고, 이를 Epic이 호스팅하는 인스턴스에 업로드한 다음, 로컬 Fortnite 클라이언트에 해당 인스턴스에 연결하도록 명령해야 합니다.
대형 임포트 메시, 대규모 텍스처 배열 또는 복잡한 오디오 스템을 작업하는 경우 "컴파일을 위해 크리에이티브 허브에서 대기"하는 단계가 거대한 병목 현상이 됩니다. 서버는 클라이언트가 허브에서 라이브 게임 상태로 빠르게 전환되기를 기대합니다. 클라이언트가 로컬에서 4,000개의 셰이더를 컴파일하느라 멈춰 있으면 네트워크 틱(network tick)이 굶주리게 됩니다.
이는 더 광범위한 엔진 문제의 국지적 버전입니다. 사실, 과부하 후 공간 동기화에 어려움을 겪고 있다면 How To Fix Player Location Desync In Uefn And Unreal Engine Multiplayer 가이드를 검토해 보시기 바랍니다.
표준 Unreal Engine 5에서 타임아웃 수정하기
UEFN은 저수준 엔진 구성 파일을 편집하는 기능을 추상화하지만, 커스텀 dedicated servers로의 전환을 계획하는 개발자에게는 표준 Unreal Engine 5에서 이 문제를 해결하는 방법을 이해하는 것이 필수적입니다.
표준 UE5 프로젝트에서는 충돌을 일으킨 Threshold 값을 직접 조작할 수 있습니다. 기본적으로 Unreal Engine은 끊긴 연결이 서버 메모리를 소모하는 것을 방지하기 위해 네트워크 타임아웃을 매우 공격적으로 설정합니다.
이 임계값을 높이려면 DefaultEngine.ini 파일을 수정해야 합니다. 무거운 에셋 컴파일 중에 클라이언트에 더 많은 여유를 주기 위해 필요한 정확한 구성은 다음과 같습니다.
; DefaultEngine.ini
[/Script/OnlineSubsystemUtils.IpNetDriver]
; 표준 연결 타임아웃을 120초로 증가
ConnectionTimeout=120.0
; 무거운 맵 로드 시 초기 연결 단계에 더 많은 시간(150초) 부여
InitialConnectTimeout=150.0
[/Script/Engine.NetDriver]
ConnectionTimeout=120.0
InitialConnectTimeout=150.0
KeepAliveTime=0.2
MaxClientRate=100000
MaxInternetClientRate=100000
타임아웃을 30초에서 120초로 늘리면 서버가 연결을 끊지 않고도 클라이언트가 블로킹 작업(셰이더 컴파일 또는 seamless travel 에셋 로딩 등)을 마칠 수 있습니다.
C++를 통한 동적 타임아웃 조정
INI 파일에 120초 타임아웃을 하드코딩하는 것은 투박한 도구입니다. 2분 타임아웃은 플레이어가 실제로 충돌한 경우 서버가 해당 액터와 네트워크 리소스를 메모리에 120초 동안 유지하여 귀중한 CPU 사이클과 RAM을 낭비한다는 것을 의미합니다. 낭비되는 서버 리소스가 수익에 미치는 영향에 대한 자세한 내용은 Architecting Zero Waste Servers The Fortnite Server Optimization Hibernation Proposal Analyzed 분석을 확인하세요.
커스텀 UE5 게임을 위한 훨씬 더 나은 접근 방식은 대규모 오픈 월드 맵 로딩과 같이 무거운 블로킹 작업이 발생할 것임을 알 때만 타임아웃 임계값을 동적으로 조정하는 것입니다.
다음은 UNetConnection에 액세스하고 로딩 단계에서 일시적으로 타임아웃을 연장하는 방법을 보여주는 C++ 구현입니다.
#include "Engine/NetConnection.h"
#include "GameFramework/PlayerController.h"
void AMyPlayerController::PrepareForHeavyMapLoad()
{
// 이 플레이어의 활성 네트워크 연결 검색
if (UNetConnection* NetConnection = GetNetConnection())
{
// 나중에 복원하기 위해 원래 타임아웃 저장
float OriginalTimeout = NetConnection->GetTimeoutValue();
// 무거운 에셋 컴파일을 견디기 위해 타임아웃을 일시적으로 180초로 상향
NetConnection->SetTimeoutValue(180.f);
UE_LOG(LogTemp, Warning, TEXT("Adjusted connection timeout from %f to 180s for loading phase."), OriginalTimeout);
// TODO: 맵 로드 완료 시 OriginalTimeout을 복원하기 위한 델리게이트 바인딩
}
else
{
UE_LOG(LogTemp, Error, TEXT("Failed to retrieve UNetConnection. Player may already be disconnected."));
}
}
이 코드는 서버가 실제로 끊긴 연결을 신속하게 제거하는 능력을 영구적으로 손상시키지 않으면서 플레이어가 로딩 화면을 견딜 수 있도록 보장합니다.
세션 타임아웃 방지를 위한 모범 사례
UEFN에 묶여 있어 DefaultEngine.ini를 편집할 수 없는 경우 타임아웃을 연장하는 대신 페이로드를 최적화하여 문제를 해결해야 합니다. 다음은 UEFN 세션 실행 타임아웃을 방지하기 위한 5가지 실천 가능한 모범 사례입니다.
- 실행 전 미사용 에셋 제거: UEFN은 레벨에 배치되지 않았더라도 프로젝트 디렉토리에 존재하는 에셋을 검증하고 업로드하려고 시도합니다. Launch Session을 누르기 전에 사용하지 않는 고폴리 메시와 4K 텍스처를 프로젝트 폴더 밖으로 옮기세요.
- 셰이더 사전 컴파일 강제 실행: 커스텀 머티리얼을 사용하는 경우 세션을 시작하기 전에 로컬에서 완전히 컴파일되었는지 확인하세요. 30초 타임아웃의 흔한 원인은 서버가 네트워크 heartbeat를 기다리는 바로 그 시점에 로컬 클라이언트가 셰이더를 컴파일하느라 멈추는 것입니다.
- Verse 코드 실행 제한 최적화: Verse의 무거운
OnBeginPlay루프는 서버 측 초기화를 지연시킬 수 있습니다.Sleep(0.0)을 사용하여 대규모 초기화 루프를 분할하고 실행 권한을 메인 스레드에 반환하여 네트워크 틱이 처리될 수 있도록 하세요. - 콜리전 복잡도 감소: 복잡한 커스텀 콜리전 메시는 백엔드에서 검증하는 데 훨씬 더 오랜 시간이 걸립니다. 가능한 경우 콜리전에 단순한 박스 또는 캡슐 프리미티브를 사용하세요.
- 업로드 대역폭 모니터링: 클라이언트가 변경 사항을 업로드하는 동안에도
DriverTime지표는 계속 카운트됩니다. 업로드 대역폭이 낮은(20Mbps 미만) 연결인 경우 500MB 프로젝트 업데이트를 푸시하면 거의 확실하게 타임아웃이 발생합니다.
백엔드 인프라 요인
UEFN에서 Unreal Engine의 자체 독립형 멀티플레이어 게임 구축으로 전환하면 이러한 네트워크 규칙을 규정하는 백엔드 인프라를 관리할 책임이 생깁니다.
세션 타임아웃 처리, dedicated servers 로드 밸런싱, 플레이어 매치메이킹(matchmaking) 관리를 위해서는 Agones와 같은 플릿 매니저를 배포하거나 Kubernetes에서 커스텀 오케스트레이션 레이어를 작성해야 합니다. 이를 직접 구축하려면 데이터베이스 샤딩(sharding), SSL 인증서 관리, 리전 간 라우팅 설정이 필요하며, 게임 로직을 작성하기 전에도 4~6주간의 고된 DevOps 작업이 필요합니다.
이것이 바로 horizOn이 필요한 이유입니다. horizOn을 사용하면 이러한 복잡한 백엔드 서비스가 게임 개발자를 위해 특별히 사전 구성되어 제공됩니다. AWS에서 서버 오케스트레이션 및 연결 타임아웃과 씨름하는 대신 dedicated servers 확장을 자동으로 처리하는 완전 관리형 Backend-as-a-Service를 이용할 수 있습니다.
결론
UEFN 세션 실행 타임아웃을 겪는 것은 좌절스러운 장애물이지만, 현대 게임 엔진이 네트워크 상태를 어떻게 처리하는지에 대한 귀중한 교훈이기도 합니다. 엔진은 단순히 서버 안정성을 보호하기 위해 죽은 것처럼 보이는 연결을 공격적으로 제거하는 자신의 일을 하고 있는 것입니다.
서버 인프라 걱정을 멈추고 멀티플레이어 백엔드 확장을 시작할 준비가 되셨나요? horizOn을 무료로 체험하거나 API 문서를 살펴보고 오늘 바로 프로덕션 준비가 된 게임 서버를 얼마나 쉽게 배포할 수 있는지 확인해 보세요.