📈 실시간 데이터 대시보드

120

왜 이걸 만들까? — 5분 전 데이터는 이미 늦었다

여러분이 라이브 커머스 플랫폼의 운영 엔지니어라고 상상해 보세요.

실시간 데이터 대시보드 아키텍처 — Kinesis + Lambda + DynamoDB

인기 인플루언서가 8시에 라이브 방송을 시작합니다. 방송 시작과 동시에 동시 접속자가 1만 명을 넘기고, 주문이 초당 수십 건씩 쏟아집니다. 그런데 갑자기 결제 성공률이 급락합니다.

5분 뒤에 알면? 이미 수백 명이 결제에 실패하고 이탈합니다. 매출 손실은 수천만 원. 10초 안에 알면? 즉시 결제 서비스 상태를 확인하고, 대체 결제 수단을 활성화할 수 있습니다.

이것이 실시간 데이터 대시보드의 가치입니다.

기존 배치 분석은 "어제 무슨 일이 있었는지" 사후 보고에 적합합니다. 하지만 "지금 무슨 일이 일어나고 있는지"를 파악하려면 실시간 스트리밍 파이프라인이 필요합니다.

이 실습에서는 AWS의 실시간 데이터 서비스를 조합하여 서버 모니터링 대시보드 파이프라인을 구축합니다:

  • Kinesis Data Streams: 초당 수천 건의 메트릭 이벤트를 수집하는 실시간 스트림
  • Lambda (프로듀서): 서버 CPU, 메모리, 요청 수 등 시뮬레이션 데이터를 생성
  • Lambda (컨슈머): 스트림 레코드를 1분 단위로 집계 (평균, 최대, 최소)
  • DynamoDB: 집계된 시계열 데이터를 저장 (TTL로 자동 삭제)
  • API Gateway: 대시보드 클라이언트가 데이터를 조회하는 API

완성하면 1분마다 서버 메트릭이 자동으로 수집 → 집계 → 저장되고, API를 통해 최근 1시간의 CPU 사용률 추이를 조회할 수 있습니다.

이 프로젝트를 통해 배우게 되는 것:

  • 실시간 스트리밍 처리: Kinesis Data Streams의 프로듀서/컨슈머 패턴
  • 이벤트 소스 매핑: Kinesis → Lambda 자동 트리거 구성
  • 시계열 데이터 설계: DynamoDB에서 파티션 키 + 정렬 키를 활용한 시계열 테이블
  • TTL 활용: DynamoDB 자동 데이터 삭제로 비용 최적화
  • 배치 vs 스트리밍: 두 처리 방식의 근본적 차이와 각각의 적합한 사용 사례

실습을 시작하기 전에 AWS 콘솔에 로그인되어 있는지 확인하세요. 리전은 ap-northeast-2 (서울) 을 사용합니다.

아키텍처 개요

Kinesis 실시간 데이터 스트리밍 아키텍처

데이터 파이프라인 흐름

다이어그램 로딩 중...
실시간 스트리밍 데이터 파이프라인

비용 예측

비용 계산기

4시간
0h24h
50 GB
0 GB100 GB
Kinesis Data Streams (1 샤드)

시간

$0.0600
Kinesis PUT 요청

백만 건

$0.7000
DynamoDB (온디맨드)

백만 쓰기

$62.5000
Lambda

100만 요청당 $0.20 + 실행시간

$0.0080
예상 총 비용$63.2680

* 실제 비용은 AWS 요금 정책에 따라 달라질 수 있습니다.

Step 1: Kinesis Data Streams 생성

