Skip to content
Published on

Redis 내부와 분산 캐시 — 싱글 스레드, 자료구조, Cluster, Sentinel, RDB/AOF, Redlock, Valkey, Dragonfly 완전 정복 (2025)

Authors

"Redis is what happens when a C programmer falls in love with data structures." — Salvatore Sanfilippo (antirez)

Redis만큼 **"그냥 쓴다"**와 "제대로 이해하고 쓴다" 사이의 간극이 큰 시스템도 드물다. 대부분의 개발자는 GET/SET 두 명령만 쓰고, 그것도 문자열 캐시 용도로만 쓴다. 그러나 Redis는 사실 인메모리 데이터 구조 서버(In-Memory Data Structure Server) — 캐시는 부산물일 뿐이다.

2009년 Salvatore Sanfilippo가 자신의 웹 분석 도구 LLOOGG를 위해 만들었다. MySQL로는 실시간 랭킹을 유지할 수 없어서 직접 만든 "Remote Dictionary Server"가 Redis의 시작이다. 2010년 VMware가 고용, 2013년 Pivotal, 2015년 Redis Labs(현 Redis Inc)로 이어졌다. 그리고 2024년 3월, Redis는 갑자기 오픈소스 라이선스를 버렸다. Linux Foundation이 Valkey를 포크하면서 클라우드 전쟁의 새 국면이 열렸다.

이 글은 Redis를 "정말로" 이해하려는 사람을 위한 지도다.


1. 왜 Redis는 빠른가 — 싱글 스레드 역설

흔한 오해

"싱글 스레드인데 빠르다니, 코어를 놀리는 거 아닌가?"

아니다. Redis 6.0부터는 네트워크 I/O는 멀티스레드로 처리하지만, 명령 실행 자체는 여전히 싱글 스레드다. 그리고 이것이 빠른 이유다.

싱글 스레드의 합리성

  1. 메모리 속도 = CPU 속도에 가까움 — 병목이 네트워크와 OS 호출에 집중된다
  2. 락 없음 — 공유 자료구조에 락/뮤텍스 오버헤드 제로
  3. 컨텍스트 스위치 없음 — CPU 캐시 locality 최대
  4. 원자성이 자연스러움 — 모든 명령이 atomic
  5. 디버그/추론 쉬움 — 버그 재현이 단순하다

antirez의 말: "이미 2009년에 나는 락 기반 멀티스레딩이 현실적으로 어렵다는 것을 알고 있었다. 락 없이 빠른 것을 만들자."

그런데 어떻게 100만 QPS?

실제로 Redis는 단일 인스턴스에서 초당 100만 명령을 넘게 처리한다. 비결은:

  • I/O 멀티플렉싱epoll(Linux)/kqueue(BSD) 이벤트 루프로 한 스레드에서 수천 개의 소켓을 동시에 감시
  • RESP 프로토콜 — 단순한 텍스트 기반, 파싱 비용 최소
  • 파이프라이닝 — 한 번에 여러 명령을 보내고 응답을 묶어서 받음
  • 제로카피 아님 — 하지만 작은 단위라 문제 없음
  • 대부분 O(1)O(1) 또는 O(logN)O(\log N) 자료구조

Event Loop 한 바퀴

1. epoll_wait() — 읽기/쓰기 준비된 소켓 찾기
2. 요청 파싱 (RESP)
3. 명령 실행 (싱글 스레드, 메모리 조작만)
4. 응답 버퍼에 쓰기
5. 다음 이벤트로 이동

한 명령이 오래 걸리면? 전체가 멈춘다. 그래서 KEYS *FLUSHALL은 프로덕션에서 절대 금지. 대신 SCAN, UNLINK를 쓴다.


2. 자료구조 — Redis의 진짜 힘

Redis의 OBJECT ENCODING mykey로 내부 인코딩을 확인해보면 놀랄 것이다. 같은 "String"이라도 숫자면 int, 짧으면 embstr, 길면 raw로 다르게 저장된다.

