[Daily morning study] AWS ElastiCache와 인메모리 캐싱 아키텍처

#daily morning study

Image


AWS ElastiCache란

ElastiCache는 AWS에서 제공하는 완전 관리형 인메모리 캐싱 서비스다. Redis와 Memcached 두 가지 엔진을 지원하며, 데이터베이스 앞단에 캐시 레이어를 두어 응답 속도를 높이고 DB 부하를 줄이는 데 사용한다.

직접 EC2에 Redis를 설치해 운영하는 방식과 달리, ElastiCache는 패치, 백업, 복제, 장애 조치(Failover) 등을 AWS가 자동으로 처리해준다.


Redis vs Memcached

ElastiCache는 두 가지 엔진을 지원하며, 용도에 따라 선택이 달라진다.

항목RedisMemcached
데이터 구조String, List, Set, Hash, ZSet 등 다양String만 지원
복제 (Replication)지원 (Primary-Replica)미지원
영속성 (Persistence)RDB / AOF 지원미지원 (휘발성)
클러스터 모드지원 (Cluster Mode)지원 (단순 수평 확장)
Pub/Sub지원미지원
멀티스레드단일 스레드 기반멀티스레드
주요 사용처세션, 순위표, 분산 락, 캐시단순 오브젝트 캐시

실무에서는 대부분 Redis를 선택한다. 기능이 훨씬 풍부하고, 복제와 영속성을 지원하기 때문이다.


ElastiCache for Redis 구성 방식

1. Single Node (단일 노드)

가장 단순한 구성. 하나의 Redis 인스턴스만 운영한다.

  • 비용이 낮다
  • 장애 시 복구 불가 (SPOF)
  • 개발/테스트 환경에 적합

2. Cluster Mode Disabled (복제 그룹)

Primary 노드 1개와 Read Replica 여러 개로 구성된다.

Client ──→ Primary (Write)
           ├── Replica 1 (Read)
           └── Replica 2 (Read)
  • 읽기 부하를 분산할 수 있다
  • Primary 장애 시 Replica가 자동으로 승격된다 (Automatic Failover)
  • 데이터는 단일 샤드에만 저장 (데이터 파티셔닝 없음)

3. Cluster Mode Enabled (클러스터 모드)

데이터를 여러 샤드에 분산 저장한다. 각 샤드는 Primary + Replica 쌍으로 구성된다.

Shard 1: Primary + Replica  → slot 0~5460
Shard 2: Primary + Replica  → slot 5461~10922
Shard 3: Primary + Replica  → slot 10923~16383

Redis는 총 16,384개의 해시 슬롯을 사용한다. 키를 CRC16으로 해시한 뒤 16384로 나눈 나머지를 슬롯 번호로 사용해 어느 샤드에 저장할지 결정한다.

  • 대용량 데이터 저장 가능 (수평 확장)
  • 쓰기 성능도 분산된다
  • 멀티 키 연산에 제약이 생긴다 (같은 슬롯에 있어야 함)

캐싱 전략

ElastiCache를 도입할 때 어떤 캐싱 전략을 쓸지 결정해야 한다.

Cache-Aside (Lazy Loading)

애플리케이션이 직접 캐시를 확인하고, 없으면 DB에서 가져와 캐시에 저장하는 방식이다.

def get_user(user_id):
    cached = redis.get(f"user:{user_id}")
    if cached:
        return json.loads(cached)
    
    user = db.query("SELECT * FROM users WHERE id = %s", user_id)
    redis.setex(f"user:{user_id}", 3600, json.dumps(user))
    return user
  • 실제로 요청된 데이터만 캐시에 올라간다
  • 캐시 미스 시 응답 지연이 발생한다 (Cold Start 문제)
  • DB와 캐시 간 데이터 불일치가 생길 수 있다

Write-Through

데이터를 DB에 쓸 때 캐시에도 동시에 쓰는 방식이다.

def update_user(user_id, data):
    db.update("UPDATE users SET ... WHERE id = %s", user_id)
    redis.setex(f"user:{user_id}", 3600, json.dumps(data))
  • 캐시 미스가 거의 없다
  • 자주 접근하지 않는 데이터도 캐시에 올라간다 (낭비 가능)