Kinesis Data Streams는 이 파이프라인의 중앙 데이터 고속도로입니다. 프로듀서가 보낸 레코드를 시간순으로 저장하고, 컨슈머가 순차적으로 읽어갈 수 있게 합니다. 온디맨드 모드를 선택하면 트래픽에 따라 자동으로 샤드 수가 조절됩니다.

  1. AWS 콘솔 → Kinesis 서비스 이동 → 좌측 메뉴 Data Streams 선택
  2. 데이터 스트림 생성 클릭
  3. 스트림 이름: realtime-metrics-stream
  4. 용량 모드: 온디맨드 선택 (트래픽에 따라 자동 스케일, 실습에 적합)
  5. 데이터 스트림 생성 클릭 → 상태가 "활성"이 될 때까지 대기 (약 30초)
  6. 스트림 세부 정보에서 ARN을 복사하여 메모 (Lambda 트리거 설정에 필요)
코드
aws kinesis create-stream \
  --stream-name realtime-metrics-stream \
  --stream-mode-details StreamMode=ON_DEMAND \
  --region ap-northeast-2

온디맨드 모드는 트래픽에 따라 자동으로 샤드 수를 조절합니다. 실습에서는 비용을 최소화할 수 있어 적합하지만, 프로덕션에서는 트래픽이 예측 가능하다면 프로비저닝 모드가 비용 예측에 유리합니다. 온디맨드 모드의 최소 비용은 시간당 약 $0.015입니다.

Step 2: DynamoDB 시계열 테이블 생성

시계열(Time Series) 데이터에 최적화된 DynamoDB 테이블을 설계합니다. 파티션 키로 메트릭 유형(cpu_usage, memory_usage 등)을, 정렬 키로 타임스탬프를 사용하면, 특정 메트릭의 시간 범위 쿼리가 매우 효율적입니다. TTL을 설정하면 오래된 데이터가 자동 삭제되어 비용을 절약합니다.

진행률 0/8
  1. 1DynamoDB 콘솔 → 테이블 생성 클릭
  2. 2테이블 이름: realtime-metrics
  3. 3파티션 키: metric_type (String) — 예: cpu_usage, memory_usage, request_count
  4. 4정렬 키: timestamp (Number) — Unix 타임스탬프(초 단위) 사용
  5. 5용량 모드: 온디맨드 선택 (실습용 최적)
  6. 6테이블 생성 완료 후 → 추가 설정 탭 → TTL(Time To Live) 관리 클릭
  7. 7TTL 속성 이름: expiry 입력 → 활성화 → 24시간(86400초) 후 자동 삭제 설정
  8. 8테이블 상태가 "활성"인지 확인

TTL(Time To Live)을 설정하면 오래된 시계열 데이터가 자동 삭제됩니다. 실습에서는 24시간(86400초)으로 설정하여 불필요한 데이터 축적을 방지하세요. TTL 삭제는 보통 설정된 시간 후 48시간 이내에 이루어지며, 삭제에 대한 추가 비용은 없습니다.

시계열 테이블 설계 주의: 파티션 키를 timestamp로 설정하면 안 됩니다. DynamoDB는 파티션 키 기준으로 데이터를 분산하므로, 타임스탬프를 파티션 키로 쓰면 최신 시간대의 파티션에 쓰기가 집중되어 핫 파티션(Hot Partition) 문제가 발생합니다. 파티션 키는 metric_type, 정렬 키는 timestamp가 올바른 설계입니다.

Step 3: 데이터 프로듀서 Lambda 작성

프로듀서 Lambda는 실제 서버에서 메트릭을 수집하는 에이전트를 시뮬레이션합니다. CPU 사용률(0100%), 메모리 사용률(4095%), 초당 요청 수(10~500)를 랜덤으로 생성하여 Kinesis에 전송합니다. EventBridge 규칙으로 1분마다 자동 실행되도록 설정합니다.

  1. Lambda 콘솔 → 함수 생성 → 이름: metrics-producer
  2. 런타임: Python 3.12, 아키텍처: arm64
  3. 실행 역할에 AmazonKinesisFullAccess 정책 추가
  4. 환경 변수: STREAM_NAME = realtime-metrics-stream
  5. 코드 작성 핵심:
    • import random, json, time, boto3
    • 3종 메트릭(cpu_usage, memory_usage, request_count) 각각 랜덤 값 생성
    • kinesis.put_records()로 3건의 레코드를 한 번에 전송
    • PartitionKey는 metric_type 값 사용 (같은 메트릭은 같은 샤드로)
  6. Deploy 클릭 → 테스트로 수동 실행 → Kinesis 모니터링 탭에서 레코드 수신 확인
  7. EventBridge 규칙 생성: 스케줄rate(1 minute) → 대상: metrics-producer Lambda
  8. 규칙 활성화 후 1~2분 대기 → Lambda 실행 로그 확인