9가지 핵심 자료구조

자료구조사용처내부 구현특이점
String문자열/숫자/바이너리SDS (Simple Dynamic String)512MB까지
List큐/스택QuickList (ziplist+linkedlist)양방향 O(1) push/pop
Hash객체 필드listpack/hashtableziplist로 작은 해시 최적화
Set고유값 집합listpack/intset/hashtable숫자만 있으면 intset
Sorted Set랭킹/우선순위 큐Skip List + hash역사적으로 흥미로운 선택
Stream이벤트 로그Radix TreeKafka-like consumer group
HyperLogLog카디널리티 추정12KB 고정, 표준편차 0.81%확률적 자료구조
Bitmap비트 배열String 기반10억 유저 DAU를 128MB에
Geospatial위치 질의Sorted Set + GeohashGEOADD/GEORADIUS

SDS — 왜 C 문자열이 아닌가

struct sdshdr {
    int len;     // O(1) strlen
    int free;    // 여분 공간 (재할당 감소)
    char buf[];  // 실제 데이터 + '\0'
};
  • strlen O(1) (C 문자열은 O(N))
  • Binary safe (중간에 \0 포함 가능)
  • 재할당 횟수 감소 (2배 버퍼링)

Sorted Set의 Skip List — 왜 Red-Black Tree가 아닌가

antirez가 Skip List를 선택한 이유 (직접 블로그에 썼다):

  1. 구현이 단순 — B-Tree/Red-Black Tree 대비 절반 이하
  2. Range query 최적화 — 정렬된 링크드리스트 구조
  3. 메모리 locality가 적당히 좋음
  4. 디버깅 쉬움 — 트리 회전 없음

"내가 Skip List를 고른 것은 그것이 최적이어서가 아니라, 구현이 단순했기 때문이다." — antirez

HyperLogLog — 12KB로 수십억 카디널리티 추정

  • "오늘 방문한 UV가 몇 명?" → Set으로 하면 메모리 폭발
  • HLL은 확률적 자료구조로 표준편차 0.81%로 추정
  • 고정 12KB — 1억 명도 12KB, 100억 명도 12KB
PFADD visitors user:1 user:2 user:3
PFCOUNT visitors  # 근사치 반환
PFMERGE today yesterday  # 집합 합집합 근사

Bitmap — SETBIT의 위력

SETBIT user:active:20260415 12345 1  # user 12345 오늘 접속
BITCOUNT user:active:20260415       # 오늘 DAU
BITOP AND weekly user:active:*      # 주간 활성

10억 유저 → 10억 비트 → 128MB. RDB보다 훨씬 빠르게 "지난 30일 연속 접속 사용자" 같은 질의가 가능.

Stream — 2018년 추가, Kafka-lite

Redis 5.0부터. Consumer Group + offset 관리로 Kafka-lite 용도. 단, 영속성은 Redis persistence에 의존하므로 Kafka 대체라기보다 경량 메시지 버스.


3. 영속성 — RDB vs AOF, 그 미묘한 트레이드오프

Redis는 인메모리지만 데이터 손실을 막기 위해 두 가지 영속성을 제공한다.

RDB (Redis Database) — 스냅샷

  • 주기적으로 전체 데이터셋을 바이너리 파일로 덤프
  • BGSAVE — fork() 후 자식 프로세스가 덤프, 부모는 계속 서비스
  • Copy-on-Write 덕에 부모 메모리 2배가 되지 않음(대개)
  • 단점: fork 시점 이후 데이터는 손실 가능
  • 장점: 재시작이 빠름, 파일 작음

AOF (Append-Only File) — 로그

  • 모든 쓰기 명령을 파일 끝에 append
  • fsync 정책:
    • always — 매 명령마다 fsync (느림, 손실 없음)
    • everysec — 1초마다 fsync (기본값, 최대 1초 손실)
    • no — OS 맡김 (빠름, 손실 큼)
  • AOF Rewrite — 주기적으로 압축 (현재 상태를 재구성하는 최소 명령만)
  • 단점: 재시작이 느림 (모든 명령 재생), 파일 큼
  • 장점: 손실 거의 없음

