Skip to content
메모장
Go back

Redis 비교

📂 Redis vs Memcached

1. 기본 설계 철학

RedisMemcached
데이터 모델String, Hash, List, Set, Sorted Set, Stream, Bitmap, HyperLogLog 등 다양한 자료구조단순 key-value (value는 opaque blob, 보통 1MB 제한)
아키텍처싱글 스레드 이벤트 루프 (커맨드 처리 기준, I/O는 6.0+부터 멀티스레드 일부 지원)멀티스레드 (libevent 기반, 스레드별 독립 락)
영속성RDB snapshot, AOF(append-only file) 지원 → 재시작 시 데이터 복구 가능없음. 프로세스 재시작하면 데이터 전부 소실
메모리 관리jemalloc 등 커스텀 allocator, 자체 메모리 관리 정책(maxmemory-policy)slab allocator (고정 크기 청크로 메모리 재사용, 단편화 이슈 유명)

2. 동시성 모델

3. 클러스터링 / 고가용성

4. 언제 뭘 쓰나

5. 실무에서 자주 나오는 차이점


📂 부록: Valkey

배경

2024년 3월, Redis Inc.가 Redis 7.4부터 라이선스를 기존 BSD 3-Clause에서 RSAL(Redis Source Available License) + SSPL 이중 라이선스로 전환하면서 논란이 발생. 클라우드 벤더(AWS, 클라우드 재판매 사업자 등)가 Redis를 관리형 서비스로 팔면서 원 프로젝트에 기여하지 않는 문제(소위 “free-riding”)를 막겠다는 취지였지만, 오픈소스 진영에서는 “더 이상 오픈소스가 아니다”라는 반발이 큼.

이에 Linux Foundation 산하로 Valkey가 포크됨. AWS, Google Cloud, Oracle, Ericsson, Snap 등이 주도적으로 참여. 마지막 BSD 라이선스였던 Redis 7.2.4를 베이스로 시작.

현재 상태

Redis와의 차이 (기술적)

실무 관점


📂 Redis vs RDS (관계형 DB)

먼저 전제: RDS는 AWS의 관리형 서비스 이름이지만, 여기서는 논의의 핵심이 “관계형 DB(RDBMS, MySQL/PostgreSQL 등)“이므로 그 관점에서 정리한다. RDS 자체의 운영 이슈(백업, Multi-AZ 등)는 별도로 다룬다.

1. 근본적으로 다른 존재 이유

RedisRDBMS (RDS)
정체성인메모리 데이터 구조 저장소 (원래 캐시로 시작)영속적 시스템 오브 레코드
데이터 위치메모리(RAM)가 1차, 디스크는 백업/복구용디스크가 1차, 메모리는 버퍼캐시
목표낮은 지연시간, 높은 처리량데이터 정합성, 내구성, 복잡한 질의

이 하나의 차이에서 아래 모든 이슈가 파생된다.

2. Redis가 RDS를 대체할 수 없는 이유

(1) 내구성(Durability) 보장 수준이 다름

(2) 트랜잭션 격리 수준(Isolation)이 다름

(3) 관계/제약조건이 없음

(4) 쿼리 유연성 부족

(5) 데이터 크기당 비용

(6) 백업/복구, 감사(audit), 운영 성숙도

3. 실무 패턴: 그래서 어떻게 같이 쓰나

핵심 한 문장으로 요약하면: Redis는 “빠른 접근이 필요한 휘발성 가능 데이터”를 위한 것이고, RDBMS는 “정합성이 보장되어야 하는 영구 데이터”를 위한 것 — 이 둘은 경쟁 관계가 아니라 상호보완 관계.


📂 Redis 설계 패턴

프로덕션에서 실제로 트레이드오프가 갈리는 4가지 패턴을 정리한다.

1. 분산 락 (Distributed Lock)

기본 형태

SET resource_name unique_random_value NX PX 30000

Redlock 알고리즘 단일 Redis 인스턴스 락은 그 인스턴스가 죽으면 보장이 깨짐 → antirez가 제안한 Redlock은 N개(보통 5개)의 독립된 Redis 인스턴스 중 과반수(quorum)에서 락 획득에 성공해야 락을 잡은 것으로 간주하는 방식.

Kleppmann vs antirez 논쟁

Martin Kleppmann이 2016년 Redlock을 정면 비판했고, antirez가 반박한 유명한 논쟁이다. 핵심 쟁점 두 가지:

  1. 타이밍 가정의 취약성: GC pause, 클럭 점프, 네트워크 지연으로 클라이언트가 “나 아직 락 갖고 있어”라고 착각한 채로 깨어날 수 있음. 그 사이 락은 이미 만료돼서 다른 클라이언트가 새로 획득했을 수 있음 → 두 클라이언트가 동시에 자원에 쓰기를 함.
  2. Fencing token 부재: Redlock이 주는 랜덤 값은 단조증가(monotonic)하지 않아서, 이 쓰기 요청이 더 최신 락 소유자의 것인지를 보호 대상 리소스가 검증할 방법이 없음. 진짜 안전한 분산 락은 락 획득 시 단조증가하는 토큰을 발급하고, 보호 대상(DB 등)이 “더 작은 토큰의 쓰기는 거부”하는 방식으로 fencing을 해야 함.

Kleppmann의 결론(그리고 지금 실무에서 받아들여지는 원칙)은 “효율성(efficiency)을 위한 락”과 “정합성(correctness)을 위한 락”을 구분하라는 것.