코드
aws lambda create-function \
  --function-name metrics-producer \
  --runtime python3.12 \
  --handler lambda_function.lambda_handler \
  --role arn:aws:iam::YOUR_ACCOUNT:role/lambda-kinesis-role \
  --timeout 30 --memory-size 128 \
  --zip-file fileb://producer.zip

EventBridge 규칙 삭제를 잊지 마세요: 1분 간격으로 Lambda를 호출하는 규칙은 실습 완료 후 반드시 비활성화 또는 삭제해야 합니다. 방치하면 Lambda가 무한히 호출되어 Kinesis 쓰기 비용이 누적됩니다. 프리티어 범위 내라면 Lambda 비용은 없지만, Kinesis PUT 비용은 발생합니다.

중간 점검: 프로듀서 → Kinesis 연결 확인

Step 4로 넘어가기 전에, 프로듀서가 Kinesis에 정상적으로 레코드를 전송하는지 반드시 확인합니다:

  • Lambda 콘솔에서 metrics-producer를 수동 테스트 실행
  • CloudWatch 로그에서 "Successfully put 3 records" 등의 성공 메시지 확인
  • Kinesis 콘솔 → realtime-metrics-stream모니터링 탭에서 "수신 레코드" 그래프에 데이터 포인트가 찍히는지 확인
  • 데이터가 보이지 않으면: Lambda 실행 역할에 AmazonKinesisFullAccess 정책이 있는지, 스트림 이름이 정확한지 확인

여기까지 성공했으면 컨슈머를 만들어 연결합니다.

Step 4: 컨슈머 Lambda (집계 로직) 작성

컨슈머 Lambda는 Kinesis 스트림에 새 레코드가 도착할 때 자동으로 트리거됩니다. 배치(batch) 단위로 레코드를 받아, 메트릭 유형별로 1분 단위 통계(평균, 최대, 최소, 데이터 포인트 수)를 계산하고, DynamoDB에 저장합니다.

진행률 0/9
  1. 1Lambda 콘솔 → 함수 생성 → 이름: metrics-consumer
  2. 2런타임: Python 3.12, 아키텍처: arm64
  3. 3실행 역할에 AmazonDynamoDBFullAccess + AWSLambdaKinesisExecutionRole 정책 추가
  4. 4환경 변수: TABLE_NAME = realtime-metrics
  5. 5트리거 추가 → Kinesis → realtime-metrics-stream 선택
  6. 6배치 크기: 100 (한 번에 최대 100개 레코드 처리)
  7. 7시작 위치: 최신(LATEST) — 지금부터 들어오는 새 레코드만 처리
  8. 8코드 작성 핵심: Kinesis 레코드를 base64 디코딩 → JSON 파싱 메트릭 유형별로 값을 모아 평균(avg), 최대(max), 최소(min), 개수(count) 계산 현재 시각의 1분 단위 타임스탬프 생성 (예: 1700000060) DynamoDB batch_write_item()으로 집계 결과 저장 expiry 필드에 현재 시각 + 86400(24시간) 설정 (TTL용)
  9. 9Deploy 클릭

Step 5: API Gateway 조회 엔드포인트