혼용 전략 — Redis 4.0+

aof-use-rdb-preamble yes — AOF 파일 앞에 RDB를, 뒤에 증분 AOF를 붙인다. 빠른 재시작 + 적은 손실을 모두 얻는다. 현재 사실상 표준.

의사결정 매트릭스

시나리오RDBAOF혼용
캐시 용도O (영속성 불필요)XX
세션 저장XO (everysec)O
재시작 시간 중요OXO (RDB preamble)
주 저장소XO (always)O (best)
디스크 I/O 예민OX조심

그런데 진짜 영속 저장소로 쓸 수 있나?

권장하지 않는다. antirez도 여러 번 경고했다. Redis는 "빠른 캐시 + 최소 데이터 손실"이 목표이지 "완벽한 내구성"이 목표가 아니다. 중요한 데이터는 Postgres/MySQL에 쓰고 Redis는 캐시로 쓰자.


4. Redis Cluster — Hash Slot의 예술

왜 Cluster?

  • 단일 Redis는 메모리/처리량 한계 (보통 한 인스턴스 수십 GB)
  • 멀티 샤드가 필요 → Redis Cluster (3.0, 2015년)

Hash Slot — 16384개

  • 키를 CRC16으로 해싱 후 16384(2^14)으로 모듈로
  • 각 슬롯을 마스터 노드에 할당
  • 예: 3 마스터라면 각 ~5461 슬롯

왜 16384인가

antirez가 직접 답한 유명한 GitHub 이슈:

  1. 각 노드가 보유한 슬롯을 비트맵으로 전송하는데, 16384비트 = 2KB
  2. 65536이면 8KB — 가십 프로토콜에서 너무 크다
  3. 1000개 미만 클러스터에서는 16384가 분배 품질에 충분

MOVED & ASK — 리다이렉션

클라이언트가 잘못된 노드에 요청하면:

  • MOVED <slot> <host>:<port> — "이 슬롯은 영구적으로 저기 있다"
  • ASK <slot> <host>:<port> — "지금 마이그레이션 중이야, 한 번만 저기 물어봐"

스마트 클라이언트(Lettuce, redis-py-cluster)는 자동으로 슬롯 맵을 캐시하고 MOVED가 오면 갱신한다.

Hash Tag — 같은 슬롯에 보장

SET {user:1}:profile "..."
SET {user:1}:sessions "..."
# 둘 다 CRC16("user:1") 기준으로 해싱되어 같은 슬롯
# 따라서 MULTI/EXEC, SUNION 같은 멀티 키 명령 가능

{} 안의 부분만 해싱에 쓰인다. 트랜잭션이나 Lua 스크립트에서 여러 키를 다룰 때 필수.

Gossip & Failure Detection

  • 노드들끼리 PING/PONG으로 상태 교환
  • cluster-node-timeout 넘으면 PFAIL (주관적 실패)
  • 다수의 노드가 PFAIL 보고하면 FAIL (객관적 실패)
  • Replica가 자동 승격

한계

  • 복잡 질의(SINTER) 같은 멀티키 명령은 같은 슬롯 강제
  • 크로스 슬롯 트랜잭션 불가
  • 백업이 복잡 (노드별로 따로)

5. Sentinel — 고가용성의 또 다른 길

Cluster가 샤딩+HA를 함께 제공한다면, Sentinel은 단순 HA만 제공한다.

구조

  • 마스터 1 + 리플리카 N + Sentinel M (보통 3개 이상, 홀수)
  • Sentinel들이 마스터 상태를 모니터링
  • 장애 시 Raft-유사 합의로 새 리더 선출
  • 클라이언트는 Sentinel에 먼저 물어보고 현재 마스터를 알아냄

