🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

ElastiCache로 인메모리 캐싱 구현하기 - 슬라이드 1/7
A

AI Generated

2025. 12. 28. · 2 Views

ElastiCache로 인메모리 캐싱 구현하기

AWS ElastiCache를 활용하여 애플리케이션의 성능을 획기적으로 개선하는 방법을 알아봅니다. Redis 클러스터 구성부터 실제 연동까지 실무에서 바로 적용할 수 있는 내용을 다룹니다.


목차

  1. ElastiCache의_필요성과_사용_사례
  2. Redis_vs_Memcached_선택_가이드
  3. ElastiCache_서브넷_그룹_생성
  4. Redis_클러스터_생성_실습
  5. 캐시_전략_구현하기
  6. 애플리케이션에서_Redis_연동하기

1. ElastiCache의 필요성과 사용 사례

김개발 씨는 오늘도 모니터링 대시보드를 바라보며 한숨을 쉬었습니다. 서비스 출시 후 사용자가 급증하면서 데이터베이스 응답 시간이 점점 느려지고 있었습니다.

"이대로 가다간 서버가 버티지 못할 것 같은데..." 바로 그때 옆자리 박시니어 씨가 말했습니다. "캐싱을 적용해 볼 때가 된 것 같네요."

ElastiCache는 AWS에서 제공하는 완전 관리형 인메모리 캐싱 서비스입니다. 마치 자주 찾는 책을 책상 위에 꺼내 두는 것처럼, 자주 조회하는 데이터를 메모리에 저장해 두어 빠르게 접근할 수 있게 해줍니다.

데이터베이스 부하를 줄이고 응답 속도를 밀리초 단위로 개선할 수 있습니다.

다음 코드를 살펴봅시다.

// ElastiCache 사용 전: 매번 DB 조회
async function getUserProfile(userId) {
  // 매 요청마다 데이터베이스에 직접 접근
  const user = await database.query(
    'SELECT * FROM users WHERE id = ?',
    [userId]
  );
  return user;
}

// ElastiCache 사용 후: 캐시 우선 조회
async function getUserProfileWithCache(userId) {
  // 1. 캐시에서 먼저 확인
  const cached = await redis.get(`user:${userId}`);
  if (cached) return JSON.parse(cached);

  // 2. 캐시에 없으면 DB 조회 후 캐시 저장
  const user = await database.query('SELECT * FROM users WHERE id = ?', [userId]);
  await redis.setex(`user:${userId}`, 3600, JSON.stringify(user));
  return user;
}

김개발 씨가 운영하는 서비스는 하루 방문자가 10만 명을 넘어섰습니다. 문제는 사용자들이 자주 조회하는 인기 상품 페이지였습니다.

같은 데이터를 수천 명이 동시에 요청하는데, 매번 데이터베이스에서 가져오니 서버가 비명을 지르고 있었습니다. 박시니어 씨가 화이트보드에 그림을 그리기 시작했습니다.

"생각해 봐요. 도서관에서 가장 인기 있는 책이 뭔지 아세요?" 김개발 씨가 고개를 갸웃했습니다.

"글쎄요, 베스트셀러요?" "맞아요. 그런데 그 책을 빌리려고 할 때마다 사서가 창고까지 가서 가져온다면 어떨까요?

시간이 엄청 오래 걸리겠죠. 그래서 도서관에서는 인기 있는 책을 대출 코너에 미리 꺼내 둡니다." 바로 이것이 캐싱의 핵심 개념입니다.

자주 사용하는 데이터를 빠르게 접근할 수 있는 곳에 미리 저장해 두는 것입니다. 데이터베이스가 창고라면, ElastiCache는 대출 코너와 같습니다.

그렇다면 왜 하필 인메모리 캐싱일까요? 컴퓨터에서 데이터를 저장하는 곳은 크게 두 가지입니다.

하드디스크와 메모리입니다. 하드디스크는 용량이 크지만 느립니다.

반면 메모리는 용량은 작지만 엄청나게 빠릅니다. 마치 책상 위와 창고의 차이와 같습니다.

ElastiCache는 데이터를 메모리에 저장합니다. 그래서 데이터베이스보다 100배 이상 빠른 응답 속도를 자랑합니다.

데이터베이스 조회가 보통 10~100밀리초라면, ElastiCache는 1밀리초 미만으로 데이터를 가져올 수 있습니다. 실무에서 ElastiCache가 빛을 발하는 대표적인 사례를 살펴보겠습니다.

첫 번째는 세션 저장소입니다. 사용자가 로그인하면 세션 정보를 저장해야 합니다.

이 정보는 모든 요청에서 확인해야 하므로 빠른 접근이 필수입니다. ElastiCache에 세션을 저장하면 인증 과정이 눈에 띄게 빨라집니다.

