본문 바로가기
개발 · IT/백엔드

Redis TTL & SETEX 완전 정리 — 개념 · 명령어 · 실전 예제

by 플라퉁 2025. 11. 19.
반응형

 

Redis TTL & SETEX 완전 정리 — 개념 · 명령어 · 실전 예제

레디스 썸네일 이미지

Redis에서 만료(Expiration)는 캐시·세션·일회성 토큰 등에서 핵심이죠.

이 글에서는 TTL의 개념, 관련 명령어(EXPIRE, TTL, PTTL, PERSIST 등),

그리고 SETEX와 SET ... EX의 차이와 실제 적용 팁을 예제와 함께 정리합니다.

핵심 요약
  • TTL은 키의 남은 수명(초/밀리초)을 의미. 기본값은 무제한.
  • SETEX key seconds value는 값 설정과 만료를 한 번에(원자적) 처리.
  • EXPIRE / PEXPIRE / EXPIREAT로 기존 키에 만료를 추가/수정할 수 있음.
  • TTL 반환값: -2(키 없음), -1(만료 없음), >=0(남은 초). PTTL은 밀리초 단위.
  • 운영 팁: TTL 랜덤화·캐시 스탬피드 대비·만료 정책(활성/수동) 이해가 중요.

1. TTL(시간대기) 기본 개념

Redis에서 TTL(Time To Live)은 키가 자동으로 삭제되기까지 남은 시간입니다. 기본적으로 새로 생성한 키는 만료가 설정되지 않으면 무한히 유지되죠. 만료가 설정되면 Redis는 키를 삭제 대상으로 관리합니다.

참고: Redis의 만료 삭제는 '지연 삭제(lazy expiration)'와 '능동적 스캔(active expiration)' 조합으로 동작합니다. 즉 즉시 삭제되지 않을 수 있으며, 접근 시 만료를 검사하거나 백그라운드 스캔으로 정리합니다.

2. 관련 명령어 한눈에

  • SETEX key seconds value — 값 설정 + 초 단위 만료(원자적).
  • SET key value EX seconds — SET의 옵션 형태(원자적). (또는 PX ms로 밀리초)
  • EXPIRE key seconds — 기존 키에 초 단위 만료 설정/갱신.
  • PEXPIRE key ms — 밀리초 단위 만료 설정/갱신.
  • EXPIREAT key timestamp / PEXPIREAT key ms-timestamp — 절대 시간으로 만료 설정.
  • TTL key — 남은 시간(초) 반환. 키 없으면 -2, 만료 없으면 -1.
  • PTTL key — 남은 시간(밀리초) 반환.
  • PERSIST key — 만료 제거(영구 키로 만듦).
  • EXISTS key — 키 존재 확인(만료되면 존재하지 않음).

3. TTL/ PTTL 반환값 의미

TTL은 초 단위 정수 또는 다음 특별값을 반환합니다.

  • -2 : 키가 존재하지 않음(이미 만료되었거나 애초에 없음)
  • -1 : 키는 존재하지만 만료(Expiration)이 없음
  • >=0 : 남은 시간(초)

PTTL은 밀리초 단위의 동일한 규칙을 따릅니다.

4. SETEX 과 SET key ... EX의 차이

두 방식은 거의 같은 목적(값 저장 + 만료)으로 쓰입니다만,

중요한 포인트는 둘 다 원자적(atomic)이라는 것 — 한 번의 명령으로 값 저장과 TTL 설정을 수행합니다.

예시(동일 기능):

-- SETEX 방식
SETEX mykey 60 "hello"

-- SET + EX 옵션 방식 (더 유연)
SET mykey "hello" EX 60
SET mykey "hello" PX 1500  -- 밀리초

팁: SET에는 NX/XX 옵션(존재 유무에 따라 설정)과 EX/PX 조합이 가능해서 캐시-스탬프 방지나 분산 락 구현 시 유용합니다. 예: SET key val NX PX 30000.

5. 동작 특성 & 주의사항

  • 키 재설정 시 TTL 변화 — 기존 키에 단순 SET key value로 덮어쓰면 TTL은 제거됩니다. 만료를 유지하려면 SET key value KEEPTTL (Redis 6.0+) 또는 SET ... EX로 다시 설정해야 합니다.
  • EXPIRE가 없는 키는 -1 반환 — 영구 키라는 의미입니다.
  • 만료는 즉시 삭제되지 않을 수 있음 — Redis는 접근 시 만료를 검사(lazy)하고 주기적 스캔(active)으로 청소합니다. 아주 빠르게 대량 만료를 기대하면 설계 고려 필요.
  • EXPIRE는 존재하지 않는 키에 0 반환 — (성공 여부를 0/1로 반환).
  • 정밀도: EXPIRE/TTL은 초 단위, PEXPIRE/PTTL은 밀리초 단위로 정교하게 제어 가능.

6. 실전 예제 — 사용 패턴