Cluster vs Sentinel

측면SentinelCluster
샤딩XO
HAOO
설정 복잡도낮음중간
앱 클라이언트 지원넓음Smart client 필요
운영 규모소~중중~대
멀티키 명령완전 지원Hash Tag 필요

선택 기준: 데이터가 한 노드 메모리에 들어가면 Sentinel, 안 들어가면 Cluster.


6. 캐시 패턴 — 뜨거운 감자

Cache-Aside (Lazy Loading)

def get_user(id):
    user = redis.get(f"user:{id}")
    if user is None:
        user = db.query(id)
        redis.set(f"user:{id}", user, ex=3600)
    return user
  • 가장 흔한 패턴
  • 장점: 구현 쉬움, 캐시 미스만 DB 부담
  • 단점: 처음 요청이 느림, Stale 데이터 가능

Write-Through

def update_user(id, data):
    db.update(id, data)
    redis.set(f"user:{id}", data, ex=3600)  # 동시에 갱신
  • 쓰기마다 DB + 캐시 모두 갱신
  • 캐시 일관성 좋음
  • 단점: 쓰기 지연 증가, 잘 안 읽히는 데이터도 캐시

Write-Behind (Write-Back)

def update_user(id, data):
    redis.set(f"user:{id}", data)
    queue.push({"id": id, "data": data})
    # 워커가 배치로 DB 쓰기
  • 쓰기 지연 최소
  • 단점: 데이터 손실 위험, 구현 복잡

Refresh-Ahead

  • TTL 임박한 캐시를 비동기로 미리 갱신
  • Thundering Herd(아래) 방지

실전 조합

대부분의 프로덕션은 Cache-Aside + TTL + (조건부) Write-Through. 중요한 건 TTL 전략:

  • 짧은 TTL (1-5분) — 최신성 중요
  • 긴 TTL (1시간+) — 변경 적은 데이터
  • Jitterex=3600 + random(-300, 300) — 동시 만료 방지

7. Thundering Herd & Cache Stampede

가장 흔하면서 가장 은밀한 Redis 장애 원인.

시나리오

  1. 인기 키가 만료됨
  2. 동시에 수천 요청이 캐시 미스
  3. 모두 DB로 몰림 → DB 과부하 → 전체 장애

해결책 1 — Mutex Lock

def get_with_lock(key):
    value = redis.get(key)
    if value is not None:
        return value
    
    lock = redis.set(f"lock:{key}", "1", nx=True, ex=10)
    if not lock:
        time.sleep(0.05)
        return redis.get(key)  # 다른 프로세스가 채웠기를 기대
    
    try:
        value = db.query(...)
        redis.set(key, value, ex=3600)
        return value
    finally:
        redis.delete(f"lock:{key}")

해결책 2 — Probabilistic Early Expiration (XFetch)

만료 시간 전에 확률적으로 갱신. 논문 "Optimal Probabilistic Cache Stampede Prevention".

def fetch(key, beta=1.0):
    value, ttl, delta = redis.get_with_meta(key)
    now = time.time()
    if value is None or now - delta * beta * math.log(random.random()) >= ttl:
        value = db.query(...)
        redis.set(key, value, ex=3600)
    return value

해결책 3 — 이중 TTL (Soft & Hard)

  • Soft TTL 지나면 백그라운드 갱신, 클라이언트는 낡은 값 반환
  • Hard TTL 지나면 그때 동기 갱신

8. 분산 락 — Redlock 논쟁

Redis를 분산 락으로 쓰는 것은 매력적이다. SET key value NX PX 10000으로 간단히 구현.

단순 락 — 한 인스턴스

SET lock:resource unique_id NX PX 30000
# 성공하면 락 획득

# 해제 (Lua로 atomic하게 — unique_id 확인)
EVAL "if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end" 1 lock:resource unique_id

Redlock — 5개 인스턴스 기반 분산 락