두 번째는 데이터베이스 쿼리 캐싱입니다. 위 코드 예제처럼 자주 조회되는 데이터를 캐시에 저장해 두면 데이터베이스 부하를 크게 줄일 수 있습니다.

특히 읽기 작업이 많은 서비스에서 효과가 탁월합니다. 세 번째는 실시간 순위표입니다.

게임이나 커뮤니티 서비스에서 실시간으로 변하는 랭킹을 관리할 때 Redis의 Sorted Set 자료구조가 매우 유용합니다. AWS에서 ElastiCache를 사용하면 이 모든 것을 완전 관리형으로 제공받습니다.

직접 Redis나 Memcached 서버를 설치하고 관리할 필요가 없습니다. 장애 복구, 백업, 보안 패치까지 AWS가 알아서 처리해 줍니다.

김개발 씨가 물었습니다. "그러면 모든 데이터를 캐시에 넣으면 되겠네요?" 박시니어 씨가 웃으며 고개를 저었습니다.

"아니에요. 캐시는 메모리를 사용하기 때문에 비용이 많이 듭니다.

자주 조회되고, 자주 변하지 않는 데이터에 적용해야 효과적이에요." 이것이 바로 캐싱 전략의 핵심입니다. 무엇을 캐시할지, 얼마나 오래 저장할지를 결정하는 것이 성능 최적화의 시작점입니다.

실전 팁

💡 - 읽기가 쓰기보다 훨씬 많은 데이터에 캐싱을 적용하면 효과가 극대화됩니다

  • 캐시 만료 시간은 데이터 특성에 맞게 설정해야 하며, 처음에는 짧게 시작하는 것이 안전합니다
  • CloudWatch 지표를 통해 캐시 적중률을 모니터링하고 최적화해 나가세요

2. Redis vs Memcached 선택 가이드

ElastiCache를 사용하기로 결정한 김개발 씨 앞에 새로운 선택지가 나타났습니다. AWS 콘솔에서 ElastiCache 클러스터를 생성하려고 하니 두 가지 옵션이 보였습니다.

RedisMemcached. 둘 다 인메모리 캐시인데, 무엇이 다른 걸까요?

Redis와 Memcached는 모두 인메모리 캐싱 솔루션이지만 특성이 다릅니다. Memcached는 단순한 키-값 저장에 최적화된 반면, Redis는 다양한 자료구조와 영속성, 복제 기능을 제공합니다.

대부분의 현대적인 애플리케이션에서는 Redis가 더 적합한 선택입니다.

다음 코드를 살펴봅시다.

// Memcached: 단순 키-값 저장만 가능
await memcached.set('user:1', JSON.stringify(userData));
const user = JSON.parse(await memcached.get('user:1'));

// Redis: 다양한 자료구조 지원
// 1. 해시 - 객체 필드별 저장
await redis.hset('user:1', 'name', '김개발', 'email', 'kim@dev.com');
const name = await redis.hget('user:1', 'name');

// 2. 리스트 - 최근 활동 로그
await redis.lpush('user:1:activities', '로그인');
const recentActivities = await redis.lrange('user:1:activities', 0, 9);

// 3. Sorted Set - 실시간 랭킹
await redis.zadd('leaderboard', 1500, 'player:1');
await redis.zadd('leaderboard', 2000, 'player:2');
const top10 = await redis.zrevrange('leaderboard', 0, 9, 'WITHSCORES');

박시니어 씨가 두 개의 상자를 책상 위에 올려놓았습니다. "이 두 상자의 차이를 알면 선택이 쉬워져요." 첫 번째 상자에는 Memcached라고 적혀 있었습니다.

"이건 심플한 사물함이에요. 물건을 넣고 빼는 것만 가능하죠.

대신 정말 빠르고 단순합니다." 두 번째 상자에는 Redis라고 적혀 있었습니다. "이건 스마트 창고예요.

물건을 넣고 빼는 것뿐만 아니라, 물건을 정렬하고, 그룹으로 묶고, 심지어 물건 목록을 기억해 둘 수도 있습니다." 이것이 두 서비스의 가장 큰 차이점입니다. 자료구조의 다양성입니다.

Memcached는 오직 문자열만 저장할 수 있습니다. 복잡한 객체를 저장하려면 JSON으로 직렬화해야 합니다.

데이터의 일부만 수정하고 싶어도 전체를 읽어서 수정한 다음 다시 저장해야 합니다. 반면 Redis는 다섯 가지 핵심 자료구조를 제공합니다.

String은 가장 기본적인 형태입니다. 단순한 값을 저장할 때 사용합니다.

Hash는 객체를 저장하기에 적합합니다. 사용자 정보처럼 여러 필드를 가진 데이터를 효율적으로 관리할 수 있습니다.

List는 순서가 있는 데이터를 저장합니다. 최근 본 상품 목록이나 알림 히스토리에 딱 맞습니다.

