Redis vs DynamoDB vs DAX: AWS 캐싱 성능을 벤치마크했더니 (예상치 못한 결과)

발행: (2026년 2월 2일 오후 05:00 GMT+9)
15 분 소요
원문: Dev.to

위에 제공해 주신 Source 링크만으로는 번역할 본문이 없습니다. 번역이 필요한 전체 텍스트를 알려주시면, 요청하신 대로 마크다운 형식과 코드 블록, URL은 그대로 유지하면서 한국어로 번역해 드리겠습니다.

DynamoDB 읽기용 인‑메모리 캐싱 벤치마킹

많은 백엔드 시스템에서 사용자 데이터는 거의 모든 요청마다 조회됩니다. 일반적인 가정은 인‑메모리 캐시를 추가하면 어떤 시스템이든 읽기 성능이 향상된다는 것입니다.

이 가정을 검증하기 위해 서버리스 아키텍처 내에서 DynamoDB에서 사용자 데이터를 가져오는 세 가지 접근 방식을 벤치마크했습니다:

ApproachDescription
BaselineAWS Lambda + DynamoDB (캐시 없음)
Cache‑asideLambda → Redis → DynamoDB
DAXLambda → DynamoDB Accelerator (DAX) → DynamoDB

목표는 스타트업의 CTO가 캐싱 서비스에 투자해야 하는지를 판단하는 것이었습니다. 저는 캐시를 사용한 접근 방식이 베이스라인보다 쉽게 뛰어넘을 것이라고 예상했지만, 초당 200 요청(분당 12 000 요청)에서도 그 가정은 성립하지 않았습니다.

Source:

실험 설정

세 테스트 모두 가능한 한 동일하게 설계했으며, eu‑central‑1 AWS 리전에서 가장 저렴한 옵션을 사용했습니다.

1. 베이스라인 (DDB + Lambda)

구성 요소설정
LambdaPython 3.12, 256 MiB 메모리, 10 s 타임아웃
DynamoDBPay‑per‑request 청구 모드
액세스 패턴DynamoDB 직접 읽기 (캐시 없음)
지연 시간가장 높음 (캐시 없음)

2. DAX (DynamoDB Accelerator)

구성 요소설정
LambdaPython 3.12, 256 MiB 메모리, 10 s 타임아웃
DAX 클러스터dax.t3.small (단일 노드, 복제 팩터 = 1) – VPC 격리 서브넷에 배포
캐시DAX가 자동으로 관리 (기본 아이템 TTL ≈ 5 분, 쿼리 캐시 TTL ≈ 5 분)
액세스 패턴Lambda → DAX → DynamoDB
클라이언트amazondax Python 클라이언트 (pip 로 설치)

3. Redis (AWS ElastiCache)

구성 요소설정
LambdaPython 3.12, 256 MiB 메모리, 10 s 타임아웃
Redis 클러스터cache.t4g.micro (단일 노드, 자동 장애 조치 없음) – VPC 격리 서브넷에 배포
캐시 TTL30 초 ( REDIS_TTL_SECONDS 로 설정 가능)
액세스 패턴1️⃣ Lambda가 먼저 Redis를 확인
2️⃣ 미스 시 → DynamoDB에서 읽고 30 초 TTL 로 Redis에 저장
3️⃣ 히트 시 → 캐시된 데이터를 반환
클라이언트1 s 연결 타임아웃을 가진 표준 redis-py 클라이언트

테스트 방법론

  • 로드 수준 – 초당 50 읽기 / s (분당 3 000 읽기) 및 초당 200 읽기 / s (분당 12 000 읽기).
  • 페이로드 – 모든 실행에 대해 동일한 크기이며, 핫/믹스 키 분포를 사용합니다.
  • 측정 지표 – 95번째 백분위수 지연 시간(p95).
  • 도구 – 오픈소스 부하 테스트 라이브러리 k6 (JavaScript 스크립트).

세 가지 접근 방식 모두 동일한 DynamoDB 항목을 가져왔으며, 예시:

{
  "pk": "ITEM#123",
  "sk": "META",
  "itemId": "123",
  "title": "Example Item Title",
  "body": "This is the body content of the item",
  "updatedAt": 1736467200,
  "etag": "a7f8d9e1c2b3a4f5e6d7c8b9a0f1e2d3c4b5a6f7e8d9c0b1a2f3e4d5c6b7a8f9"
}

Source:

Results – 50 RPS (Establishing the Baseline)

Access Patternp95 Latency (ms)Avg Latency (ms)Dropped IterationsNotes
Lambda + DynamoDB (Baseline)~63~480빠르고 안정적이며 병목 현상 없음
Redis (warm‑up run)~68~6622캐시 미스 + 쓰기‑백 비용
Redis (steady state)~63~480베이스라인과 일치, 지연 시간 개선 없음
DAX (single small node)~1040~95719캐시 포화, 사용 불가

Interpretation

  • Baseline – 50 RPS에서 Lambda + DynamoDB 조합은 p95 지연 시간이 약 63 ms이며 드롭이 전혀 없었습니다. DynamoDB 온디맨드는 압박을 받지 않았습니다.
  • Redis – 첫 번째(워밍업) 실행은 캐시 미스로 인해 지연 시간이 늘어났습니다. 캐시가 충분히 워밍업된 후에는 지연 시간이 베이스라인과 일치했지만 향상되지는 않았습니다.
  • DAX – 크기가 부족한 dax.t3.small 노드는 CPU 바운드가 되어 요청이 대기열에 쌓이고 p95 지연 시간이 1 초를 초과했습니다. 이는 잘못된 크기의 캐시가 성능을 저하시킬 수 있음을 보여줍니다.

Conclusion (50 RPS)

베이스라인이 매우 우수하게 동작했으며 추가 캐시가 필요하지 않았습니다. Redis를 추가하면 DynamoDB 부하가 감소하지만 측정 가능한 지연 시간 이점은 없습니다. 크기가 부족한 DAX는 오히려 성능에 악영향을 미쳤습니다.

Results – 200 RPS (예상되었던 교차점이 발생하지 않음)

Access Patternp95 Latency (ms)Avg Latency (ms)Dropped IterationsNotes
Lambda + DynamoDB (Baseline)~63~4813안정적이며, 선형적으로 확장됨
Redis (warm run)~64~5240로드 중 캐시 채워짐
Redis (steady state)~70~5879베이스라인보다 약간 더 나쁨
DAX (single small node)~1050~9685 399클러스터 포화

Interpretation

  • Baseline – 200 RPS에서도 Lambda + DynamoDB 구성은 ~63 ms p95 지연 시간을 유지했으며, 이는 확장성을 확인시켜 줍니다.
  • Redis – 두 단계가 다시 나타났습니다. 워밍업 실행에서는 미스 지연이 발생했으며, 정상 상태 실행에서는 베이스라인보다 약간 느렸는데, 이는 추가 네트워크 홉과 로드 중 발생하는 가끔의 캐시 미스 때문으로 보입니다.
  • DAX – 작은 단일 노드가 완전히 포화되어, 엄청난 지연 시간과 수천 건의 드롭된 반복을 초래했습니다.

Conclusion (200 RPS)

베이스라인이 가장 성능이 뛰어나고 가장 간단한 솔루션으로 남아 있습니다. Redis는 이러한 부하에서는 지연 시간 이점을 제공하지 않으며, 규모가 부족한 DAX 클러스터는 성능을 크게 악화시킵니다.

전체 요약

  1. 기본 Lambda + DynamoDB만으로도 충분한 경우가 많다 – 온‑디맨드 청구와 자동 스케일링으로 200 RPS에서도 지연 시간이 낮게 유지됩니다.
  2. Cache‑aside Redis는 DynamoDB 읽기 부하를 줄일 수 있지만 네트워크 홉이 추가됩니다; 읽기‑대‑쓰기 비율이 매우 높거나 더 엄격한 지연 시간 SLA가 없으면 응답 시간을 개선하지 못할 수 있습니다.
  3. DAX는 즉시 사용 가능한 속도 향상이 아닙니다 – 적절한 용량 계획이 필수이며, 용량이 부족한 노드는 병목이 될 수 있습니다.
  4. 캐싱이 의미가 있는 경우
    • 읽기‑대‑쓰기 비율이 매우 높을 때 (예: > 100:1).
    • 지연 시간 요구사항이 10 ms 미만이며 기본 구성이 이를 충족하지 못할 때.
    • 워크로드가 강한 시간적 지역성을 보여 추가 운영 복잡성을 정당화할 때.