이건 앞서 정리한 “Redis가 RDS를 대체할 수 없는 이유”와도 이어지는 지점 — 정합성이 진짜 중요한 곳에서는 결국 RDBMS의 제약조건/트랜잭션이 최후의 방어선이 된다.

2. 캐시 스탬피드(Thundering Herd) 방지

인기 키가 만료되는 순간 수천 개의 동시 요청이 전부 DB로 몰려가는 문제.

방법 A: Mutex 락 요청 A가 SET NX로 락을 잡고 DB에서 값을 가져와 캐시를 채우는 동안, 나머지 요청들은 락 해제를 기다리거나(폴링/짧은 재시도) 약간 stale한 값을 반환. 구현이 단순하고 DB 쿼리 수를 확실히 1개로 제한하지만, 락 대기 시간만큼 tail latency가 늘어남.

방법 B: Probabilistic Early Expiration (X-Fetch) 락을 아예 쓰지 않고, 만료 시점이 다가올수록 “지금 미리 재계산할 확률”을 높여서 여러 요청 중 극소수만 먼저 재계산을 트리거하는 방식.

Gap = CurrentTime - (TimeToCompute × β × ln(Random(0,1)))
Gap >= ExpiryTime 이면 재계산

실측 비교치: 10,000 동시 요청 기준, X-Fetch(β=1.0, TTL 60s)는 DB 쿼리 3~5회, p50 12ms, DB CPU 2%. 반면 mutex 락은 DB 쿼리 1회로 더 적지만 락 대기 때문에 p50이 580ms까지 올라감.

낮은 트래픽/단순함이 우선이면 mutex 락, 초고트래픽 핫키라 락 경합 자체가 문제면 X-Fetch, 둘을 섞어 X-Fetch를 기본으로 하고 완전 캐시 미스(cold start)일 때만 mutex로 폴백하는 하이브리드가 실무에서 많이 쓰인다.

3. Rate Limiting

알고리즘Redis 자료구조특징
Fixed WindowINCR + EXPIRE (또는 INCREX)가장 단순. 윈도우 경계에서 순간적으로 2배 트래픽 허용되는 약점(예: 0:59에 100개, 1:00에 또 100개)
Sliding Window LogSorted Set (ZADD, ZREMRANGEBYSCORE, ZCARD)정확하지만 요청마다 멤버를 저장해서 메모리 비용이 큼
Sliding Window Counter두 개의 Fixed Window 카운터를 가중평균로그 방식보다 메모리 효율적, 근사치
Token BucketLua 스크립트로 토큰 수/마지막 리필 시각 관리버스트 트래픽 허용하면서 평균 rate는 제한
GCRA (leaky bucket 변형)키 1개에 TAT(이론적 도착 시각)만 저장sliding window log 수준 정확도 + 메모리 효율, 버스트/평균 rate를 동시에 표현

공통 원칙: 읽기-판단-갱신을 한 번의 Lua 스크립트(EVAL)로 묶어서 원자적으로 처리해야 동시 요청 사이의 race condition(카운터 이중 증가, 토큰 이중 차감)을 막을 수 있다.

GCRA (Generic Cell Rate Algorithm) ATM 네트워크에서 유래한 leaky bucket 변형. 매 요청마다 “이론적 도착 시각(TAT, Theoretical Arrival Time)” 하나만 갱신하면 되므로 sliding window log보다 메모리 효율적이면서도 동등한 정확도를 낸다. redis-cell 모듈이 CL.THROTTLE 커맨드로 구현을 제공하며, 버스트 허용치와 평균 rate를 동시에 파라미터로 표현할 수 있어 Token Bucket보다 직관적이라는 평가를 받는다.

Redis 8.8: INCREX — 네이티브 rate limiter 커맨드 2026년 5월 출시된 Redis 8.8에 INCREX가 추가됐다. INCR+INCRBY+bounds+EXPIRE를 하나의 원자적 커맨드로 묶은 것으로, Fixed Window Counter 패턴을 더 이상 Lua 스크립트나 MULTI/EXEC 없이 커맨드 1개로 처리할 수 있게 됐다. 다만 Sliding Window/Token Bucket/GCRA처럼 정교한 패턴은 여전히 Lua나 모듈이 필요하다.

분산 환경에서 실무 이슈

4. Redis Streams — Consumer Group 패턴

Kafka와 가장 유사한 Redis 기능. List 기반 큐(LPUSH/BRPOP)나 Pub/Sub과 달리 메시지 이력 보존 + at-least-once 전달 보장이 된다.

동작 흐름

  1. XADD로 스트림에 메시지 추가
  2. XREADGROUP으로 컨슈머 그룹 소속 컨슈머가 메시지를 읽으면, 그 메시지는 PEL(Pending Entries List) — 아직 ack 안 된 메시지 목록 — 로 이동. 같은 그룹 내 다른 컨슈머는 이 메시지를 다시 받지 않는다(로드밸런싱 자동 처리).
  3. 처리 완료 후 XACK으로 PEL에서 제거.
  4. 컨슈머가 죽어서 PEL에 메시지가 계속 남아 있으면, XPENDING으로 idle 메시지를 조회하고 XCLAIM으로 다른 컨슈머가 가져가서 재처리 가능.

운영 시 주의점

정리: 언제 뭘 쓰나


참고 문서

공식 문서 (1차 자료)

분산 락 / Redlock

캐시 스탬피드

Rate Limiting / GCRA

개념 학습


Share this post:

Previous Post
Spring @Async vs Kotlin 코루틴 — 회원탈퇴 소셜 unlink 처리로 보는 선택 기준
Next Post
Spring Security + 애플 로그인 구현 (OIDC + client_secret JWT)