TokyoAJ

도쿄아재

AWS 2025.05.21

AWS Lambda를 활용한 WebSocket 서비스 구현하기

실시간 통신이 필요한 웹 애플리케이션에서 WebSocket은 필수적인 기술입니다. 이 글에서는 AWS Lambda와 API Gateway를 활용하여 확장성 있는 서버리스 WebSocket 서비스를 구현하는 방법을 자세히 알아보겠습니다.


전체 아키텍처 개요

이 서비스는 다음과 같은 AWS 서비스로 구성됩니다:

  1. API Gateway - WebSocket 연결을 관리하는 엔드포인트
  2. Lambda 함수 - 연결, 연결 해제, 메시지 전송을 처리
  3. DynamoDB - 클라이언트 연결 정보를 저장


세 개의 Lambda 함수가 각각 다른 WebSocket 이벤트를 처리합니다:

  1. onConnect.py - 클라이언트 연결 처리
  2. onDisconnect.py - 클라이언트 연결 해제 처리
  3. sendMessage.py - 클라이언트 간 메시지 전송 처리


클라이언트 연결 처리 (onConnect)

def lambda_handler(event, context):
# WebSocket 연결 ID 추출
connection_id = event.get('requestContext',{}).get('connectionId')
# UUID 파라미터 추출 (쿼리 파라미터 또는 요청 본문)
query_params = event.get('queryStringParameters', {}) or {}
room_uuid = query_params.get('uuid')
# 요청 본문에서 UUID 확인
if not room_uuid and event.get('body'):
try:
body = json.loads(event.get('body'))
room_uuid = body.get('uuid')
except (json.JSONDecodeError, TypeError):
pass
# UUID 검증 및 DynamoDB에 저장
# ...

연결 핸들러는 다음과 같은 작업을 수행합니다.

  1. 클라이언트의 연결 ID를 추출합니다.
  2. 쿼리 파라미터나 요청 본문에서 UUID를 추출합니다.
  3. UUID가 없거나 유효하지 않으면 오류를 반환합니다.
  4. 유효한 UUID인 경우, 연결 ID와 UUID를 DynamoDB 테이블에 저장합니다.

UUID는 "룸" 또는 "채널" 개념으로 사용되어, 특정 그룹에 메시지를 전송할 때 활용됩니다. 이는 채팅방이나 게임 세션과 같은 사용 사례에 적합합니다.


클라이언트 연결 해제 처리 (onDisconnect)

def lambda_handler(event, context):
# WebSocket 연결 ID 추출
connection_id = event.get('requestContext',{}).get('connectionId')
# 연결 정보 조회 (로깅용)
try:
connection_data = connections.get_item(Key={'id': connection_id})
if 'Item' in connection_data:
uuid = connection_data['Item'].get('uuid')
logger.info(f"연결 해제: ID={connection_id}, UUID={uuid}")
except Exception as e:
logger.warning(f"연결 정보 조회 중 오류: {str(e)}")
# DynamoDB에서 연결 정보 삭제
connections.delete_item(Key={'id': connection_id})

연결 해제 핸들러는 다음과 같은 작업을 수행합니다.

  1. 연결 해제된 클라이언트의 연결 ID를 추출합니다.
  2. DynamoDB에서 해당 연결의 정보를 조회하여 로깅합니다.
  3. DynamoDB에서 해당 연결 정보를 삭제합니다.

이 과정을 통해 더 이상 활성화되지 않은 연결을 데이터베이스에서 제거하여 리소스를 효율적으로 관리합니다.


메시지 전송 처리 (sendMessage)

def lambda_handler(event, context):
# 클라이언트에서 받은 데이터 파싱
request_body = json.loads(event.get('body', '{}'))
post_data = request_body.get('data')
target_uuid = request_body.get('uuid') # 대상 UUID
# API Gateway 정보 가져오기
domain_name = event.get('requestContext',{}).get('domainName')
stage = event.get('requestContext',{}).get('stage')
current_connection_id = event.get('requestContext',{}).get('connectionId')
# 동적 엔드포인트 URL 생성
endpoint_url = f"https://{domain_name}/{stage}"
# DynamoDB에서 연결 ID 스캔 - UUID 기준 필터링
if target_uuid:
response = connections.scan(
FilterExpression=Attr('uuid').eq(target_uuid)
)
else:
items = connections.scan(ProjectionExpression='id,uuid').get('Items', [])