Set은 중복 없이 데이터를 저장합니다. 태그나 팔로워 목록 관리에 유용합니다.

마지막으로 Sorted Set은 점수와 함께 데이터를 저장합니다. 게임 랭킹이나 인기 검색어 순위를 만들 때 이보다 좋은 도구는 없습니다.

김개발 씨가 고개를 끄덕였습니다. "그러면 Redis가 무조건 좋은 거 아닌가요?" 박시니어 씨가 손가락을 들어 올렸습니다.

"대부분의 경우에는 그렇죠. 하지만 Memcached만의 장점도 있어요." Memcached는 멀티스레드를 지원합니다.

Redis는 기본적으로 싱글스레드로 동작합니다. 따라서 매우 단순한 키-값 저장만 필요하고, CPU 코어를 최대한 활용해야 하는 상황에서는 Memcached가 약간 더 나을 수 있습니다.

하지만 현실에서는 대부분 Redis를 선택합니다. 그 이유는 영속성 때문입니다.

Memcached는 서버가 재시작되면 모든 데이터가 사라집니다. 순수한 캐시로만 사용해야 합니다.

반면 Redis는 데이터를 디스크에 저장할 수 있습니다. 서버가 재시작되어도 데이터가 보존됩니다.

또한 Redis는 복제(Replication) 기능을 제공합니다. 주 노드의 데이터를 여러 복제 노드에 복사해 둘 수 있습니다.

장애가 발생해도 복제 노드가 자동으로 승격되어 서비스가 중단되지 않습니다. 클러스터 모드도 Redis의 강점입니다.

데이터를 여러 노드에 분산 저장하여 수평적으로 확장할 수 있습니다. 대용량 데이터와 높은 처리량이 필요한 서비스에서 필수적인 기능입니다.

결론적으로 다음과 같이 정리할 수 있습니다. 단순한 세션 캐싱이나 페이지 캐싱만 필요하고, 데이터 손실이 괜찮다면 Memcached를 고려해 볼 수 있습니다.

하지만 다양한 자료구조가 필요하거나, 데이터 영속성이 중요하거나, 고가용성이 필요하다면 Redis가 정답입니다. 김개발 씨가 결심한 듯 말했습니다.

"저희 서비스는 세션도 관리하고 랭킹 기능도 있으니까 Redis로 가야겠네요!"

실전 팁

💡 - 새 프로젝트라면 Redis를 기본 선택으로 시작하는 것이 안전합니다

  • Memcached는 레거시 시스템이나 매우 단순한 캐싱 요구사항에만 고려하세요
  • Redis 클러스터 모드는 데이터가 많아질 것을 대비해 처음부터 활성화하는 것이 좋습니다

3. ElastiCache 서브넷 그룹 생성

Redis를 선택한 김개발 씨는 AWS 콘솔에서 ElastiCache 클러스터를 만들려고 했습니다. 그런데 첫 단계부터 막혔습니다.

서브넷 그룹을 선택하라는 화면이 나왔는데, 목록이 비어 있었습니다. "이게 뭐죠?" 김개발 씨가 당황한 표정으로 물었습니다.

서브넷 그룹은 ElastiCache 클러스터가 배치될 네트워크 위치를 정의합니다. VPC 내의 특정 서브넷들을 묶어서 그룹으로 만들고, 캐시 클러스터는 이 그룹 내의 서브넷에 노드를 배치합니다.

고가용성을 위해 여러 가용 영역의 서브넷을 포함시키는 것이 좋습니다.

다음 코드를 살펴봅시다.

// AWS CLI로 서브넷 그룹 생성
aws elasticache create-cache-subnet-group \
  --cache-subnet-group-name my-redis-subnet-group \
  --cache-subnet-group-description "Subnet group for Redis cluster" \
  --subnet-ids subnet-0123456789abcdef0 subnet-0123456789abcdef1

// Terraform으로 서브넷 그룹 생성
resource "aws_elasticache_subnet_group" "redis" {
  name       = "my-redis-subnet-group"
  subnet_ids = [
    aws_subnet.private_a.id,  // ap-northeast-2a
    aws_subnet.private_c.id   // ap-northeast-2c
  ]

  tags = {
    Name        = "Redis Subnet Group"
    Environment = "production"
  }
}

박시니어 씨가 화이트보드에 큰 사각형을 그렸습니다. "이게 우리 VPC예요.

가상의 네트워크 공간이라고 생각하면 돼요." 사각형 안에 여러 개의 작은 사각형을 그렸습니다. "이것들이 서브넷이에요.

VPC를 더 작은 네트워크로 나눈 거죠." 김개발 씨가 고개를 끄덕였습니다. "아, 아파트 단지 안에 여러 동이 있는 것처럼요?" "정확해요!

