Redis 키가 만료되지 않을 때: TTL이 안 먹는 흔한 원인
Dev
마지막 업데이트

Redis 키가 만료되지 않을 때: TTL이 안 먹는 흔한 원인


Redis 키가 만료되지 않을 때는 Redis가 TTL을 “잊어버린” 경우보다, 애플리케이션이 키를 다시 쓰거나 EXPIRE를 빼먹거나, 원래 volatile이어야 할 키를 영구 키처럼 만들어버리는 경우가 더 많습니다.

이 글은 가장 빠른 점검 순서에 집중합니다. 실제 키에 TTL이 남아 있는지 확인하고, 어떤 쓰기 경로가 TTL을 지워버리는지 먼저 좁혀 봅니다.


먼저 무엇부터 확인할까

애플리케이션 코드보다 실제 키 상태부터 보는 편이 빠릅니다.

먼저:

TTL your:key

필요하면:

PTTL your:key

TTL이 -1이면 키는 존재하지만 만료 시간이 없습니다. TTL이 -2면 키가 이미 사라진 상태입니다.

이 차이를 먼저 구분해야 “만료가 안 된다”와 “이미 없어졌다”를 헷갈리지 않습니다.


가장 흔한 원인: 키를 다시 써버림

Redis 문서에 따르면 키를 덮어쓰는 명령은 timeout을 지웁니다. 대표적으로 SETGETSET 같은 명령이 그렇습니다.

실무에서는 이런 흐름이 자주 나옵니다.

  1. 애플리케이션이 키를 만든다
  2. EXPIRE로 TTL을 설정한다
  3. 다른 경로에서 SET으로 키를 다시 쓴다
  4. TTL이 사라진다

TTL이 갑자기 -1로 바뀐다면 이 패턴을 가장 먼저 의심하는 편이 좋습니다.


EXPIRE가 실제로 성공하는지 보기

EXPIRE는 성공하면 1, 실패하면 0을 반환합니다.

그래서 가장 단순한 확인 순서는:

SET mykey value
EXPIRE mykey 60
TTL mykey

입니다.

애플리케이션이 EXPIRE 반환값을 보지 않으면 XXNX 같은 조건 옵션 때문에 TTL이 실제로는 붙지 않았는데도 지나치기 쉽습니다.


조건부 만료 옵션도 같이 보기

Redis는 EXPIRENX, XX, GT, LT 옵션을 지원합니다.

이 옵션들은 유용하지만 디버깅 함정도 만듭니다.

  • XX는 기존 expiry가 있을 때만 설정
  • NX는 expiry가 없을 때만 설정
  • GT는 새 TTL이 더 클 때만 설정
  • LT는 새 TTL이 더 작을 때만 설정

팀에서 한 번 넣고 잊어버리면, 코드가 맞아 보여도 TTL이 갱신되지 않는 상황이 생길 수 있습니다.


실제 write 경로가 하나인지 보기

TTL 버그는 writer가 하나가 아닐 때 자주 생깁니다.

예를 들면:

  • 요청 핸들러는 TTL을 올바르게 붙인다
  • 백그라운드 작업이 같은 키를 만료 없이 다시 쓴다
  • 캐시 워머가 값만 갱신하고 TTL은 빼먹는다
  • 세션 갱신 로직이 TTL이 항상 유지된다고 가정한다

이 문제가 메모리 증가와 함께 보인다면 Redis 메모리 사용량이 높을 때도 같이 보세요. 반대로 키 소실과 정책 문제가 같이 보인다면 Redis eviction policy 가이드도 도움이 됩니다.


가장 단순한 재현 테스트 해보기

애플리케이션 전체를 보기 전에, 정확한 명령 순서를 그대로 재현해 보면 빠릅니다.

예:

SET mykey value
EXPIRE mykey 30
TTL mykey
SET mykey newvalue
TTL mykey

두 번째 TTL이 -1이 된다면 Redis가 이상한 것이 아니라 문서대로 동작하는 것입니다. 이 경우 문제는 Redis 서버가 아니라 애플리케이션 write 패턴입니다.


더 안전한 패턴

값과 만료 시간이 항상 함께 붙어야 한다면, 한 명령에서 같이 설정하는 편이 낫습니다.

문자열 키라면:

SET mykey value EX 60

같은 패턴이 더 안전합니다.


빠른 체크리스트

  • TTL이 -1, -2, 양수 중 무엇인지 확인
  • 키를 쓰는 모든 코드 경로 찾기
  • SET 같은 overwrite 명령이 EXPIRE 뒤에 오는지 확인
  • EXPIRENX, XX, GT, LT가 붙어 있는지 확인
  • Redis에서 직접 명령 순서를 재현

대부분 애플리케이션 쪽 패턴으로 모이면, Redis 스케줄러 버그가 아니라 write-path 버그로 보는 편이 맞습니다.


증상별 진입 힌트

  • cache나 session key가 만료돼야 하는데 오래 남아 있으면 여기부터 보면 됩니다.
  • 처음 보이는 증상이 memory growth라면 memory 글도 같이 보는 편이 좋습니다.

바로 확인할 명령어

redis-cli TTL your:key
redis-cli PTTL your:key
redis-cli OBJECT idletime your:key

이 명령어로 expiration 유무, 만료까지 남은 시간, 키가 계속 다시 touch되고 있는지를 나눠서 볼 수 있습니다.

TTL이 -1인지, overwrite 때문에 TTL이 계속 사라지는지, idle time이 늘지 않아 다른 writer가 계속 key를 덮는지 보세요.


FAQ

Q. TTL-1이면 무슨 뜻인가요?

키는 존재하지만 현재 만료 시간이 없다는 뜻입니다.

Q. SET을 하면 기존 TTL이 유지되나요?

보통은 아닙니다. Redis 문서에 따르면 덮어쓰는 명령은 timeout을 지웁니다.

Q. 만료 키를 더 안전하게 만드는 방법은 무엇인가요?

가능하면 값과 TTL을 한 명령에서 같이 쓰는 편이 좋습니다.


Sources:

먼저 읽어볼 가이드

검색 유입이 많은 핵심 글부터 이어서 보세요.