메시지 전송 핸들러는 더 복잡한 작업을 수행합니다.

1.클라이언트로부터 받은 메시지 데이터와 대상 UUID를 추출합니다.

2.API Gateway 엔드포인트 URL을 구성합니다.

3.두 가지 모드로 작동합니다.

특정 UUID가 지정된 경우: 해당 UUID에 연결된 클라이언트에만 메시지를 전송

UUID가 지정되지 않은 경우: 모든 연결된 클라이언트에 브로드캐스트

4.메시지에 발신자 UUID 정보를 추가합니다.

5.연결된 모든 대상 클라이언트에 메시지를 전송합니다.

6.종료된 연결을 감지하여 DynamoDB에서 자동으로 정리합니다.


구현의 주요 특징

1. UUID 기반 룸 시스템

이 구현의 핵심은 UUID를 사용한 "룸" 개념입니다. 클라이언트는 연결 시 UUID를 제공해야 하며, 이 UUID는 클라이언트 그룹을 구분하는 데 사용됩니다.

  1. 특정 그룹에만 메시지 전송 가능
  2. 다중 채팅방, 게임 세션 등 구현 가능
  3. 다양한 애플리케이션 요구사항에 맞게 확장 가능


2. 자동 연결 관리

연결 해제 시 자동으로 DynamoDB에서 데이터가 삭제됩니다. 또한 메시지 전송 시 존재하지 않는 연결이 감지되면 자동으로 정리하는 기능이 포함되어 있습니다.

  1. 오래된 연결 정보로 인한 리소스 낭비 방지
  2. 메시지 전송 실패 시 연결 상태 자동 갱신
  3. 시스템 안정성과 성능 최적화


3. 상세한 로깅 시스템

모든 Lambda 함수에는 상세한 로깅이 포함되어 있어 문제 해결과 모니터링이 용이합니다.

  1. 연결/연결 해제 이벤트 로깅
  2. 메시지 전송 성공/실패 로깅
  3. 오류 상황에 대한 자세한 정보 기록


실제 활용 사례

이 WebSocket 구현은 다음과 같은 애플리케이션에 적합합니다.

  1. 실시간 채팅 서비스 - UUID를 채팅방 ID로 활용
  2. 멀티플레이어 게임 - 게임 세션별로 UUID 할당
  3. 실시간 협업 도구 - 문서나 프로젝트별로 UUID 할당
  4. IoT 애플리케이션 - 장치 그룹별로 UUID 할당하여 제어 신호 전송


확장 방안

이 구현은 다음과 같이 확장할 수 있습니다.

  1. 사용자 인증 추가 - JWT 토큰이나 Cognito를 활용한 사용자 인증
  2. 메시지 영속성 - 중요 메시지를 DynamoDB에 저장하여 오프라인 클라이언트를 위한 히스토리 제공
  3. 메시지 필터링 - 특정 조건에 따라 메시지를 필터링하거나 변환
  4. 웹훅 통합 - 특정 이벤트 발생 시 외부 서비스 호출


결론

AWS Lambda, API Gateway, DynamoDB를 활용한 이 WebSocket 구현은 서버리스 아키텍처의 장점을 최대한 활용합니다. 확장성, 유지보수 용이성, 비용 효율성을 모두 갖춘 이 구현은 다양한 실시간 통신 요구사항을 충족할 수 있습니다.


특히 UUID를 활용한 룸 시스템은 다양한 사용 사례에 맞게 유연하게 적용할 수 있으며, 자동화된 연결 관리 시스템은 서비스의 안정성을 향상시킵니다.







댓글