대시보드 클라이언트가 DynamoDB에 저장된 집계 데이터를 조회하는 API를 구성합니다. 쿼리 파라미터로 메트릭 유형과 시간 범위를 지정하면, 해당 범위의 시계열 데이터를 JSON 배열로 반환합니다.

  1. Lambda 콘솔 → 함수 생성 → 이름: metrics-query-handler
  2. 코드: DynamoDB Querymetric_type = 파라미터, timestamp BETWEEN start_time AND end_time
  3. API Gateway 콘솔 → REST API생성 → 이름: metrics-dashboard-api
  4. 리소스 /metrics 생성 → GET 메서드 추가
  5. 쿼리 파라미터 설정: metric_type (필수), start_time (선택), end_time (선택)
  6. Lambda 통합: metrics-query-handler 연결
  7. CORS 활성화 → API 배포 → 스테이지: dev
  8. 배포 URL 복사하여 테스트
코드
# API 테스트 — 최근 1시간 CPU 사용률 조회
curl "https://YOUR_API_ID.execute-api.ap-northeast-2.amazonaws.com/dev/metrics?metric_type=cpu_usage&start_time=1700000000&end_time=1700003600"
✏️

본인의 말로 설명해 보세요

비개발자 팀원에게 '배치 처리와 실시간 스트리밍 처리의 차이'를 우편(배치)과 전화(스트리밍) 비유로 설명해 보세요.

Step 6: 통합 테스트

전체 파이프라인이 끊김 없이 동작하는지 단계별로 검증합니다. 프로듀서 → Kinesis → 컨슈머 → DynamoDB → API의 전체 흐름을 확인합니다.

진행률 0/7
  1. 1프로듀서 Lambda 테스트 이벤트로 수동 실행 → CloudWatch 로그에서 "3 records sent to Kinesis" 메시지 확인
  2. 2Kinesis 콘솔 → realtime-metrics-stream → 모니터링 탭에서 "수신 레코드" 그래프에 데이터가 표시되는지 확인
  3. 3컨슈머 Lambda CloudWatch 로그(/aws/lambda/metrics-consumer)에서 집계 처리 로그 확인
  4. 4DynamoDB 콘솔 → realtime-metrics 테이블 → 항목 탐색에서 저장된 시계열 데이터 확인 metric_type = cpu_usage, timestamp, avg, max, min, count, expiry 필드 존재 확인
  5. 5API Gateway 테스트: GET /metrics?metric_type=cpu_usage → JSON 배열 응답 확인
  6. 6EventBridge 규칙을 활성화하고 5분간 모니터링 → 1분 간격으로 데이터가 축적되는지 확인
  7. 75분 후 API로 다시 조회 → 5개의 시계열 데이터 포인트가 반환되는지 확인

핵심 개념 확인

트러블슈팅 가이드

컨슈머 Lambda가 트리거되지 않을 때:

  • Kinesis 스트림 상태가 "활성"인지 확인
  • Lambda 트리거 목록에 Kinesis가 표시되는지 확인 — 없으면 트리거 재추가
  • Lambda 실행 역할에 AWSLambdaKinesisExecutionRole 정책이 있는지 확인
  • 프로듀서가 실제로 레코드를 전송했는지 Kinesis 모니터링 그래프 확인

DynamoDB에 데이터가 저장되지 않을 때:

  • 컨슈머 Lambda CloudWatch 로그에서 에러 메시지 확인
  • 테이블 이름(realtime-metrics)이 환경 변수와 정확히 일치하는지 확인
  • Lambda 실행 역할에 DynamoDB 쓰기 권한이 있는지 확인
  • Kinesis 레코드의 base64 디코딩이 올바르게 이루어지는지 확인: base64.b64decode(record['kinesis']['data'])

API 응답이 빈 배열일 때:

  • DynamoDB 콘솔에서 실제로 데이터가 저장되어 있는지 확인
  • API 쿼리 파라미터의 start_time, end_time이 데이터가 있는 시간 범위와 겹치는지 확인
  • Lambda Query 코드에서 KeyConditionExpression이 올바른지 확인
  • DynamoDB TTL이 데이터를 이미 삭제했을 수 있음 — 최근 데이터로 테스트

완성 후 테스트 가이드