그리고 ElastiCache 클러스터를 만들 때는 이 중에서 어떤 동에 배치할지 미리 정해줘야 해요. 그게 바로 서브넷 그룹이에요." 서브넷 그룹을 만들 때 가장 중요한 원칙은 프라이빗 서브넷을 사용하는 것입니다.

퍼블릭 서브넷은 인터넷에서 직접 접근할 수 있는 네트워크입니다. 캐시 서버를 여기에 배치하면 보안상 매우 위험합니다.

반면 프라이빗 서브넷은 인터넷에서 직접 접근할 수 없습니다. 오직 VPC 내부에서만 접근 가능합니다.

따라서 ElastiCache는 반드시 프라이빗 서브넷에 배치해야 합니다. 애플리케이션 서버도 같은 VPC 내에 있어야 캐시에 접근할 수 있습니다.

두 번째 원칙은 **여러 가용 영역(AZ)**에 걸쳐 서브넷을 구성하는 것입니다. AWS의 가용 영역은 물리적으로 분리된 데이터 센터입니다.

하나의 가용 영역에 장애가 발생해도 다른 가용 영역은 정상 운영됩니다. 서브넷 그룹에 여러 가용 영역의 서브넷을 포함시키면, ElastiCache가 노드를 분산 배치하여 고가용성을 확보합니다.

AWS 콘솔에서 서브넷 그룹을 만드는 과정을 살펴보겠습니다. 먼저 ElastiCache 대시보드에서 왼쪽 메뉴의 Subnet groups를 클릭합니다.

Create subnet group 버튼을 누르면 생성 화면이 나타납니다. 이름을 입력합니다.

예를 들어 my-redis-subnet-group처럼 용도를 알 수 있는 이름이 좋습니다. 설명도 간단히 적어줍니다.

VPC를 선택합니다. 애플리케이션 서버가 위치한 VPC를 선택해야 합니다.

다른 VPC의 서브넷은 선택할 수 없습니다. 마지막으로 서브넷을 선택합니다.

프라이빗 서브넷만 선택하고, 가능하면 2개 이상의 가용 영역에 있는 서브넷을 선택합니다. 위의 코드 예제에서 AWS CLI를 사용한 방법도 확인할 수 있습니다.

subnet-ids 옵션에 여러 서브넷 ID를 공백으로 구분하여 나열합니다. Terraform을 사용하는 경우 aws_elasticache_subnet_group 리소스를 정의합니다.

subnet_ids에 프라이빗 서브넷들의 ID를 배열로 전달합니다. 김개발 씨가 질문했습니다.

"서브넷 ID는 어디서 확인하나요?" 박시니어 씨가 답했습니다. "VPC 대시보드의 Subnets 메뉴에서 확인할 수 있어요.

각 서브넷에 태그를 잘 달아두면 퍼블릭인지 프라이빗인지 쉽게 구분할 수 있습니다." 서브넷 그룹 생성이 완료되면 ElastiCache 클러스터를 만들 때 이 그룹을 선택할 수 있습니다. 이제 본격적으로 Redis 클러스터를 만들 준비가 되었습니다.

실전 팁

💡 - 서브넷 그룹 이름에 환경(dev, staging, prod)과 용도를 포함시키면 관리가 편합니다

  • 최소 2개 이상의 가용 영역에 서브넷을 포함시켜 장애에 대비하세요
  • 인터넷 접근이 필요 없으므로 NAT Gateway 설정 없이도 프라이빗 서브넷 사용이 가능합니다

4. Redis 클러스터 생성 실습

서브넷 그룹까지 준비를 마친 김개발 씨는 드디어 Redis 클러스터를 생성하기로 했습니다. AWS 콘솔의 ElastiCache 대시보드에서 Create 버튼을 클릭하니 수많은 옵션이 나타났습니다.

노드 타입, 복제본 수, 클러스터 모드... 무엇을 어떻게 설정해야 할까요?

ElastiCache Redis 클러스터를 생성할 때는 노드 타입, 복제본 구성, 클러스터 모드 여부를 결정해야 합니다. 프로덕션 환경에서는 Multi-AZ 배포와 자동 장애 조치를 활성화하여 고가용성을 확보하는 것이 중요합니다.

개발 환경에서는 단일 노드로 시작해도 됩니다.

다음 코드를 살펴봅시다.

// AWS CLI로 Redis 클러스터 생성 (복제 그룹 방식)
aws elasticache create-replication-group \
  --replication-group-id my-redis-cluster \
  --replication-group-description "Production Redis cluster" \
  --engine redis \
  --engine-version 7.0 \
  --cache-node-type cache.r6g.large \
  --num-cache-clusters 3 \
  --cache-subnet-group-name my-redis-subnet-group \
  --security-group-ids sg-0123456789abcdef0 \
  --automatic-failover-enabled \
  --multi-az-enabled \
  --at-rest-encryption-enabled \
  --transit-encryption-enabled

