11. TTL 만료 메커니즘
- Redis는 키에 TTL(time to live)을 설정해 일정 시간 뒤 자동 삭제할 수 있음
- 캐시 무효화, 세션·토큰 만료, 예약(hold) 자동 반납, rate limit 윈도우 등에 활용
- 핵심: 만료는 즉시가 아니라 근사 — passive + active 두 방식이 협력해 삭제
만료 설정·조회 명령
EXPIRE key seconds / PEXPIRE key ms: 상대 시간 TTL
EXPIREAT key unixtime / PEXPIREAT key ms-unixtime: 절대 시각(Unix timestamp)
SET key val EX 30 / PX 30000: 저장과 동시에 TTL
TTL key(초) / PTTL key(ms): 남은 TTL — 없으면 -1, 키 없으면 -2
PERSIST key: TTL 제거(영속화)
EXPIRETIME / PEXPIRETIME: 만료 시각 자체 조회
조건부 옵션 (7.0+)
NX: 기존 TTL이 없을 때만 설정
XX: 기존 TTL이 있을 때만 설정
GT: 새 TTL이 현재보다 클 때만 (TTL 없는 키는 무한대로 취급)
LT: 새 TTL이 현재보다 작을 때만
두 가지 만료 방식
Passive (lazy) expiration
- 키에 접근하는 순간 만료 여부를 확인 → 만료됐으면 삭제하고 없는 것처럼 응답(null)
- 만료된 키가 클라이언트에 노출되지 않음을 보장
- 단점: 접근하지 않으면 영원히 안 지워짐 → 메모리 점유 (그래서 active가 필요)
Active expiration
- 백그라운드로 주기적으로 만료 키를 수거
- 알고리즘 (기본)
- 초당 10회(100ms마다) 실행
- TTL이 설정된 키 중 무작위 20개를 샘플링
- 그중 만료된 키를 삭제
- 만료된 비율이 25% 초과면 즉시 1번부터 반복, 아니면 다음 주기까지 대기
- 샘플링 방식이라 CPU 사용과 메모리 회수 사이를 균형 — 만료 키가 많으면 더 자주 돈다
만료 정밀도
- 만료 시각은 근사치 — active 주기와 샘플링에 의존해 약간 늦게 지워질 수 있음
- 단, passive 덕분에 만료된 키가 읽히는 일은 없음(논리적으로는 만료 즉시 사라진 것처럼 동작)
- 밀리초 단위의 엄밀한 정시 삭제는 보장하지 않음
복제본(replica)에서의 만료
- replica는 스스로 키를 만료시키지 않음 → master가 보내는
DEL/UNLINK를 기다려 삭제
- 이유: master/replica 간 만료 타이밍이 어긋나면 데이터 불일치 → master를 단일 권위로
- 단, replica도 읽기 시 논리적으로 만료된 키는 숨김(만료된 값을 반환하지 않음)
- 즉 “삭제 권한은 master, 노출 차단은 양쪽”
TTL이 유지/초기화되는 연산
- 유지: 값을 변경하되 교체하지 않는 연산 —
INCR, LPUSH, HSET 등
- 초기화(제거): 키를 통째로 덮어쓰는 연산 —
SET(EX 없이), GETSET, *STORE 등
SET으로 값을 갱신하면 기존 TTL이 사라지는 함정에 주의 → 유지하려면 KEEPTTL 옵션
DEL 후 재생성도 당연히 TTL 없음
- 음수/0 TTL은 즉시 삭제(
del 이벤트, expired 아님)
maxmemory eviction과의 구분
- TTL 만료: 키에 설정된 시간이 지나 삭제 (시간 기반)
- eviction:
maxmemory 한도에 도달해 정책(LRU/LFU 등)에 따라 키를 강제 축출 (메모리 기반)
- 둘은 별개 — TTL 없는 키도 eviction 대상이 될 수 있고(
allkeys-*), 메모리 여유가 있어도 TTL은 만료됨
만료 이벤트 (keyspace notification)
- 키 만료 시
__keyevent@<db>__:expired 채널로 알림 발행 가능 (notify-keyspace-events 설정)
- 주의: 이벤트는 실제 삭제 시점(passive 접근 또는 active 수거)에 발행 → TTL이 끝난 정시가 아니라 약간 지연될 수 있음
- “만료 즉시 정확한 트리거”를 기대하면 안 됨
참고