게임 서버나 웹 서비스를 운영할 때 애플리케이션의 기능만큼 중요한 것이 네트워크와 배포 구조다. 서버가 정상적으로 실행되고 있어도 DNS 설정이 잘못되거나 TLS 인증서가 만료되면 사용자는 서비스에 접근할 수 없다. 트래픽이 급증했을 때 부하를 분산하지 못하거나 배포 과정에서 기존 서버를 중단하면 서비스 장애로 이어질 수 있다.
안정적인 서비스를 운영하려면 DNS, HTTPS, TLS, 로드 밸런싱, Auto Scaling, 무중단 배포, 장애 복구를 하나의 운영 체계로 이해해야 한다.
DNS와 HTTPS
DNS의 역할
DNS(Domain Name System)는 사람이 사용하는 도메인 이름을 서버의 IP 주소로 변환하는 시스템이다.
사용자가 api.example.com에 접속하면 클라이언트는 DNS 조회를 통해 해당 도메인에 연결할 IP 주소를 확인한다. 이후 확인된 주소를 기반으로 서버와 통신한다.
DNS는 단순한 주소 변환을 넘어 서비스의 네트워크 진입점을 관리하는 역할도 한다. 로드 밸런서의 도메인을 연결하거나, 서비스 이전 시 새로운 인프라로 트래픽을 유도할 수 있다.
주요 DNS 레코드는 다음과 같다.
- A 레코드: 도메인을 IPv4 주소에 연결한다.
- AAAA 레코드: 도메인을 IPv6 주소에 연결한다.
- CNAME 레코드: 도메인을 다른 도메인 이름에 연결한다.
- MX 레코드: 이메일을 수신할 메일 서버를 지정한다.
- TXT 레코드: 도메인 소유권 검증이나 이메일 보안 정책 등에 사용한다.
클라우드 환경에서는 DNS가 개별 서버의 IP 주소보다 로드 밸런서의 DNS 이름을 가리키도록 구성하는 경우가 많다. 이렇게 하면 서버 구성이 변경되어도 사용자는 동일한 도메인으로 서비스를 이용할 수 있다.
DNS 캐싱과 TTL
DNS 조회 결과는 효율적인 통신을 위해 캐싱된다. TTL(Time To Live)은 DNS 응답을 캐시에 유지할 수 있는 시간을 의미한다.
TTL이 길면 반복적인 DNS 조회를 줄일 수 있지만, DNS 레코드를 변경했을 때 새로운 설정이 사용자에게 반영되기까지 시간이 걸릴 수 있다. 반대로 TTL이 짧으면 변경 사항을 상대적으로 빠르게 반영할 수 있지만 DNS 조회가 증가할 수 있다.
다만 TTL을 줄여도 이미 캐싱된 응답이나 리졸버의 동작에 따라 변경 사항이 즉시 반영되는 것은 아니다.
서버 이전이나 장애 대응을 계획할 때는 DNS 변경만으로 즉각적인 트래픽 전환이 보장된다고 가정해서는 안 된다.
HTTPS의 역할
HTTPS는 HTTP 통신을 TLS로 보호하는 방식이다. 클라이언트와 서버 사이에서 전달되는 데이터의 기밀성과 무결성을 보호하고, 서버의 신원을 검증할 수 있도록 한다.
HTTPS가 적용되지 않은 통신에서는 네트워크 경로에 있는 공격자가 데이터를 엿보거나 변조할 위험이 있다. 특히 로그인 토큰, 세션 쿠키, 결제 요청, 게임 계정 정보처럼 민감한 데이터를 다루는 서비스에서는 HTTPS가 필수적이다.
일반적인 HTTPS 연결 과정은 다음과 같다.
- 클라이언트가 서버에 연결을 요청한다.
- TLS 핸드셰이크를 통해 서버 인증서를 확인하고 암호화에 필요한 키를 설정한다.
- 암호화된 연결을 통해 HTTP 요청과 응답을 주고받는다.
운영 환경에서는 외부 통신 구간에 HTTPS를 적용하고, 내부 통신에도 서비스의 보안 요구 사항에 따라 TLS를 적용한다.
TLS 인증서
TLS 인증서는 서버가 특정 도메인에 대해 유효한 신원을 가지고 있음을 증명하는 데 사용된다. 일반적으로 신뢰할 수 있는 인증 기관(CA)이 발급한 인증서를 사용한다.
인증서에는 도메인 정보, 공개키, 유효 기간, 발급 기관 등의 정보가 포함된다. 클라이언트는 인증서의 신뢰 체인과 도메인 일치 여부, 유효 기간 등을 검증한다.
인증서 발급과 갱신
운영 환경에서는 인증서 발급 자체보다 갱신과 적용 상태를 지속적으로 관리하는 것이 중요하다.
인증서가 만료되면 브라우저나 클라이언트에서 연결을 거부할 수 있다. 서비스 프로세스가 정상적으로 실행되고 있더라도 사용자는 접속할 수 없게 된다.
인증서 운영 시 확인해야 할 항목은 다음과 같다.
- 인증서의 대상 도메인이 실제 서비스 도메인과 일치하는가?
- 인증서가 만료되지 않았으며 갱신이 자동화되어 있는가?
- 중간 인증서를 포함한 인증서 체인이 올바르게 구성되어 있는가?
- 인증서 갱신 후 웹 서버나 로드 밸런서에 새 인증서가 정상적으로 적용되었는가?
- 인증서의 개인키가 안전하게 관리되고 있는가?
AWS 환경에서는 ACM(AWS Certificate Manager)을 활용해 지원되는 서비스의 인증서를 발급하고 관리할 수 있다. 예를 들어 Application Load Balancer에 ACM 인증서를 연결하면 외부 HTTPS 연결의 TLS 처리를 로드 밸런서에서 수행할 수 있다.
이때 인증서의 개인키를 애플리케이션 코드나 저장소에 포함하지 않는 것이 중요하다.
Application Load Balancer
Application Load Balancer(ALB)는 AWS의 계층형 로드 밸런서로, 주로 HTTP와 HTTPS 트래픽을 처리한다. OSI 모델의 애플리케이션 계층에서 요청을 분석하고 규칙에 따라 적절한 대상으로 전달한다.
클라이언트가 애플리케이션 서버에 직접 연결하는 대신 ALB를 진입점으로 사용하면 트래픽 분산, HTTPS 종료, 헬스 체크, 경로 기반 라우팅 등을 중앙에서 관리할 수 있다.
주요 기능
경로 기반 라우팅
요청 경로에 따라 서로 다른 대상 그룹으로 트래픽을 전달할 수 있다.
예를 들어 /api/* 요청은 API 서버로, /admin/* 요청은 관리자 서비스로 전달하도록 구성할 수 있다.
호스트 기반 라우팅
도메인 이름에 따라 요청을 서로 다른 서비스로 전달할 수 있다.
api.example.com과 admin.example.com이 동일한 ALB를 사용하면서도 각각 다른 대상 그룹으로 연결되도록 구성할 수 있다.
헬스 체크
ALB는 설정된 경로로 주기적으로 요청을 보내 대상 서버의 상태를 확인한다. 비정상적인 대상은 정상적인 트래픽 전달 대상에서 제외될 수 있다.
단, 헬스 체크는 애플리케이션의 모든 기능이 정상이라는 의미는 아니다. 실제 서비스에 필요한 데이터베이스 연결이나 필수 의존성까지 검사할지 적절히 설계해야 한다.
TLS 종료
ALB에서 HTTPS 연결을 처리하고, 내부 대상 서버에는 HTTP 또는 HTTPS로 요청을 전달할 수 있다. 내부 구간의 암호화 여부는 보안 요구 사항에 맞춰 결정한다.
ALB와 게임 서버
ALB는 HTTP 기반 API뿐 아니라 WebSocket 연결도 지원한다. 따라서 로그인, 매치메이킹, 로비, 알림 등 HTTP와 WebSocket을 함께 사용하는 게임 플랫폼에서 유용하다.
다만 UDP 기반 실시간 게임 통신이나 임의의 TCP 프로토콜을 ALB가 모두 처리할 수 있는 것은 아니다. 이러한 트래픽은 프로토콜에 맞는 네트워크 구성과 로드 밸런서를 선택해야 한다.
WebSocket 연결 유지
WebSocket은 클라이언트와 서버 사이에 지속적인 양방향 통신 채널을 제공한다. HTTP 요청과 응답을 반복하는 방식과 달리 연결이 유지되는 동안 양쪽에서 메시지를 주고받을 수 있다.
게임 로비, 실시간 채팅, 매치 상태 알림, 협동 게임의 이벤트 전달 등에 적합하다.
연결 유지에 영향을 주는 요소
WebSocket 연결은 클라이언트와 서버의 애플리케이션만으로 유지되지 않는다. 로드 밸런서, 프록시, 방화벽 등의 네트워크 장비도 연결 상태에 영향을 준다.
특히 다음 항목을 고려해야 한다.
- Idle Timeout: 일정 시간 동안 트래픽이 없는 연결을 종료할 수 있다.
- Heartbeat: Ping/Pong 또는 애플리케이션 수준의 메시지를 사용해 연결 상태를 확인한다.
- 재접속: 연결이 끊어졌을 때 클라이언트가 다시 연결하도록 구현한다.
- 세션 복구: 재접속한 클라이언트가 인증과 게임 상태를 복구할 수 있도록 설계한다.
- 연결 수 관리: 동시 연결 수와 서버별 메모리 사용량을 모니터링한다.
ALB의 idle timeout과 애플리케이션의 heartbeat 주기는 서로 맞아야 한다. 연결이 유휴 상태로 판단되어 종료되기 전에 적절한 주기로 트래픽이 발생하도록 구성할 수 있다.
다만 heartbeat만으로 모든 연결 장애를 방지할 수 있는 것은 아니다. 네트워크 단절, 서버 종료, 배포, 클라이언트 절전 등의 상황에서는 재접속 로직이 필요하다.
로드 밸런싱과 세션 상태
WebSocket은 연결이 성립된 이후 동일한 연결을 통해 계속 통신한다. 따라서 연결을 처음 수립할 때 특정 서버로 라우팅되었다면 해당 연결은 일반적으로 그 서버에 유지된다.
문제는 서버가 여러 대일 때 발생한다. 특정 서버의 메모리에만 세션이나 게임 상태가 저장되어 있으면 재접속 후 다른 서버에 연결된 클라이언트는 기존 상태를 찾지 못할 수 있다.
이 문제를 줄이려면 다음과 같은 구조를 고려할 수 있다.
- 인증 정보와 세션 메타데이터를 Redis 등의 외부 저장소에 관리한다.
- 게임 상태의 소유권과 서버 간 통신 구조를 명확히 정의한다.
- 재접속 시 기존 세션을 복구하거나 새 세션으로 전환하는 정책을 마련한다.
- 서버 종료 시 연결을 정리하고 클라이언트가 재접속할 수 있도록 한다.
ALB의 대상 고정(Stickiness)은 일부 라우팅 상황에서 유용할 수 있지만, WebSocket 연결의 지속성이나 분산 게임 상태의 정합성을 대신 보장하지는 않는다.
로드 밸런싱
로드 밸런싱은 여러 서버에 요청이나 연결을 분산해 특정 서버에 부하가 집중되는 현상을 줄이는 기술이다.
단일 서버에 모든 트래픽이 집중되면 CPU, 메모리, 네트워크, 연결 수 등의 한계에 도달할 수 있다. 로드 밸런서를 사용하면 여러 서버가 트래픽을 나누어 처리할 수 있고, 비정상적인 서버를 제외해 서비스 가용성을 높일 수 있다.
주요 로드 밸런싱 방식
라운드 로빈
요청을 대상 서버에 순서대로 분배한다. 서버의 처리 능력과 요청별 비용이 비슷할 때 단순하게 적용할 수 있다.
가중치 기반 분산
서버의 성능이나 용량에 따라 서로 다른 가중치를 부여한다. 성능이 높은 서버에 더 많은 트래픽을 전달할 수 있다.
최소 연결 수 기반 분산
활성 연결 수 등을 고려해 대상 서버를 선택한다. 다만 ALB의 기본 라우팅 알고리즘과 제공되는 알고리즘은 별도로 확인해야 하며, 모든 로드 밸런서가 동일한 정책을 지원하는 것은 아니다.
로드 밸런싱의 한계
로드 밸런서를 추가한다고 해서 서비스의 모든 병목이 해결되는 것은 아니다.
예를 들어 애플리케이션 서버가 여러 대여도 모든 요청이 단일 데이터베이스에 집중되면 데이터베이스가 병목이 될 수 있다. 또한 서버별 메모리에만 상태를 저장하면 요청이나 재접속이 다른 서버로 전달될 때 문제가 발생할 수 있다.
따라서 로드 밸런싱은 애플리케이션의 상태 관리, 데이터베이스 처리량, 캐시, 네트워크 대역폭과 함께 설계해야 한다.
Auto Scaling
Auto Scaling은 부하와 운영 조건에 따라 실행 중인 서버의 수를 자동으로 조정하는 기능이다. AWS에서는 EC2 Auto Scaling을 활용해 EC2 인스턴스 수를 늘리거나 줄일 수 있다.
트래픽이 증가하면 서버를 추가해 처리 용량을 확보하고, 트래픽이 감소하면 불필요한 인스턴스를 줄여 비용을 절감할 수 있다.
Auto Scaling의 주요 구성 요소
- Launch Template: 인스턴스 유형, AMI, 보안 그룹, 시작 설정 등을 정의한다.
- Auto Scaling Group: 관리할 인스턴스 그룹과 최소·최대·희망 용량을 지정한다.
- Scaling Policy: 부하나 일정에 따라 용량을 조정하는 정책을 정의한다.
- Health Check: 인스턴스의 상태를 확인하고 비정상 인스턴스를 교체하도록 구성한다.
- 로드 밸런서 연동: 새 인스턴스를 대상 그룹에 등록하고 트래픽을 받을 수 있도록 연결한다.
스케일 아웃과 스케일 인
Scale Out은 서버 수를 늘려 처리 용량을 확장하는 방식이다. CPU 사용률, 요청 수, 네트워크 처리량 등 적절한 지표를 기준으로 실행할 수 있다.
Scale In은 서버 수를 줄여 비용을 절감하는 방식이다. 다만 서버 수를 줄이는 과정에서 활성 연결이나 진행 중인 작업을 고려해야 한다.
특히 WebSocket 기반 게임 서버는 CPU 사용률만으로 부하를 판단하기 어렵다. 동시 연결 수, 메시지 처리량, 이벤트 루프 지연, 메모리 사용량, 매치별 자원 사용량 등을 함께 확인하는 것이 좋다.
상태를 가진 서버의 스케일링
서버가 자체 메모리에 중요한 세션이나 게임 상태를 저장한다면 인스턴스를 추가하는 것만으로 수평 확장이 완성되지 않는다.
새로운 서버가 기존 세션의 상태를 알 수 없거나, 서버 종료 과정에서 연결된 사용자의 상태가 유실될 수 있기 때문이다.
따라서 Auto Scaling을 적용하기 전에 다음 사항을 설계해야 한다.
- 서버 간 공유해야 하는 상태와 서버 내부에만 존재해도 되는 상태를 구분한다.
- 신규 서버가 트래픽을 받을 준비가 되었는지 확인한다.
- Scale In 시 기존 연결과 진행 중인 작업을 정리한다.
- 서버 수가 바뀌어도 데이터 정합성과 서비스 규칙이 유지되도록 한다.
Auto Scaling은 서버 용량을 자동으로 조정하는 기능이지, 애플리케이션의 상태를 자동으로 분산하거나 이전하는 기능은 아니다.
무중단 배포
무중단 배포는 새로운 버전의 애플리케이션을 배포하는 동안 서비스 이용이 중단되지 않도록 구성하는 배포 전략이다.
완전한 무중단을 보장하려면 애플리케이션의 배포 방식뿐 아니라 로드 밸런서, 데이터베이스 변경, 연결 유지, 장애 감지와 복구까지 고려해야 한다.
롤링 배포
롤링 배포는 여러 서버 중 일부를 새로운 버전으로 교체한 뒤, 나머지 서버를 순차적으로 교체하는 방식이다.
기존 서버가 서비스를 유지하는 동안 새 버전을 적용할 수 있어 추가 인프라 비용을 줄이기 쉽다.
하지만 배포 도중 구버전과 신버전이 동시에 실행되므로 API 계약, 세션 형식, 데이터베이스 스키마가 서로 호환되어야 한다. 새 버전이 정상적으로 동작하지 않으면 일부 사용자에게만 오류가 발생할 수도 있다.
블루-그린 배포
블루-그린 배포는 기존 환경인 Blue와 새 환경인 Green을 별도로 준비하고, 검증이 끝나면 트래픽을 새 환경으로 전환하는 방식이다.
새 환경을 충분히 검증한 뒤 전환할 수 있고, 문제가 발생하면 이전 환경으로 트래픽을 되돌리기 쉽다.
반면 두 환경을 동시에 유지해야 하므로 인프라 비용이 증가할 수 있다. 데이터베이스를 공유한다면 애플리케이션 버전이 달라도 데이터 구조와 처리 규칙이 호환되어야 한다.
카나리 배포
카나리 배포는 전체 트래픽을 한 번에 전환하지 않고 일부 트래픽부터 새 버전으로 전달하는 방식이다.
초기 사용자 그룹에서 오류율, 응답 시간, 서버 자원 사용량 등을 확인한 뒤 점진적으로 적용 범위를 확대한다.
새 버전의 문제를 전체 사용자에게 확산하기 전에 감지할 수 있다는 장점이 있다. 다만 트래픽 분배, 관측 지표, 자동 중단 기준을 제대로 구성해야 효과를 얻을 수 있다.
게임 서버 배포 시 주의점
일반적인 HTTP API 서버와 달리 WebSocket 서버는 배포 시 활성 연결을 고려해야 한다.
서버 프로세스를 즉시 종료하면 연결된 클라이언트의 연결이 끊어질 수 있다. 따라서 연결을 종료하기 전에 신규 연결을 차단하고, 기존 연결을 정리하거나 다른 서버로 재접속하도록 유도하는 드레이닝(Draining) 절차가 필요하다.
또한 게임 도중 서버가 종료되면 진행 중인 세션이나 매치 상태가 영향을 받을 수 있다. 중요한 상태를 외부 저장소에 관리하거나, 서버별 작업 소유권과 복구 절차를 명확하게 정의해야 한다.
장애 복구와 롤백
장애 복구는 서비스에 문제가 발생했을 때 정상 상태로 돌아가기 위한 절차다. 롤백은 배포나 설정 변경으로 문제가 발생했을 때 이전에 검증된 버전이나 설정으로 되돌리는 대응이다.
두 개념은 관련되어 있지만 동일하지 않다. 롤백은 장애 복구의 한 방법이며, 데이터 손상이나 인프라 장애처럼 애플리케이션 버전만 되돌려서는 해결되지 않는 문제도 있다.
장애 감지
장애를 빠르게 복구하려면 문제가 발생했다는 사실을 신속하게 감지해야 한다.
주요 모니터링 지표는 다음과 같다.
- HTTP 오류율과 요청 처리량
- p95·p99 응답 지연 시간
- CPU와 메모리 사용량
- 데이터베이스 연결 수와 쿼리 지연
- WebSocket 연결 수와 연결 종료율
- 이벤트 루프 지연과 메시지 처리 지연
- 인스턴스의 헬스 체크 결과
단일 지표만으로 장애를 판단하기보다 여러 지표를 함께 확인해야 한다. 예를 들어 CPU 사용률이 낮아도 데이터베이스 연결 풀이 고갈되면 API 요청이 실패할 수 있다.
장애 발생 시 복구 절차
일반적인 복구 절차는 다음과 같이 구성할 수 있다.
- 모니터링과 알림을 통해 장애를 감지한다.
- 오류가 발생한 배포, 설정 변경, 인프라 변경을 확인한다.
- 문제가 확산되지 않도록 트래픽을 차단하거나 영향 범위를 제한한다.
- 이전 버전 배포, 인스턴스 교체, 트래픽 전환 등 적절한 복구 방법을 실행한다.
- 서비스의 정상 동작과 데이터 정합성을 검증한다.
- 원인을 분석하고 재발 방지 대책을 마련한다.
장애가 발생한 상황에서는 복구 속도와 데이터 보존을 함께 고려해야 한다. 단순히 서버 프로세스가 실행되는 것만으로 복구가 완료되었다고 판단해서는 안 된다.
롤백이 실패하는 경우
애플리케이션 버전을 되돌려도 데이터베이스 스키마가 이미 변경되었다면 이전 버전이 정상적으로 실행되지 않을 수 있다.
이를 줄이려면 데이터베이스 변경을 애플리케이션 배포와 분리하고, 구버전과 신버전이 함께 사용할 수 있는 호환성 있는 변경을 우선 적용하는 것이 좋다.
예를 들어 새로운 컬럼을 추가할 때 기존 컬럼을 즉시 삭제하지 않고, 구버전이 해당 컬럼을 사용하지 않더라도 정상적으로 동작하도록 구성할 수 있다. 새 버전의 안정성을 확인한 뒤 사용하지 않는 구조를 제거한다.
또한 데이터가 이미 변경되거나 외부 시스템에 전달된 경우에는 코드 롤백만으로 원상 복구할 수 없다. 이때는 보상 작업, 데이터 복구, 재처리 등의 별도 절차가 필요하다.
실전 운영 아키텍처
AWS에서 Node.js 기반 게임 플랫폼을 운영한다고 가정하면 다음과 같은 구조를 구성할 수 있다.
Client
|
v
Route 53
|
v
Application Load Balancer
|
+---- HTTPS / API / WebSocket
|
v
EC2 Auto Scaling Group
|
+---- Node.js API Server
|
+---- WebSocket Server
|
+---- Background Worker
|
+---- Redis / ElastiCache
|
+---- RDS
Route 53은 서비스 도메인을 ALB에 연결한다. ALB는 HTTPS 연결을 처리하고, 요청 규칙에 따라 적절한 대상 그룹으로 트래픽을 전달한다.
EC2 Auto Scaling Group은 서버의 수를 조정하고, ALB의 헬스 체크를 통해 정상적인 대상에 트래픽을 전달하도록 구성할 수 있다.
ElastiCache는 세션, 캐시, 분산 상태 관리 등에 활용할 수 있으며, RDS는 영속적인 관계형 데이터를 저장한다. 다만 Redis를 사용한다고 해서 모든 세션과 게임 상태의 정합성이 자동으로 보장되는 것은 아니다. 데이터의 소유권과 동시성 제어 정책은 애플리케이션에서 별도로 설계해야 한다.
배포 과정에서는 새 버전의 정상 여부를 확인한 뒤 트래픽을 전환하고, 오류율이나 지연 시간이 기준을 초과하면 배포를 중단하거나 이전 버전으로 되돌리도록 구성한다.
운영 체크리스트
- DNS 레코드와 도메인 연결 상태를 확인한다.
- HTTPS와 TLS 인증서의 유효 기간 및 갱신을 관리한다.
- ALB의 대상 그룹과 헬스 체크를 구성한다.
- WebSocket의 타임아웃, heartbeat, 재접속 정책을 설계한다.
- 서버 상태와 세션을 고려해 로드 밸런싱 구조를 설계한다.
- Auto Scaling의 확장·축소 기준과 최소·최대 용량을 설정한다.
- 배포 시 구버전과 신버전의 호환성을 확인한다.
- 배포 실패 시 자동 중단과 롤백 기준을 마련한다.
- 오류율, 지연 시간, 연결 수, 데이터베이스 상태를 모니터링한다.
- 장애 복구와 데이터 복구 절차를 실제로 테스트한다.