// Terraform으로 Redis 클러스터 생성
resource "aws_elasticache_replication_group" "redis" {
  replication_group_id       = "my-redis-cluster"
  description                = "Production Redis cluster"
  engine                     = "redis"
  engine_version             = "7.0"
  node_type                  = "cache.r6g.large"
  num_cache_clusters         = 3
  subnet_group_name          = aws_elasticache_subnet_group.redis.name
  security_group_ids         = [aws_security_group.redis.id]
  automatic_failover_enabled = true
  multi_az_enabled           = true
  at_rest_encryption_enabled = true
  transit_encryption_enabled = true
}

박시니어 씨가 화면을 가리키며 설명을 시작했습니다. "Redis 클러스터를 만드는 방법은 크게 두 가지예요.

단일 노드 방식과 복제 그룹 방식이요." 단일 노드는 말 그대로 하나의 Redis 인스턴스만 운영하는 것입니다. 설정이 간단하고 비용이 저렴하지만, 그 노드에 장애가 발생하면 캐시 서비스 전체가 중단됩니다.

개발이나 테스트 환경에서만 사용해야 합니다. **복제 그룹(Replication Group)**은 프로덕션 환경의 표준입니다.

하나의 프라이머리 노드와 여러 개의 복제 노드로 구성됩니다. 프라이머리 노드에 쓰기 작업이 발생하면 복제 노드에 자동으로 동기화됩니다.

김개발 씨가 물었습니다. "복제 노드는 왜 필요한 거예요?" 박시니어 씨가 답했습니다.

"두 가지 이유가 있어요. 첫째는 읽기 성능 향상이에요.

읽기 요청을 여러 복제 노드에 분산시킬 수 있거든요. 둘째는 장애 대비예요." 프라이머리 노드에 장애가 발생하면 어떻게 될까요?

**자동 장애 조치(Automatic Failover)**가 활성화되어 있으면, ElastiCache가 자동으로 복제 노드 중 하나를 새로운 프라이머리로 승격시킵니다. 서비스 중단 시간을 최소화할 수 있습니다.

이제 실제 생성 과정을 살펴보겠습니다. AWS 콘솔에서 Redis caches 메뉴로 이동합니다.

Create Redis cache 버튼을 클릭합니다. Cluster mode를 선택해야 합니다.

클러스터 모드가 비활성화되면 단일 샤드로 운영됩니다. 데이터가 많지 않다면 이 방식으로 충분합니다.

클러스터 모드가 활성화되면 데이터를 여러 샤드에 분산 저장합니다. 대용량 데이터에 적합합니다.

노드 타입을 선택합니다. 이름에서 성능을 유추할 수 있습니다.

cache.t4g.micro는 테스트용으로 적합합니다. cache.r6g 시리즈는 메모리 최적화 인스턴스로 프로덕션에 권장됩니다.

숫자가 클수록 메모리와 성능이 높아집니다. 복제본 수를 설정합니다.

프로덕션 환경에서는 최소 2개의 복제본을 권장합니다. 프라이머리 1개와 복제본 2개로 총 3개의 노드가 됩니다.

Multi-AZ를 활성화합니다. 노드들을 여러 가용 영역에 분산 배치하여 가용 영역 장애에도 서비스를 유지할 수 있습니다.

보안 그룹을 설정합니다. 애플리케이션 서버에서만 Redis 포트(6379)로 접근할 수 있도록 인바운드 규칙을 구성해야 합니다.

암호화 옵션도 중요합니다. At-rest encryption은 저장된 데이터를 암호화합니다.

In-transit encryption은 네트워크 통신을 암호화합니다. 보안이 중요한 서비스라면 둘 다 활성화하세요.

클러스터 생성에는 보통 5~10분 정도 소요됩니다. 상태가 available로 변경되면 사용할 준비가 된 것입니다.

김개발 씨가 기쁜 표정으로 말했습니다. "드디어 Redis 클러스터가 생겼네요!

이제 어떻게 연결하죠?" 박시니어 씨가 대시보드에서 Primary endpoint 주소를 가리켰습니다. "이 주소로 연결하면 돼요.

하지만 그전에 캐시 전략을 먼저 정해야 해요."

실전 팁

💡 - 개발 환경에서는 cache.t4g.micro로 시작하여 비용을 절약하세요

  • 프로덕션에서는 반드시 Multi-AZ와 자동 장애 조치를 활성화하세요
  • 보안 그룹에서 Redis 포트(6379)를 필요한 서버에만 열어두세요

5. 캐시 전략 구현하기

Redis 클러스터가 준비되었지만, 김개발 씨는 막막했습니다. "캐시를 어떻게 사용해야 하죠?