대부분의 스타트업이 트래픽 수준이 낮은 경우 (≤ 200 RPS), 가장 간단한 아키텍처인 Lambda가 직접 DynamoDB를 조회하는 형태가 비용‑성능 균형이 가장 좋습니다. 캐시를 추가하는 것은 구체적인 지연 시간 감소 또는 비용 절감 목표에 의해 결정되어야 하며, “캐시는 항상 도움이 된다”는 가정에 의해 결정되어서는 안 됩니다.

캐시 워밍업 및 Redis 안정화

캐시가 워밍업된 후 Redis는 안정화되었지만 기본 성능을 능가하지는 못했습니다. 정상 상태에서는:

  • p95 지연 시간이 약 70 ms로 약간 증가했습니다.
  • 드롭된 반복 횟수가 DynamoDB만 사용할 때보다 더 많았습니다.

DAX @ 200 RPS: 부하 하에서 포화

200 RPS에서 DAX 구성은 붕괴되기 시작했습니다:

  • 실제 처리량이 목표 비율보다 크게 낮아졌습니다.
  • p95 지연 시간이 1초를 초과했습니다.
  • 수천 개의 반복이 누락되었습니다.

이 현상은 DAX가 크기에 매우 민감함을 확인시켜 줍니다—작은 인스턴스는 전혀 이점을 제공하지 않습니다.

결론: 200 RPS

200 RPS에서도, 이 시스템에서 가장 큰 비용은 아니라 네트워크 및 관리형 서비스 오버헤드였습니다. 캐시를 추가해도 그 비용이 사라지지는 않았으며, 오히려 비용이 추가되었습니다. 이는 선택에 따라 온‑디맨드 또는 서버리스 Redis 인스턴스에 대한 비용을 여전히 지불해야 하기 때문입니다.

실제로 증명되는 결과

  • DynamoDB on‑demand는 단순 읽기 작업에서 매우 잘 확장됩니다.
  • Redis는 지연 시간을 줄이는 것이 아니라 데이터베이스에 가해지는 압력을 감소시킵니다.
  • Cache warm‑up이 중요합니다.
  • 잘못 구성된 DAX는 캐시가 없는 것보다 더 나쁩니다.
  • Latency optimizationscaling optimization는 서로 다른 문제입니다.

결론 및 교훈

50 RPS와 200 RPS 벤치마크 결과는 명확하면서도 다소 직관에 반하는 결론을 보여줍니다. 이 워크로드에서는 DynamoDB 온디맨드와 연동된 Lambda가 이미 충분히 빠르기 때문에 캐시를 추가해도 사용자에게 보이는 지연 시간이 개선되지 않았습니다.

  • 두 로드 레벨 모두에서 DynamoDB는 병목이 아니었습니다.
  • 엔드‑투‑엔드 지연 시간은 네트워크 거리관리형 서비스 오버헤드에 의해 지배되었으며, 데이터베이스 접근 시간은 큰 영향을 미치지 않았습니다.
  • Redis를 도입하면 추가적인 네트워크 홉과 클라이언트 측 오버헤드가 발생하지만, 요청 경로에서 지배적인 비용을 제거하지는 못했습니다.

Redis는 여전히 역할을 했지만, 처음 예상했던 목적과는 달랐습니다. DynamoDB에 대한 압력을 완화하고 백엔드 부하를 평탄화했으며, 이는 비용 관리와 향후 확장에 유용할 수 있습니다. 그러나 이러한 트래픽 수준에서는 요청을 더 빠르게 만들지는 않았습니다.

DAX 교훈

  • 용량이 부족하면 DAX는 전혀 도움이 되지 않으며, 빠르게 포화되어 지연 시간 증가와 요청 손실을 초래합니다.
  • 신중한 용량 계획과 워크플로에 대한 확실한 이해가 필요합니다.

최종 생각

이 실험에서 얻은 가장 큰 교훈은 최적화 전에 측정이 필수라는 점입니다. 캐시가 백엔드 부하를 줄일 수는 있지만, 자동으로 엔드‑투‑엔드 지연 시간을 낮추지는 않습니다.

워크플로가 너무 단순하면 캐시의 이점이 눈에 띄지 않을 수 있습니다. 그러나 시간이 많이 소요되는 연산 결과를 캐시할 수 있다면, 캐시 적용을 테스트해 볼 가치가 있습니다.

요약: 느낌이 좋아서 캐시하지 말고, 데이터가 필요하다는 증거가 있을 때 캐시하십시오.

Back to Blog

관련 글

더 보기 »