antirez가 제안한 알고리즘:

  1. 5개 독립 Redis 인스턴스에 동시에 락 시도
  2. 과반(3개) 성공 + 총 시간이 TTL보다 작으면 락 획득
  3. 실패 시 모두 해제

Martin Kleppmann의 비판

DDIA 저자가 유명한 블로그로 반박:

  • Fencing token이 없음 — 프로세스가 GC 정지되면 만료된 락으로 작업 계속
  • 시계 비동기 가정 약함 — NTP 튐, VM 정지 등으로 TTL 보장 불가
  • 정확성(correctness)이 필요하면 Redlock 쓰지 말라 — ZooKeeper, etcd 써라

antirez의 반박

  • Redlock은 성능 목적 락 — 간헐적 중복 실행이 용납되는 경우에만
  • 정확성이 치명적이라면 DB 트랜잭션을 써라
  • Fencing token은 구현 가능 (단조 증가 카운터)

현실의 결론

목적권장 도구
중복 방지(성능)Redis SET NX PX
리더 선출(정확성)ZooKeeper/etcd
트랜잭션DB 자체
결제/돈 관련절대 Redis 락 금지

9. 2024년 라이선스 사태와 Valkey 포크

2024년 3월 20일, Redis Inc는 충격적 발표:

  • Redis 7.4부터 BSD → SSPL/RSALv2 이중 라이선스
  • 클라우드 사업자(AWS ElastiCache 등)에게 타격을 주려는 의도
  • 오픈소스 커뮤니티는 분노

Valkey — 48시간 만의 반격

  • 3월 28일, Linux Foundation이 Valkey 프로젝트 시작
  • AWS, Google Cloud, Oracle, Ericsson이 창립 스폰서
  • Redis 7.2.4에서 포크, BSD 3-Clause 유지
  • 주요 메인테이너 대부분 Valkey로 이동

antirez의 복귀

2024년 11월, antirez가 Redis Inc로 복귀. 2025년에는 벡터 검색(RedisVL), AI 통합에 집중.

2025년 현재 상황

제품라이선스주도기여자
RedisSSPL/RSALv2Redis Incantirez 복귀
ValkeyBSD 3-ClauseLinux FoundationAWS/Google/Oracle
KeyDBBSD 3-ClauseSnap멀티스레드 포크
DragonflyBSL/Apache 2.0Dragonfly Labs처음부터 재작성

선택 가이드:

  • 퍼블릭 클라우드 managed service 쓸 것 → 상관 없음 (ElastiCache는 Valkey 전환 중)
  • 자체 운영 + 오픈소스 고집 → Valkey
  • 멀티스레드 극한 성능 → Dragonfly
  • Redis 7.4+ 신기능 필요 → Redis

10. Dragonfly — "Redis를 25배 빠르게"

2022년 등장, C++20으로 처음부터 재작성. 비결:

  • 멀티스레드 Shared-nothing — 각 스레드가 자기 샤드 담당, 락 불필요
  • io_uring — Linux의 최신 비동기 I/O (기존 epoll보다 빠름)
  • Dash — 학술논문 기반 해시테이블 — 캐시 친화적
  • RDB 저장 속도 30배 — 메모리 스냅샷 알고리즘 혁신

성능 (2025 벤치마크)

  • 단일 AWS c7g.16xlarge: 650만 QPS (Redis는 ~200K QPS)
  • 메모리 효율도 30% 개선

한계

  • 스크립팅 지원 제한 (Lua)
  • Cluster 프로토콜 100% 호환 아직
  • 일부 edge case 명령 미구현
  • 운영 도구 생태계 작음

KeyDB

  • Snap(Snapchat)이 만든 멀티스레드 포크
  • Redis와 거의 100% 호환
  • 2024년 이후 개발 정체 — Dragonfly로 흐름이 옮겨감

11. 메모리 관리 — OOM을 막는 8가지

Redis에서 메모리 부족은 즉시 장애. 관리 원칙:

maxmemory + Eviction Policy

maxmemory 4gb
maxmemory-policy allkeys-lru

정책:

  • noeviction — 새 쓰기 거부 (기본값, 위험)
  • allkeys-lru — 모든 키 중 LRU 제거
  • volatile-lru — TTL 있는 키 중 LRU
  • allkeys-lfu — LFU (4.0+, 추천)
  • volatile-ttl — TTL 임박 우선
  • allkeys-random / volatile-random — 랜덤

캐시 용도면 allkeys-lfu 권장. LRU는 스캔 공격(한 번 읽고 다시 안 쓰는 키)에 취약.

메모리 프로파일링

MEMORY USAGE user:1
MEMORY STATS
MEMORY DOCTOR  # 진단

Big Key 문제

단일 키가 1MB 넘으면 위험:

  • KEYS 순회 비용
  • 네트워크 전송 지연
  • Cluster 재샤딩 시 전체 이동
  • 해결: 해시/리스트로 분할

Hot Key 문제

단일 키에 요청 집중:

  • CPU 한 코어가 풀로 돌아감
  • 해결: 클라이언트측 캐시, 샤드 분산, Replica로 읽기 분산

TTL 전략

  • 반드시 TTL 설정 — 무한 키는 메모리 누수
  • Jitter 추가 — 동시 만료 방지
  • Hot key는 TTL 길게, Cold는 짧게

12. Lua 스크립팅 & Functions

Redis는 Lua 5.1 인터프리터를 내장. 여러 명령을 atomic하게 실행.

-- 재고 차감 (race condition 없이)
local stock = tonumber(redis.call('GET', KEYS[1]))
if stock >= tonumber(ARGV[1]) then
    redis.call('DECRBY', KEYS[1], ARGV[1])
    return 1
else
    return 0
end

Functions (Redis 7.0+)

Lua 스크립트를 서버에 라이브러리로 저장 (함수 단위 관리).

주의

  • Lua 실행 중 다른 모든 명령 블록 — 오래 걸리는 스크립트 금지
  • EVAL 자주 쓰면 EVALSHA + SCRIPT LOAD로 캐시

13. Client-Side Caching (Tracking) — Redis 6.0

Redis가 서버 측 변경을 클라이언트에 푸시 알림. 클라이언트는 로컬 캐시를 유지하다가 무효화.

CLIENT TRACKING ON REDIRECT 1234 BCAST PREFIX user:
  • Roundtrip 제거 → 지연 극도로 짧아짐
  • 대부분의 현대 드라이버(Lettuce, redis-py)가 지원
  • 단, 클라이언트 메모리 관리 필요

14. 모니터링 지표 — 꼭 봐야 할 10개

지표설명경고선
used_memory / maxmemory메모리 사용률80%
evicted_keys축출된 키 수증가 추세
connected_clients동시 연결1만+ 주의
instantaneous_ops_per_secQPS베이스라인 대비
latency_percentiles_usec_*p99 지연1ms 초과
rejected_connections연결 거부0 유지
keyspace_hits / keyspace_misses캐시 히트율90% 이상
aof_current_sizeAOF 크기디스크 여유
rdb_last_save_time마지막 RDB오래되면 경고
master_link_status (Replica)복제 연결up

느린 명령 추적

CONFIG SET slowlog-log-slower-than 10000  # 10ms 이상
SLOWLOG GET 10

MONITOR 금지

MONITOR는 모든 명령을 스트리밍 → 성능 50%+ 저하. 운영에서는 절대 금지. 대신 SLOWLOG, LATENCY 명령.