그냥 모든 데이터를 저장하면 되나요?" 박시니어 씨가 고개를 저었습니다. "캐시 전략이 없으면 오히려 문제가 생길 수 있어요.

Cache-AsideWrite-Through에 대해 알아봅시다."

캐시 전략은 데이터를 언제, 어떻게 캐시에 저장하고 갱신할지 결정하는 패턴입니다. Cache-Aside는 애플리케이션이 직접 캐시를 관리하는 방식이고, Write-Through는 쓰기 작업 시 캐시와 데이터베이스를 동시에 갱신하는 방식입니다.

각 전략의 장단점을 이해하고 상황에 맞게 선택해야 합니다.

다음 코드를 살펴봅시다.

// Cache-Aside 패턴 (가장 일반적)
async function getUserWithCacheAside(userId) {
  const cacheKey = `user:${userId}`;

  // 1. 캐시 조회
  const cached = await redis.get(cacheKey);
  if (cached) {
    return JSON.parse(cached);  // 캐시 히트
  }

  // 2. 캐시 미스: DB에서 조회
  const user = await db.query('SELECT * FROM users WHERE id = ?', [userId]);

  // 3. 캐시에 저장 (TTL 1시간)
  await redis.setex(cacheKey, 3600, JSON.stringify(user));

  return user;
}

// Write-Through 패턴
async function updateUserWithWriteThrough(userId, userData) {
  // 1. 먼저 DB 업데이트
  await db.query('UPDATE users SET name = ?, email = ? WHERE id = ?',
    [userData.name, userData.email, userId]);

  // 2. 캐시도 즉시 갱신
  const cacheKey = `user:${userId}`;
  await redis.setex(cacheKey, 3600, JSON.stringify(userData));

  return userData;
}

박시니어 씨가 화이트보드에 두 개의 다이어그램을 그렸습니다. "캐시 전략은 마치 노트 필기 습관과 비슷해요." 첫 번째 다이어그램 옆에 Cache-Aside라고 적었습니다.

"이건 '필요할 때 찾아보는' 방식이에요. 수업 시간에 질문을 받으면 먼저 자기 노트를 확인하고, 없으면 교과서를 찾아보는 거죠." Cache-Aside 패턴의 동작 방식을 단계별로 살펴보겠습니다.

애플리케이션이 데이터를 요청합니다. 먼저 캐시를 확인합니다.

데이터가 있으면 바로 반환합니다. 이것을 **캐시 히트(Cache Hit)**라고 합니다.

캐시에 데이터가 없으면 데이터베이스에서 조회합니다. 이것을 **캐시 미스(Cache Miss)**라고 합니다.

조회한 데이터를 캐시에 저장한 후 반환합니다. 다음번에 같은 요청이 오면 캐시에서 바로 가져올 수 있습니다.

이 패턴의 장점은 구현이 간단하다는 것입니다. 애플리케이션이 직접 캐시를 제어하므로 유연하게 사용할 수 있습니다.

또한 캐시 서버에 장애가 발생해도 데이터베이스에서 데이터를 가져올 수 있습니다. 단점은 첫 번째 요청은 항상 느리다는 것입니다.

캐시가 비어 있기 때문입니다. 이를 콜드 스타트(Cold Start) 문제라고 합니다.

김개발 씨가 물었습니다. "데이터가 업데이트되면 어떻게 하죠?" 박시니어 씨가 두 번째 다이어그램을 가리켰습니다.

"그래서 Write-Through 전략이 필요해요." Write-Through 패턴은 데이터를 쓸 때 캐시와 데이터베이스를 동시에 갱신합니다. 마치 노트와 교과서에 같은 내용을 동시에 적는 것과 같습니다.

이 패턴의 장점은 데이터 일관성입니다. 캐시와 데이터베이스가 항상 같은 상태를 유지합니다.

캐시에서 읽는 데이터가 항상 최신임을 보장할 수 있습니다. 단점은 쓰기 작업이 느려진다는 것입니다.

데이터베이스뿐만 아니라 캐시에도 저장해야 하기 때문입니다. 또한 자주 변경되지만 거의 읽히지 않는 데이터도 캐시에 저장되므로 메모리가 낭비될 수 있습니다.

실무에서는 두 전략을 조합하여 사용합니다. 읽기에는 Cache-Aside를, 쓰기에는 Write-Through를 적용하는 것이 일반적입니다.

위 코드 예제가 바로 이 조합을 보여줍니다. 추가로 알아두면 좋은 전략이 있습니다.

Write-Behind(Write-Back) 패턴입니다. 쓰기 작업 시 캐시에만 먼저 저장하고, 나중에 비동기로 데이터베이스에 반영합니다.

쓰기 성능은 좋아지지만 데이터 손실 위험이 있어 주의가 필요합니다. 또한 TTL(Time To Live) 설정도 중요합니다.