전체 실시간 파이프라인을 아래 체크리스트로 검증하세요:

  1. 프로듀서 동작: 수동 실행 후 Kinesis 모니터링에서 레코드 수신 확인
  2. 스트림 전달: Kinesis → 컨슈머 Lambda가 트리거되어 CloudWatch 로그에 처리 결과 기록
  3. 집계 저장: DynamoDB 항목 탐색에서 metric_type, timestamp, avg, max, min 필드 확인
  4. TTL 설정: expiry 필드가 현재 시각 + 86400(초)으로 설정되어 있는지 확인
  5. API 조회: GET /metrics?metric_type=cpu_usage → 시계열 JSON 배열 반환
  6. 자동 실행: EventBridge 활성화 후 5분 대기 → 5개 이상의 데이터 포인트 축적 확인
  7. 지연 시간 측정: 프로듀서 실행 시각과 DynamoDB 저장 시각의 차이 측정 (목표: 30초 이내)
  8. 비용 확인: Kinesis 콘솔에서 PUT 레코드 수, DynamoDB 쓰기 요청 수를 모니터링
  9. 스트림 모니터링: Kinesis 메트릭에서 IteratorAge(컨슈머 지연)가 0에 가까운지 확인

확장 아이디어

  1. 실시간 대시보드 UI: React + Chart.js로 프론트엔드를 만들고, 5초마다 API를 폴링하여 실시간 차트 렌더링
  2. 임계값 알림: 컨슈머 Lambda에서 CPU 사용률이 90%를 넘으면 SNS로 경고 이메일 발송
  3. Kinesis Data Firehose 연동: 원본 레코드를 S3에 자동 아카이빙하여, 나중에 Athena로 장기 분석
  4. 다중 메트릭 대시보드: 네트워크 트래픽, 디스크 I/O, 에러율 등 메트릭을 추가하여 종합 모니터링
  5. CloudWatch 커스텀 메트릭 연동: DynamoDB 대신 CloudWatch에 커스텀 메트릭으로 발행하여 CloudWatch 대시보드 활용

Kinesis 프로듀서 코드 핵심 구조

프로듀서 Lambda의 핵심 코드를 이해하면 실습이 수월합니다:

코드
import json, random, time, os, boto3
 
kinesis = boto3.client('kinesis', region_name='ap-northeast-2')
STREAM_NAME = os.environ['STREAM_NAME']
 
def lambda_handler(event, context):
    timestamp = int(time.time())
    records = [
        {
            'Data': json.dumps({
                'metric_type': 'cpu_usage',
                'value': round(random.uniform(10, 95), 2),
                'timestamp': timestamp
            }),
            'PartitionKey': 'cpu_usage'
        },
        {
            'Data': json.dumps({
                'metric_type': 'memory_usage',
                'value': round(random.uniform(40, 90), 2),
                'timestamp': timestamp
            }),
            'PartitionKey': 'memory_usage'
        },
        {
            'Data': json.dumps({
                'metric_type': 'request_count',
                'value': random.randint(10, 500),
                'timestamp': timestamp
            }),
            'PartitionKey': 'request_count'
        }
    ]
    
    response = kinesis.put_records(
        StreamName=STREAM_NAME,
        Records=records
    )
    
    failed = response['FailedRecordCount']
    return {'statusCode': 200, 'sent': len(records), 'failed': failed}

put_records()는 여러 레코드를 한 번의 API 호출로 전송합니다 (최대 500건). PartitionKeymetric_type으로 설정하면 같은 메트릭 데이터가 같은 샤드에 순서대로 저장됩니다. FailedRecordCount를 확인하여 부분 실패를 감지하고 재시도 로직을 구현할 수 있습니다.

학습 정리

핵심 치트시트

Kinesis Data Streams, Lambda, DynamoDB, API Gateway를 조합하여 실시간 서버 메트릭 수집/집계/조회 파이프라인을 구축했습니다. 프로듀서가 1분마다 메트릭을 Kinesis에 전송하고, 컨슈머가 자동으로 집계하여 DynamoDB에 저장합니다. API Gateway를 통해 시계열 데이터를 조회할 수 있는 대시보드 백엔드를 완성했습니다.