15. 캐시 전략 안티패턴 TOP 10

  1. TTL 없는 키 대량 삽입 — 메모리 누수
  2. KEYS * 또는 FLUSHALL — 싱글 스레드 정지
  3. 거대한 Hash/List 누적 — 한 명령이 초 단위
  4. 캐시에만 데이터 저장 — Redis 손실 시 복구 불가
  5. 모든 키 같은 TTL — 동시 만료 → Stampede
  6. 분산 락으로 돈 관리 — Redlock 논쟁 참조
  7. Pub/Sub으로 영속 큐 — 메시지 사라짐, Stream 써라
  8. TTL 짧은 Write-Through — 쓰기마다 DB+Redis, 의미 없음
  9. Replica로 쓰기 — 복제는 비동기, 데이터 손실
  10. 클러스터에서 크로스 슬롯 트랜잭션 시도 — 조용히 실패

16. Redis를 현명하게 쓰는 체크리스트

  • 용도가 캐시인가, 저장소인가 명확히 구분
  • maxmemoryeviction policy 명시적 설정
  • 모든 키에 TTL — Jitter 포함
  • AOF + everysec로 1초 이내 손실 허용, 혼용 모드 고려
  • MONITOR / KEYS * / FLUSHALL 금지 정책
  • Big Key / Hot Key 경보 설정 (1MB/10k QPS)
  • 캐시 히트율 90%+ 목표, 미스면 왜인지 분석
  • Thundering Herd 대비 — Mutex 또는 XFetch
  • 분산 락은 성능 목적만 — 정확성이 필요하면 다른 도구
  • Cluster vs Sentinel 결정 기준 명확 (데이터 크기)
  • Client-Side Caching 검토 — 읽기 집중 워크로드
  • Replica 승격 시나리오 훈련 (Failover 테스트)

마치며 — 싱글 스레드의 우아함

Redis의 성공은 역설이다. 병렬이 왕인 시대에, 싱글 스레드로 초당 100만 QPS를 내는 시스템. 그 뒤에는 antirez의 철학이 있다.

"복잡한 것을 단순하게 만드는 게 아니라, 처음부터 단순하게 설계하는 것이 진짜 엔지니어링이다." — antirez

많은 "레거시" 기술이 그렇듯, Redis는 보기보다 훨씬 깊다. 자료구조, I/O 모델, 영속성, 분산, 트레이드오프 — 모든 결정에 이유가 있다. 2024년 라이선스 논쟁은 오픈소스와 상업화의 오래된 긴장이 Redis에서 터진 사건이고, Valkey/Dragonfly의 부상은 "Redis 그 자체보다 그 인터페이스가 더 중요해진" 시대를 보여준다.


다음 글 예고 — PostgreSQL 내부와 쿼리 최적화

Redis가 "데이터 구조의 우아함"이라면, PostgreSQL은 "관계형 DB의 완결판"이다. 다음 글에서는:

  • MVCC — 왜 PostgreSQL은 Oracle과 다르게 구현했나 (tuple versioning)
  • VACUUM의 비밀 — dead tuple, wraparound, autovacuum tuning
  • WAL과 Streaming Replication — Physical vs Logical 복제
  • Query Planner 내부 — 왜 같은 쿼리가 느리거나 빠른가 (EXPLAIN ANALYZE 읽기)
  • Index의 세계 — B-Tree, Hash, GiST, GIN, BRIN, HNSW (pgvector)
  • Partitioning & Sharding — Declarative partitioning, Citus
  • pgBouncer & Connection Pooling — 왜 PostgreSQL은 연결이 비싼가
  • JSONB vs Document DB — "Postgres로 다 된다"는 신화의 진실
  • pgvector / pg_duckdb — AI와 분석 워크로드를 품은 PostgreSQL
  • PostgreSQL 18(2025)의 신기능 — AIO, DirectIO, UUIDv7

데이터베이스가 "블랙박스가 아닌 투명한 엔진"임을 확인하는 여정.


"Redis는 원래 저를 위한 도구였습니다. 1만 명이 쓰기 시작하고, 100만 명이 쓰기 시작했을 때도, 저는 여전히 '내가 쓰기 좋게' 만들려고 했어요. 그게 Redis의 비밀입니다." — Salvatore Sanfilippo (2025, Redis 복귀 인터뷰)