레디스ttl

강코딩·2025년 10월 28일

레디스

목록 보기
19/21

🧩 Redis의 TTL(만료) 구조 — 전체 아키텍처 개요

Redis는 TTL을 핸들러(Handler) 또는 스케줄러(Thread) 로 따로 만들지 않았습니다.
즉, “별도 스레드나 타이머 기반 TTL 관리자가 없습니다.”

대신, TTL은 Redis의 싱글 이벤트 루프(eventLoop) 안에 통합되어 동작합니다.
즉, 메인 루프 내부에서 주기적으로 실행되는 "TTL 관리 서브루틴(handler처럼 동작하는 함수)" 형태예요.

⚙️ 핵심 개념 요약
항목 설명
관리 주체 Redis 메인 이벤트 루프 (싱글 스레드)
방식 Active + Passive Expiration (능동 + 수동 병행)
주기 약 100ms 간격으로 일부 샘플링 실행
실행 위치 serverCron() → activeExpireCycle() 내부
데이터 구조 각 DB별 expires 딕셔너리 (hash map: key → expire timestamp)
삭제 동작 삭제 시 dbDelete() 호출 → 메모리 해제 및 AOF/RDB 반영
🔧 TTL이 실제로 만들어지는 과정 (핸들러 수준)

Redis는 키를 생성할 때 TTL을 설정하면 내부적으로 다음 단계를 거칩니다:

1️⃣ 키 삽입 시 만료 시간 등록
setCommand() {
setKey(db, key, value);
if (expire) setExpire(db, key, expire_time);
}

→ setExpire() 함수가 호출되어 db->expires 딕셔너리에
key → expire_timestamp(ms) 로 등록됩니다.

📦 expires는 내부적으로 dict (hash table) 구조입니다.

2️⃣ Passive Expiration (수동 만료)

클라이언트가 키를 읽거나 쓸 때마다 Redis는 자동으로 만료 여부를 체크합니다:

lookupKeyRead() {
if (expireIfNeeded(db, key)) return NULL;
return dictFetchValue(db->dict, key);
}

expireIfNeeded() → getExpire()로 만료시간 가져옴

현재 시간과 비교하여 만료됐으면 dbDelete() 실행

즉, 접근 시점에서 “핸들러”처럼 작동합니다.

🟢 장점: 접근이 자주 일어나는 키는 즉시 정리됨
🔴 단점: 접근이 없는 키는 계속 남아 있음 → Active Expiration 필요

3️⃣ Active Expiration (능동 만료)

이건 Redis의 “핸들러 루프”처럼 작동합니다.
주기적으로 호출되는 serverCron() 함수 내부에서 TTL 관리 루틴이 실행됩니다.

핵심 함수:
void activeExpireCycle(void) {
for (each db in redis) {
sample random keys from db->expires;
check expire time;
if expired -> dbDelete();
}
}

매 루프마다 일정 시간(기본 25ms ~ 100ms) 동안만 수행

모든 키를 훑지 않고 “랜덤 샘플링 기반”으로 일부만 검사

CPU 점유율을 제어하기 위해 time slice 기반으로 제한

📌 이 루틴이 사실상 TTL 핸들러의 역할을 수행합니다.
즉, Redis에는 별도 TTL 쓰레드가 없고, 이 함수가 주기적 “만료 핸들러” 역할을 합니다.

4️⃣ 메모리 해제 및 디스크 반영

키가 삭제되면:

dbDelete()로 메모리에서 제거

만약 AOF가 활성화되어 있다면 AOF_DEL 명령 추가

RDB 스냅숏 시점에는 이미 삭제된 키는 포함되지 않음

즉, TTL은 단순 삭제 이상의 처리 (AOF/RDB 반영까지) 를 거칩니다.

🧮 내부 데이터 구조 요약
구조체 역할
dict dict 실제 데이터 저장 (key → value)
dict
expires TTL 등록된 키들의 만료시간 저장
expire.c TTL 관련 함수 구현 (setExpire, getExpire, expireIfNeeded, activeExpireCycle 등)
serverCron() Redis의 메인 루프 (TTL 검사 루틴 포함)
🕐 TTL 검사 주기

Redis는 TTL 스캔을 한 번에 전부 하지 않습니다.
CPU 사용률을 조절하기 위해 다음처럼 동작합니다:

매 100ms마다 activeExpireCycle() 실행

한 번에 각 DB에서 최대 25% 정도의 TTL 키를 샘플링

만료된 키가 많으면 루프를 추가로 연장 (adaptive cycle)

Redis 7.0 이후에는 내부적으로 “latency guard” 로 지연 감시

이 방식 덕분에 TTL이 수백만 개 있어도 Redis가 멈추지 않습니다.

🧠 요약 정리
항목 설명
TTL 저장 위치 db->expires (dict)
만료 검사 시점 키 접근 시 (Passive), 주기적 샘플링 (Active)
실행 루틴 expireIfNeeded(), activeExpireCycle()
동작 위치 serverCron() 루프 내부
별도 쓰레드 존재 ❌ 없음 (싱글 루프 내에서 처리)
AOF/RDB 반영 삭제 시 자동 반영
복잡도 평균 O(1) (샘플링 기반), 최악 O(n)
🚀 핵심 결론

✅ Redis TTL은 별도의 스레드나 핸들러로 만들어지지 않았습니다.
TTL은 Redis의 메인 이벤트 루프(serverCron) 안에서 동작하는 함수(activeExpireCycle) 로 처리됩니다.

즉, Redis TTL은 “핸들러처럼 동작하는 루틴 함수 구조”이며,
싱글 루프의 100ms 주기 이벤트로 TTL이 만들어지고 관리됩니다.

profile
주니어 풀스택개발자

0개의 댓글