핵심 개념

  • Kinesis Data Streams실시간 데이터 스트리밍 서비스. 초당 수천~수백만 건의 레코드를 수집하고 24시간~365일 보존합니다. 샤드(Shard) 단위로 처리량을 확장하며, Lambda, KCL 등 다양한 컨슈머와 연동됩니다.
  • 샤드 (Shard)Kinesis의 처리량 단위. 각 샤드는 초당 1MB 쓰기(1,000 레코드), 2MB 읽기 용량을 제공합니다. 온디맨드 모드에서는 자동으로 조절되고, 프로비저닝 모드에서는 직접 샤드 수를 지정합니다.
  • 파티션 키 (Partition Key)레코드를 어느 샤드에 배치할지 결정하는 키. 같은 파티션 키의 레코드는 같은 샤드에 순서대로 저장됩니다. metric_type을 파티션 키로 쓰면 같은 메트릭 데이터가 순서 보장됩니다.
  • 이벤트 소스 매핑Kinesis 스트림과 Lambda를 연결하는 매커니즘. Lambda 서비스가 스트림을 폴링하여 새 레코드를 감지하면 자동으로 Lambda 함수를 호출합니다. 배치 크기, 시작 위치, 동시 실행 수 등을 설정합니다.
  • 시계열 데이터 설계DynamoDB에서 시계열 데이터는 metric_type(파티션 키) + timestamp(정렬 키)로 설계합니다. 특정 메트릭의 시간 범위 Query가 효율적이며, TTL로 오래된 데이터를 자동 삭제합니다.
  • TTL (Time To Live)DynamoDB 항목에 만료 시각을 지정하면 해당 시각 이후 자동 삭제되는 기능. 삭제에 대한 추가 쓰기 비용이 없어 시계열/세션/캐시 데이터 정리에 적합합니다.

흔한 실수

  • EventBridge 스케줄 규칙을 실습 후 삭제/비활성화하지 않아 Lambda가 무한 호출
  • Kinesis 레코드의 base64 디코딩을 빠뜨려 컨슈머에서 JSON 파싱 에러
  • DynamoDB 시계열 테이블에서 timestamp를 파티션 키로 설정하여 핫 파티션 발생
  • Lambda 트리거의 시작 위치를 TRIM_HORIZON으로 설정하여 과거 테스트 데이터까지 재처리
  • 컨슈머 Lambda에서 DynamoDB batch_write 실패 시 재시도 로직 미구현
  • Kinesis 온디맨드 모드의 최소 시간당 비용($0.015)을 간과하여 장기간 방치
배치 처리 (Batch)실시간 스트리밍 (Streaming)
데이터를 모아서 주기적으로 처리 (시간/일 단위)데이터가 발생하는 즉시 처리 (초/밀리초 단위)
지연: 수 분 ~ 수 시간지연: 수 밀리초 ~ 수 초
ETL Job, Glue, EMR에 적합Kinesis, Lambda, Flink에 적합
과거 데이터 분석 (What happened?)현재 상태 모니터링 (What is happening?)
저렴한 처리 비용 (대량 일괄)상대적으로 높은 비용 (항상 가동)

리소스 정리

실습 완료 후 반드시 아래 순서대로 리소스를 정리하여 불필요한 과금을 방지하세요. EventBridge 규칙을 가장 먼저 비활성화하세요 — 방치하면 Lambda가 계속 호출됩니다.

  1. EventBridge 규칙 비활성화 및 삭제 (가장 먼저!)
  2. Lambda 함수 삭제 (프로듀서, 컨슈머, API 핸들러)
  3. API Gateway API 삭제
  4. Kinesis Data Streams 삭제 (realtime-metrics-stream)
  5. DynamoDB 테이블 삭제 (realtime-metrics)
  6. CloudWatch 로그 그룹 삭제 (각 Lambda 함수별)
  7. IAM 역할 및 정책 삭제