API Gateway WebSocket API를 사용한 데이터 상태 업데이트
Source: Dev.to
TL;DR
Amazon API Gateway의 WebSocket API를 사용하면 프런트엔드가 최신 데이터를 실시간에 가깝게 유지할 수 있어, 상태 알림을 위해 REST API 엔드포인트를 폴링하는 방식에 대한 실시간 대안을 제공합니다.
시나리오
클릭‑데이터 처리 애플리케이션을 운영한다고 가정합니다. 고객이 페이지의 링크와 버튼을 클릭하면 애플리케이션이 클릭 수와 유형을 기록합니다. 권한이 부여된 브라우저 기반 대시보드가 현재 클릭 수를 표시합니다. 프런트엔드는 데이터를 표시할 뿐이며 비즈니스 로직은 없습니다.
클릭 결과는 데이터베이스에 저장되고 백엔드에서 클라이언트가 조회합니다. 문제는 현재 클릭‑카운트 상태를 실시간에 가깝게 어떻게 표시할 것인가 입니다.
요구 사항
- 대시보드가 실시간 또는 실시간에 가깝게 클릭을 표시해야 함.
- 사람의 개입을 최소화하고 가능한 한 자동화된 솔루션이어야 함.
- 클릭 결과는 데이터베이스에 영구 저장되어야 함.
- 솔루션은 확장 가능해야 함.
- 아키텍처는 확장 가능하고 다른 비즈니스 시나리오에서도 재사용할 수 있어야 함.
- 인프라는 AWS에 호스팅되고 서버리스여야 함.
옵션
| 접근 방식 | 장점 | 단점 |
|---|---|---|
| 폴링 | 구현이 간단하고 기존 REST API와 바로 사용할 수 있음. | 규모가 커질수록 비용이 많이 들고 지연이 발생하며 폴러 관리(간격, 정리)가 필요함. |
| WebSocket | 푸시 기반, 실시간에 가까운 업데이트; 네트워크 트래픽 감소; 폴러 로직 불필요. | WebSocket API 설정 및 연결‑ID 관리가 필요함. |
테스트 결과 폴링은 합리적이지만 비용이 많이 들어 WebSocket 접근 방식을 선택하게 되었습니다.
아키텍처 개요
다이어그램은 생략되었습니다.
아키텍처는 다음으로 구성됩니다:
- Ingestion –
/ingestREST 엔드포인트(API Gateway) →IngestClickDataLambda → DynamoDB 테이블. - WebSocket API –
$connect,$disconnect,$default라우트. - Connection‑ID 영구 저장 –
PersistConnectionIdsLambda가 연결 ID를 DynamoDB에 저장. - 스트림 처리 – DynamoDB Streams가
StreamProcessorLambda를 트리거하고, 이 Lambda가 모든 연결된 클라이언트에 클릭 업데이트를 브로드캐스트. - 대시보드 클라이언트 – WebSocket API에 연결하고 실시간 클릭 상태 메시지를 수신.
사전 요구 사항
- API Gateway(REST & WebSocket), Lambda, DynamoDB, DynamoDB Streams를 생성할 수 있는 권한이 있는 AWS 계정.
- 인프라‑코드(IaC) 도구(예: AWS CDK)에 익숙하면 도움이 되지만 필수는 아님.
구현 세부 사항
Ingestion
사용자가 요소를 클릭하면 프런트엔드가 클릭 데이터를 /ingest REST 엔드포인트로 전송합니다. IngestClickData Lambda가 페이로드를 검증(및 선택적 변환)하고 PutItem 작업으로 DynamoDB에 기록합니다.
Note: 검증/변환이 필요하지 않다면 API Gateway가 직접 DynamoDB에 기록하도록 할 수 있어 Lambda를 없애고 수십 밀리초를 절감할 수 있습니다.
대시보드 연결 (WebSocket 클라이언트)
// connectWebSocket.js
function connectWebSocket() {
// 1. Create the WebSocket object
const ws = new WebSocket(WEBSOCKET_URL);
// 2. Connection opened
ws.onopen = () => {
updateConnectionStatus(ConnectionStatus.CONNECTED);
};
// 3. Message received
ws.onmessage = handleMessage;
// 4. Connection closed
ws.onclose = (event) => {
updateConnectionStatus(ConnectionStatus.DISCONNECTED);
// Optional reconnection logic here
};
// 5. Error occurred
ws.onerror = (error) => {
updateConnectionStatus(ConnectionStatus.DISCONNECTED);
// onerror is always followed by onclose
};
}
WEBSOCKET_URL은 REST API와 동일한 패턴을 따릅니다. 예:
wss://.execute-api.eu-central-1.amazonaws.com//
IaC(예: CDK)를 사용할 경우, 빌드 시점에 URL을 클라이언트 번들에 주입할 수 있습니다.
WebSocket 라우트
- $connect –
PersistConnectionIdsLambda를 트리거하여 생성된 연결 ID를 DynamoDB에 저장합니다. - $disconnect –
DeleteConnectionIdsLambda를 트리거하여 대시보드 클라이언트가 떠날 때 연결 ID를 삭제합니다. - $default – 이 예제에서는 사용되지 않으며, fallback 용도로만 존재합니다.
DynamoDB Streams & StreamProcessor
IngestClickData가 새로운 클릭 레코드를 DynamoDB에 기록하면 Streams 이벤트가 발생합니다. StreamProcessor Lambda가 이 이벤트를 소비하고, 클릭‑데이터 항목을 필터링한 뒤, 저장된 모든 연결 ID에 WebSocket API를 통해 업데이트를 브로드캐스트합니다.
클릭 데이터와 연결 ID를 동일 테이블에 저장한다면, 이벤트 필터를 사용해 불필요한 호출을 줄일 수 있습니다:
// CDK example – filter for items where entityType = 'CLICK'
streamProcessorLambda.addEventSource(
new lambdaEventSources.DynamoEventSource(clickstreamTable, {
// ... other properties
filters: [
lambda.FilterCriteria.filter({
dynamodb: {
NewImage: {
entityType: {
S: lambda.FilterRule.isEqual('CLICK')
}
}
}
})
]
})
);
클릭 데이터 브로드캐스트
StreamProcessor는 DynamoDB에서 모든 활성 연결 ID를 조회하고, API Gateway Management API를 사용해 각 클라이언트에 메시지를 전송합니다:
// Pseudo‑code
for (const connId of connectionIds) {
await apigatewaymanagementapi.postToConnection({
ConnectionId: connId,
Data: JSON.stringify(clickStatus)
}).promise();
}
클릭 결과 수신 (클라이언트 측)
function handleMessage(event) {
const data = JSON.parse(event.data);
// Update UI with the new click count
updateClickCount(data.count);
}
논의 포인트
REST API가 필요 없을까?
인제스트 경로에서 검증이 전혀 필요하지 않다면 REST API를 건너뛰고 API Gateway가 직접 DynamoDB에 기록하도록 할 수 있어, 지연과 비용을 더욱 낮출 수 있습니다.
비동기 워크플로우
아키텍처는 자연스럽게 비동기 처리를 지원합니다. 클릭 이벤트가 저장·스트리밍·브로드캐스트되는 동안 클라이언트는 블로킹되지 않습니다.
유연성
- 테이블 분리 – 클릭 데이터와 연결 ID를 별도 테이블에 저장하면 관심사의 명확한 분리가 가능합니다.
- 추가 소비자 – 동일한 DynamoDB Stream에 다른 서비스(예: 분석, 알림)를 구독시킬 수 있습니다.
- 스케일링 – Lambda 동시 실행 수와 DynamoDB 프로비저닝 용량을 자동으로 조정할 수 있습니다.
요약
REST 인제스트 엔드포인트, DynamoDB Streams, API Gateway WebSocket API를 결합함으로써 클라이언트‑측 폴링의 부하 없이 실시간에 가까운 대시보드 업데이트를 구현했습니다. 이 솔루션은 완전 서버리스이며, 확장 가능하고 다양한 비즈니스 시나리오에 재사용할 수 있습니다.