캐시 데이터에 만료 시간을 설정하면 오래된 데이터가 자동으로 삭제됩니다. 위 코드에서 setex 명령의 두 번째 인자 3600은 3600초, 즉 1시간 후에 만료됨을 의미합니다.

김개발 씨가 정리했습니다. "그러면 저희 서비스에서는 사용자 프로필은 Cache-Aside로 읽고, 프로필 수정 시에는 Write-Through로 캐시도 같이 갱신하면 되겠네요!" 박시니어 씨가 엄지를 치켜들었습니다.

"정확해요! 이제 실제로 코드에 적용해 볼까요?"

실전 팁

💡 - 읽기가 많고 쓰기가 적은 데이터에는 Cache-Aside가 효과적입니다

  • TTL은 데이터 특성에 맞게 설정하되, 처음에는 짧게 시작해서 점진적으로 늘려가세요
  • 캐시 무효화(Invalidation) 시점을 명확히 정의해두어야 데이터 불일치를 방지할 수 있습니다

6. 애플리케이션에서 Redis 연동하기

모든 준비가 끝났습니다. 캐시 전략도 정했고, Redis 클러스터도 떠 있습니다.

이제 김개발 씨는 실제 애플리케이션 코드에 Redis를 연동할 차례입니다. Node.js 프로젝트를 열고 Redis 클라이언트 라이브러리를 설치하기 시작했습니다.

ElastiCache Redis를 애플리케이션에 연동하려면 Redis 클라이언트 라이브러리가 필요합니다. Node.js에서는 ioredis가 가장 널리 사용됩니다.

클러스터 모드, 센티넬, 파이프라인 등 고급 기능을 모두 지원하며 성능도 우수합니다. 연결 풀 관리와 에러 처리를 올바르게 구현하는 것이 중요합니다.

다음 코드를 살펴봅시다.

// ioredis 설치: npm install ioredis

const Redis = require('ioredis');

// ElastiCache Redis 연결 설정
const redis = new Redis({
  host: 'my-redis-cluster.xxxxx.ng.0001.apn2.cache.amazonaws.com',
  port: 6379,
  password: process.env.REDIS_PASSWORD,  // AUTH 설정 시
  tls: {},  // TLS 활성화 시 필요
  retryStrategy(times) {
    const delay = Math.min(times * 50, 2000);
    return delay;  // 재연결 간격 (ms)
  },
  maxRetriesPerRequest: 3
});

// 연결 이벤트 핸들링
redis.on('connect', () => console.log('Redis 연결됨'));
redis.on('error', (err) => console.error('Redis 에러:', err));

// 캐시 헬퍼 함수
async function cacheGet(key, fetchFn, ttl = 3600) {
  const cached = await redis.get(key);
  if (cached) return JSON.parse(cached);

  const data = await fetchFn();
  await redis.setex(key, ttl, JSON.stringify(data));
  return data;
}

// 실제 사용 예시
const user = await cacheGet(`user:${userId}`,
  () => db.query('SELECT * FROM users WHERE id = ?', [userId]),
  3600
);

김개발 씨가 터미널을 열고 명령어를 입력했습니다. npm install ioredis.

설치가 완료되자 새 파일을 만들기 시작했습니다. 박시니어 씨가 옆에서 지켜보며 말했습니다.

"ioredis를 선택한 건 좋은 결정이에요. Node.js에서 가장 안정적인 Redis 클라이언트거든요." Redis 클라이언트 라이브러리는 여러 가지가 있습니다.

node-redis도 많이 사용되지만, ioredis가 클러스터 모드 지원이 더 좋고 API도 직관적입니다. 대부분의 프로덕션 환경에서 ioredis를 선호합니다.

먼저 연결 설정을 살펴보겠습니다. host에는 ElastiCache 콘솔에서 확인한 Primary endpoint 주소를 입력합니다.

포트는 기본값인 6379를 사용합니다. TLS 암호화를 활성화했다면 tls 옵션을 빈 객체 **{}**로 설정해야 합니다.

이 옵션이 없으면 암호화된 연결이 실패합니다. retryStrategy는 연결이 끊어졌을 때 재연결 로직을 정의합니다.

위 코드에서는 재시도 횟수에 비례하여 대기 시간을 늘리되, 최대 2초까지만 기다립니다. 이렇게 하면 네트워크 일시적 장애에도 자동으로 복구됩니다.

maxRetriesPerRequest는 요청당 최대 재시도 횟수입니다. 이 횟수를 초과하면 에러를 반환합니다.

무한정 재시도하면 사용자 응답이 지연되므로 적절한 값을 설정해야 합니다. 연결 이벤트 핸들링도 중요합니다.

connect 이벤트는 연결 성공 시 발생합니다. error 이벤트는 에러 발생 시 발생합니다.