Write-Behind (Write-Back)

캐시에 먼저 쓰고, 일정 시간 후 DB에 비동기로 반영하는 방식이다.

  • 쓰기 성능이 높다
  • 캐시 장애 시 데이터 유실 위험이 있다

TTL과 Eviction Policy

TTL (Time to Live)

캐시 데이터에 만료 시간을 설정해 자동으로 삭제되게 한다.

SET session:abc123 "user_data" EX 1800   # 30분 후 만료

TTL 없이 데이터를 쌓으면 메모리가 가득 차서 장애가 발생할 수 있다.

Eviction Policy

메모리가 가득 찼을 때 어떤 키를 삭제할지 결정하는 정책이다.

정책동작
noeviction메모리 초과 시 에러 반환
allkeys-lru모든 키 중 LRU 방식으로 삭제
volatile-lruTTL 설정된 키 중 LRU 방식으로 삭제
allkeys-lfu모든 키 중 LFU 방식으로 삭제
allkeys-random무작위 삭제
volatile-ttlTTL이 가장 짧은 키를 먼저 삭제

캐시 용도라면 allkeys-lru 또는 allkeys-lfu가 일반적으로 적합하다.


ElastiCache와 VPC 구성

ElastiCache는 반드시 VPC 내부에 위치시켜야 하며, 외부에서 직접 접근할 수 없다.

[인터넷]
   │
[ALB / EC2 / Lambda]  ← Public Subnet or Private Subnet
   │
[ElastiCache Subnet Group]  ← Private Subnet
   │
[RDS / Aurora]  ← Private Subnet
  • ElastiCache 서브넷 그룹을 생성해 특정 서브넷에 배치한다
  • Security Group으로 접근을 허용할 출처를 명시한다 (예: EC2 SG에서만 6379 포트 허용)
  • 같은 AZ에 있는 인스턴스에서 접근해야 지연 시간이 줄어든다

Multi-AZ와 Failover

Cluster Mode Disabled 구성에서 Multi-AZ를 활성화하면:

  1. Primary 노드 장애 감지 시 자동으로 Replica가 Primary로 승격된다
  2. DNS 엔드포인트가 새로운 Primary를 가리키도록 업데이트된다
  3. 일반적으로 30초~1분 이내에 복구된다

애플리케이션은 Primary 엔드포인트 하나만 바라보면 되고, Failover는 투명하게 처리된다.

Primary Endpoint: my-cache.abc123.cfg.apne2.cache.amazonaws.com:6379

Cluster Mode Enabled에서는 Configuration Endpoint를 사용한다. 클라이언트가 클러스터 토폴로지를 자동으로 파악한다.


모니터링 지표

CloudWatch에서 ElastiCache의 주요 메트릭을 확인해야 한다.

지표설명
CacheHits캐시에서 응답된 요청 수
CacheMisses캐시 미스 횟수
CacheHitRate캐시 히트율 (높을수록 좋다)
Evictions메모리 부족으로 삭제된 키 수
FreeableMemory사용 가능한 메모리 잔량
CurrConnections현재 연결 수
ReplicationLagPrimary와 Replica 간 복제 지연

Evictions가 급증하거나 FreeableMemory가 낮으면 메모리를 증설하거나 Eviction Policy를 조정해야 한다.


실무 적용 시 체크리스트

  1. 엔진 선택: 단순 키-값 캐시라면 Memcached, 복잡한 자료구조나 Failover가 필요하면 Redis
  2. 노드 타입 선택: cache.r7g.* (메모리 최적화), cache.t3.* (개발/테스트)
  3. Multi-AZ 활성화: 프로덕션 환경에서 반드시 설정
  4. 서브넷 그룹: Private Subnet에 배치하고 Security Group으로 접근 제어
  5. TTL 설정: 모든 캐시 키에 적절한 TTL을 부여
  6. Eviction Policy: 캐시 용도라면 allkeys-lru 또는 allkeys-lfu
  7. 모니터링: CacheHitRate, Evictions, FreeableMemory 알람 설정