处理 TTL 与过期策略
한국어 원문으로 표시합니다.
목표
TTL 의 동작을 정확히 이해하고, TTL 이 조용히 사라지는 함정을 재현해 막고, 축출 정책의 차이를 실제 축출로 확인한다.
왜 중요한가
"Redis 메모리가 계속 자라는데 원인을 모르겠다"는 문의의 대부분은 TTL 을 안 건 키입니다. 그리고 그것이 눈에 안 띄는 이유는 코드가 SETEX 를 잘 쓰고 있는데도 어딘가에서 SET 으로 값만 갱신하면서 원래 있던 수명을 날려 버리기 때문입니다. 이 실습의 3번 스텝이 정확히 그 장면입니다. 또 하나 몸에 남겨야 할 것은 만료가 즉시가 아니라는 사실입니다. Redis 는 접근할 때 지우거나 백그라운드에서 표본을 뽑아 지웁니다. 그래서 만료 시각이 지난 키가 DBSIZE 에 남아 있을 수 있고, "만료됐는데 왜 메모리가 안 줄지"의 답이 여기 있습니다. 마지막 감사 스크립트는 운영에 그대로 가져가 쓸 수 있는 물건입니다.
단계
cache:a를 값과 함께 60초 수명으로 넣고/root/ttl/ttl1.txt에ttl=<남은초>를 적는다. 값은 1 이상 60 이하이다.cache:a의 TTL 을 제거한다./root/ttl/ttl2.txt에ttl=-1이 적혀야 한다.cache:b를 60초 수명으로 넣은 뒤SET cache:b <새값>으로 값만 갱신한다. TTL 이 -1 이 되는 것을/root/ttl/lost.txt에 기록하고,KEEPTTL로 다시 시도한 결과를/root/ttl/kept.txt에ttl=<양수>로 적는다.cache:c를 1초 수명으로 넣고 2초 기다린 뒤, 접근하지 않은 상태의DBSIZE와 접근 후의DBSIZE를/root/ttl/lazy.txt에before=<n> after=<n>으로 적는다.maxmemory-policy를allkeys-lfu로 설정한다./root/ttl/policy.txt에maxmemory-policy allkeys-lfu가 들어가야 한다.maxmemory를 8mb 로 낮추고/root/ttl/fill.py로 키를 충분히 넣어 축출을 일으킨다./root/ttl/evicted.txt에evicted_keys=<n>을 적고 n 은 0보다 커야 한다./root/ttl/audit.sh로SCAN순회하며 TTL 이 -1 인 키를/root/ttl/nottl.txt에 적는다. 스크립트에KEYS문자열이 있으면 안 되고, 결과 파일에 최소 1개의 키가 있어야 한다.
참고
- 수명 조회:
TTL key— -1 은 만료 없음, -2 는 키 없음입니다. - TTL 유지 갱신:
SET key val KEEPTTL - 축출 통계:
redis-cli INFO stats | grep evicted_keys - TTL 지터:
ttl = base + random(-spread, +spread)로 동시 만료를 흩뜨립니다. - 흔한 실수:
volatile-lru정책에서 캐시 키에 TTL 을 빠뜨리는 것 — 그 키는 영원히 축출되지 않습니다.
TTL 걸고 남은 수명 확인하기
cache:a 를 값과 함께 60초 수명으로 넣고 /root/ttl/ttl1.txt 에 ttl=<남은초> 를 적는다. 값은 1 이상 60 이하이다.
수명을 함께 지정해 넣는 명령도 있고, 이미 있는 키에 거는 명령도 있습니다. 남은 수명을 조회해 보세요.
TTL 제거해 영구 키로 만들기
cache:a 의 TTL 을 제거한다. /root/ttl/ttl2.txt 에 ttl=-1 이 적혀야 한다.
TTL 이 없는 키의 조회 결과는 -1 입니다. -2 는 다른 뜻이니 주의하세요.
SET 이 TTL 을 날리는 함정 재현하고 막기
cache:b 를 60초 수명으로 넣은 뒤 SET cache:b <새값> 으로 값만 갱신한다. TTL 이 -1 이 되는 것을 /root/ttl/lost.txt 에 기록하고, KEEPTTL 로 다시 시도한 결과를 /root/ttl/kept.txt 에 ttl=<양수> 로 적는다.
값만 갱신했는데 수명이 사라집니다. 수명을 유지하는 옵션이 있습니다.
만료가 즉시 메모리 반환이 아님을 관찰하기
cache:c 를 1초 수명으로 넣고 2초 기다린 뒤, 접근하지 않은 상태의 DBSIZE 와 접근 후의 DBSIZE 를 /root/ttl/lazy.txt 에 before=<n> after=<n> 으로 적는다.
만료 시각이 지났는데 아무도 접근 안 한 키는 한동안 남아 있습니다. 조회 전후로 개수를 비교해 보세요.
축출 정책 설정하기
maxmemory-policy 를 allkeys-lfu 로 설정한다. /root/ttl/policy.txt 에 maxmemory-policy allkeys-lfu 가 들어가야 한다.
기본값은 캐시 용도에 맞지 않습니다. 캐시 전용이라면 어떤 정책이 좋을지 읽기 자료를 참고하세요.
실제로 축출이 일어나게 만들기
maxmemory 를 8mb 로 낮추고 /root/ttl/fill.py 로 키를 충분히 넣어 축출을 일으킨다. /root/ttl/evicted.txt 에 evicted_keys=<n> 을 적고 n 은 0보다 커야 한다.
메모리 한도를 작게 잡고 키를 많이 넣으면 됩니다. 축출 통계는 INFO 에 있습니다.
TTL 없는 키 감사 스크립트 만들기
/root/ttl/audit.sh 로 SCAN 순회하며 TTL 이 -1 인 키를 /root/ttl/nottl.txt 에 적는다. 스크립트에 KEYS 문자열이 있으면 안 되고, 결과 파일에 최소 1개의 키가 있어야 한다.
SCAN 으로 순회하며 남은 수명이 -1 인 키를 모읍니다. 운영에서 주기적으로 돌릴 수 있는 형태여야 합니다.