(A) 캐시: Cache-Aside 패턴

// pseudocode
value = redis.GET(key)
if value == null then
  value = db.query(...)
  // 300초 TTL로 캐시
  redis.SETEX(key, 300, serialize(value))
end
return value

설명: DB 조회 비용을 줄이려면 적절한 TTL을 정하고, 재생성(캐시 재고갈) 시 TTL을 평균보다 약간 분산(랜덤화)시켜 '캐시 스탬피드'를 완화.

(B) 세션 관리

// express + connect-redis 예시
// 세션은 생성 시 TTL(쿠키 만료)과 함께 저장
store.set(sessionId, sessionData, 'PX', 3600000)  // 1시간

설명: 세션 TTL은 사용자의 활동에 따라 연장(슬라이딩)할지, 고정 만료를 적용할지 정책을 정해야 함.

(C) 일회성 토큰 / 인증 코드

-- 토큰 저장 (10분)
SETEX auth:token:abc123 600 "user:42"
-- 확인 후 즉시 삭제해 재사용 방지
DEL auth:token:abc123

설명: 만료 기능과 즉시 삭제를 함께 사용하면 안전한 일회성 토큰 구현 가능.

(D) 분산 락 (간단 패턴)

// Redis 명령어 (원자적)
SET lock:job1 "" NX PX 30000  -- 30초 락
-- 해제: 안전하게 소유자 확인 후 삭제(스크립트 권장)

주의: 단일 Redis 인스턴스에서 단순 락 가능, 고가용 분산 락은 Redlock 등의 추가 고려 필요.

7. 코드 예제 — Node.js (redis v4 기준)

// npm i redis
const { createClient } = require('redis');
const client = createClient();

await client.connect();

// SETEX 예제
await client.setEx('user:1', 300, JSON.stringify({ id:1, name:'Alice' }));

// SET with EX + NX (only set if not exists)
await client.set('lock:job', 'uuid-1234', { NX: true, PX: 30000 });

// TTL 확인
const ttlSec = await client.ttl('user:1');   // 초
const pttlMs = await client.pTTL('user:1');  // 밀리초

// 만료 제거
await client.persist('user:1');

await client.quit();

설명: Redis v4의 Node 클라이언트는 명령어를 Promise 기반으로 제공하므로 비동기 흐름으로 쉽게 다룰 수 있습니다.

8. 운영·설계 팁 (실무에서 자주 겪는 문제와 해법)

  • 캐시 스탬피드 방지: 동일 키 만료가 한 번에 몰리는 것을 피하려면 TTL에 랜덤 오프셋을 더하세요 (예: base + rand(0..30s)).
  • 과도한 만료 이벤트 주의: 많은 키가 동시에 만료되면 CPU 부하·메모리 반응이 발생할 수 있으니 분산시켜 만료 유도.
  • TTL 길이 결정: 짧은 TTL은 DB 부하를 늘리고 긴 TTL은 캐시 적중률 개선 — 트레이드오프를 측정하세요.
  • 영구 키 덮어쓰기: SET으로 무심코 덮어쓰면 TTL이 상실될 수 있음 — 유지하려면 SET ... KEEPTTL 사용(지원 시) 또는 재설정.
  • AOF/RDB와 TTL: Redis 영속화(AOF/RDB)는 TTL 정보를 함께 저장/복원하므로 재시작 후에도 만료가 유지됩니다(구성에 따라 다름).
  • 모니터링: INFO keyspace, slowlog, 클러스터 상태를 모니터링해 만료 관련 이상 징후(메모리/CPU 스파이크)를 감시하세요.

9. 흔히 하는 실수

  • TTL을 신뢰만 하고 백업을 안 함: 만료로 인해 필요한 데이터가 사라질 수 있으니 중요한 데이터는 별도 영속 저장소에 보관.
  • SET으로 덮어쓰며 TTL 소실: 의도치 않게 만료가 제거되는 경우가 많음.
  • 대량 만료 시 테스트 미흡: 운영에서 대량 만료가 동시 발생하면 부하가 올라갈 수 있으니 스테이징에서 재현 테스트.

마무리 — 언제 TTL을, 어떻게 쓸 것인가?

Redis TTL은 단순하면서도 강력한 도구입니다.

캐시·세션·토큰·락 등 다양한 패턴에 필수적이지만,

만료의 동작 방식(지연 삭제, 주기적 스캔),

원자성(SETEX/SET EX),

재설정 시 TTL 소실 같은 특성을 정확히 이해하고 적용하는 것이 안정적 운영의 핵심입니다.

운영 환경에서는 TTL 랜덤화, 모니터링, 복원 전략을 함께 설계하세요.

마지막으로 Redis 사용시 쓸모없는 데이터가 쌓이지 않는지 확인하세요

이걸 간과하면 어느순간 뻗어있는 레디스를 볼 수 있어요... -- 이게 핵심입니다!!

반응형

댓글