최소한 이 두 이벤트는 반드시 처리해야 합니다. 김개발 씨가 코드를 작성하다가 멈췄습니다.

"매번 캐시 조회 로직을 작성하면 코드가 중복되지 않을까요?" 박시니어 씨가 고개를 끄덕였습니다. "그래서 캐시 헬퍼 함수를 만드는 거예요." 위 코드의 cacheGet 함수를 보세요.

이 함수는 세 가지 인자를 받습니다. 캐시 키, 캐시 미스 시 실행할 함수, 그리고 TTL입니다.

이 헬퍼 함수를 사용하면 어떤 데이터든 일관된 방식으로 캐싱할 수 있습니다. 캐시 조회, 미스 처리, 저장 로직을 한 곳에서 관리하므로 유지보수도 쉬워집니다.

실제 사용 예시를 보면 코드가 매우 깔끔해집니다. 캐시 키와 데이터 조회 함수만 전달하면 됩니다.

나머지는 헬퍼 함수가 알아서 처리합니다. 프로덕션 환경에서 추가로 고려해야 할 사항이 있습니다.

연결 풀링입니다. ioredis는 기본적으로 단일 연결을 사용합니다.

대량의 요청을 처리해야 한다면 연결 풀을 구성하거나 파이프라이닝을 활용해야 합니다. 직렬화 포맷도 중요합니다.

JSON은 가장 일반적이지만, 대용량 데이터에는 MessagePack이나 Protocol Buffers가 더 효율적일 수 있습니다. 캐시 프리픽스도 고려하세요.

여러 서비스가 같은 Redis를 공유한다면 키 충돌을 방지해야 합니다. service:entity:id 형태의 네이밍 규칙을 사용하면 좋습니다.

김개발 씨가 코드를 배포하고 모니터링 대시보드를 확인했습니다. 데이터베이스 쿼리 수가 급격히 줄어들고, 응답 시간이 눈에 띄게 빨라졌습니다.

"와, 정말 효과가 있네요!" 박시니어 씨가 미소를 지었습니다. "캐시 적중률(Hit Rate)을 계속 모니터링하세요.

80% 이상이면 훌륭한 거예요. 그리고 메모리 사용량도 확인해야 해요.

Redis 메모리가 가득 차면 오래된 데이터가 삭제될 수 있거든요." 김개발 씨는 이제 캐싱의 힘을 직접 경험했습니다. ElastiCache 덕분에 서비스 성능이 획기적으로 개선되었고, 데이터베이스 부하 걱정도 덜 수 있게 되었습니다.

실전 팁

💡 - 환경 변수로 Redis 연결 정보를 관리하여 환경별로 쉽게 전환할 수 있게 하세요

  • 캐시 적중률(Hit Rate)을 CloudWatch에서 모니터링하고 80% 이상을 목표로 최적화하세요
  • 개발 환경에서는 로컬 Redis를 사용하고, 배포 환경에서만 ElastiCache를 사용하도록 구성하면 개발이 편리합니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#AWS#ElastiCache#Redis#Caching#Performance#AWS,ElastiCache,Performance

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.

함께 보면 좋은 카드 뉴스

CloudTrail로 AWS 활동 추적 및 감사 완벽 가이드

AWS CloudTrail을 활용하여 누가, 언제, 무엇을 했는지 추적하고 감사하는 방법을 알아봅니다. 보안 사고 대응과 규정 준수를 위한 필수 서비스입니다.

CloudWatch로 리소스 모니터링 및 자동화 완벽 가이드

AWS CloudWatch를 활용하여 인프라와 애플리케이션을 모니터링하고 자동화하는 방법을 알아봅니다. 지표 수집부터 로그 분석, 이벤트 기반 자동화까지 실무에 필요한 핵심 기능을 다룹니다.

IAM으로 AWS 보안 및 권한 체계 구축

AWS 클라우드 환경에서 보안의 핵심인 IAM(Identity and Access Management)을 처음부터 끝까지 배웁니다. 사용자, 그룹, 역할, 정책의 개념부터 실무에서 바로 적용할 수 있는 보안 설정까지, 초급 개발자도 쉽게 따라할 수 있도록 설명합니다.

DynamoDB NoSQL로 확장 가능한 데이터 저장

AWS DynamoDB의 핵심 개념부터 실전 활용까지, 초급 개발자도 쉽게 이해할 수 있도록 설명합니다. 파티션 키 설계부터 GSI, Streams까지 단계별로 배워봅니다.

VPC 엔드포인트로 AWS 서비스 프라이빗 연결

AWS 서비스에 프라이빗하게 접근하는 VPC 엔드포인트의 개념과 설정 방법을 알아봅니다. 게이트웨이 엔드포인트와 인터페이스 엔드포인트의 차이점, S3 연결 설정, 그리고 비용 절감 효과까지 실무 중심으로 설명합니다.