Redis 키스페이스 이해: 삭제 및 검사 명령어
Redis 키스페이스 관리의 강력한 기능을 종합 가이드로 알아보세요. `SCAN`을 사용하여 데이터를 안전하게 검사하고(프로덕션에서 `KEYS`를 피해야 하는 이유 포함) `DEL`과 비차단 `UNLINK`를 사용하여 효율적으로 키를 삭제하는 방법을 배웁니다. `FLUSHDB`와 `FLUSHALL`의 파괴적인 특성을 이해하고 건강하고 고성능인 Redis 인스턴스를 유지하기 위한 모범 사례를 알아보세요.
Redis 키스페이스 이해: 삭제 및 검사 명령어
Redis 키스페이스는 현재 선택된 데이터베이스에 있는 키의 집합일 뿐이지만, 이러한 키를 검사하고 삭제하는 방식에 따라 정리가 지루해질지, 아니면 트래픽 중간에 애플리케이션이 중단될지가 결정됩니다.
대부분의 팀은 어려운 방법으로 이를 배웁니다. 누군가 스테이징 캐시에서 session:* 키를 삭제해야 해서 KEYS session:*를 실행하고 목록을 확인한 다음, 같은 습관을 프로덕션에서 시도합니다. 작은 데이터베이스에서는 괜찮게 느껴집니다. 수백만 개의 키가 있는 바쁜 인스턴스에서는 명령어가 서버를 충분히 오래 잡아서 관련 없는 요청이 뒤에서 대기하게 할 수 있습니다. Redis는 명령어를 매우 빠르게 처리하지만, 전체 키스페이스를 탐색하는 명령어는 여전히 작업을 수행해야 합니다.
일상적인 작업의 경우 두 가지 별도 단계로 생각하세요: 안전하게 키를 찾은 다음 안전하게 삭제합니다. 키 검사를 무해한 읽기로 취급하지 마세요. 읽기 명령어도 비용이 많이 들 수 있습니다.
실제로 사용 중인 데이터베이스부터 시작하세요
무언가를 삭제하기 전에 엔드포인트와 논리적 데이터베이스를 확인하세요.
redis-cli -h redis.example.internal -p 6379 INFO keyspace
출력은 다음과 같습니다:
# Keyspace
db0:keys=154233,expires=129900,avg_ttl=2851412
db2:keys=32,expires=32,avg_ttl=60000
이것은 어떤 논리적 데이터베이스에 키가 포함되어 있는지 알려줍니다. 많은 Redis 배포는 데이터베이스 0만 사용합니다. Redis Cluster는 데이터베이스 0만 지원하므로, FLUSHDB와 FLUSHALL은 일반적인 "선택된 데이터베이스" 개념이 같은 방식으로 유용하지 않기 때문에 특별히 주의해야 합니다.
애플리케이션이 독립 실행형 Redis에서 번호가 매겨진 데이터베이스를 사용하는 경우 올바른 데이터베이스를 명시적으로 선택하세요:
redis-cli -n 2 DBSIZE
DBSIZE는 선택된 데이터베이스의 키 수를 반환합니다. 이름을 표시하지 않으며 검사 과정을 대체하지 않지만, 정리 전후에 좋은 상태 확인입니다.
키스페이스가 작고 폐기 가능할 때만 KEYS 사용
KEYS pattern은 글로브 스타일 패턴과 일치하는 모든 키를 반환합니다:
KEYS user:*
KEYS cache:product:???
KEYS *
패턴 규칙은 편리합니다: *는 모든 시퀀스와 일치하고, ?는 한 문자와 일치하며, [0-9]와 같은 대괄호 범위는 범위의 한 문자와 일치합니다.
문제는 정확성이 아닙니다. 문제는 KEYS가 하나의 명령어로 전체 키스페이스를 스캔한다는 것입니다. 수백 개의 키가 있는 로컬 개발 Redis에서는 편리합니다. 공유 캐시에서는 Redis가 결과를 생성하는 동안 다른 모든 클라이언트에 지연 시간을 추가할 수 있습니다. 이 명령어는 선형 복잡성을 가진 키스페이스 명령어로 문서화되어 있으므로 정상적인 프로덕션 정리 스크립트의 일부가 되어서는 안 됩니다.
저는 여전히 두 곳에서 KEYS를 사용합니다:
- 테스트를 작성하는 동안 폐기 가능한 로컬 Redis.
- 이미
DBSIZE를 확인했고 명령어가 나를 놀라게 할 수 없다는 것을 알고 있는 작은 스테이징 데이터베이스.
다른 모든 곳에서는 SCAN을 사용하세요.
프로덕션 검사에는 SCAN 사용
SCAN은 커서 기반입니다:
SCAN 0 MATCH user:* COUNT 100
Redis는 두 가지를 반환합니다: 다음 커서와 키 배치. 커서 0에서 시작하세요. 반환된 커서로 계속 스캔하세요. Redis가 다시 커서 0을 반환하면 중지하세요.
1) "24576"
2) 1) "user:100"
2) "user:101"
COUNT는 힌트이지 약속이 아닙니다. Redis는 주어진 반복에 대해 더 많은 키, 더 적은 키 또는 키가 전혀 없을 수도 있습니다. MATCH는 반환되는 것을 필터링하지만 Redis는 여전히 키스페이스를 진행합니다. 좁은 패턴은 클라이언트 측 작업을 줄이는 데 유용하지만 모든 스캔을 무료로 만드는 것은 아닙니다.
셸 작업의 경우 커서 루프를 숨기기 때문에 redis-cli --scan을 선호하세요:
redis-cli --scan --pattern 'session:*'
모든 키를 출력하지 않고 일치하는 키를 계산하려면:
redis-cli --scan --pattern 'session:*' | wc -l
삭제하기 전에 유형을 검사하려면:
redis-cli --scan --pattern 'session:*' | head
redis-cli TYPE session:abc123
redis-cli TTL session:abc123
redis-cli MEMORY USAGE session:abc123
TTL은 정리 결정에 특히 유용합니다. 캐시 네임스페이스에 이미 합리적인 만료 시간이 있는 경우 대량 삭제가 전혀 필요하지 않을 수 있습니다. 키가 자연스럽게 만료되도록 두는 것이 일반적으로 업무 시간 중에 큰 삭제를 강제하는 것보다 덜 위험합니다.
알려진 키를 DEL로 삭제
DEL은 하나 이상의 키를 제거하고 존재했던 키 수를 반환합니다:
DEL session:abc123
DEL session:abc123 session:def456 session:ghi789
작은 키의 경우 DEL은 일반적으로 괜찮습니다. 문자열 키나 작은 해시를 삭제하는 것은 무서운 경우가 아닙니다. 아픈 경우는 큰 집계 값을 삭제하는 경우입니다. 예를 들어, 많은 수의 요소를 가진 리스트, 인덱스로 사용되는 세트, 원래 목적을 훨씬 넘어 성장한 해시 등이 있습니다. Redis는 키스페이스에서 키를 제거하지만 큰 값을 해제하는 것은 메인 경로에서 시간이 걸릴 수 있습니다.
작은 키를 알고 있는 하나의 키를 삭제하는 경우 DEL을 사용하세요. 많은 키를 삭제하거나 키가 얼마나 큰지 확실하지 않은 경우 UNLINK를 사용하세요.
대량 또는 대량 삭제에는 UNLINK 선호
UNLINK는 DEL과 같은 형태를 가집니다:
UNLINK session:abc123
UNLINK cache:old:1 cache:old:2 cache:old:3
중요한 차이점은 메모리 회수입니다. UNLINK는 키스페이스에서 키를 즉시 제거한 다음 비동기적으로 메모리를 해제합니다. 이는 큰 값을 가질 수 있는 키를 정리할 때 더 안전한 기본값이 됩니다.
이것이 UNLINK가 마법이라는 것을 의미하지는 않습니다. 스크립트가 가능한 한 빨리 수백만 개의 키를 발견하고 연결 해제하면 여전히 압력을 생성할 수 있습니다. Redis는 여전히 명령어를 처리해야 하고, 복제본은 여전히 변경 사항을 수신해야 하며, 메모리는 여전히 회수되어야 합니다. 실행 중에 지연 시간과 메모리를 관찰할 수 있도록 대량 정리를 조절하세요.
실용적인 정리 루프는 다음과 같습니다:
redis-cli --scan --pattern 'session:*' |
xargs -r -L 100 redis-cli UNLINK
이것은 100개 키 배치로 삭제합니다. 환경에 맞게 배치 크기를 조정하세요. 조용한 유지 관리 창에서는 더 큰 배치를 사용할 수 있습니다. 사용자 대면 트래픽이 공유하는 핫 캐시에서는 더 작은 배치와 배치 사이에 짧은 절전이 더 나을 수 있습니다:
redis-cli --scan --pattern 'session:*' |
while read -r key; do
redis-cli UNLINK "$key" >/dev/null
sleep 0.005
done
이 버전은 더 느리지만 중지하기 쉽고 추론하기 쉽습니다.
패턴 삭제에 주의
Redis는 의도적으로 DEL user:*를 제공하지 않습니다. 스캔과 삭제를 직접 결합해야 합니다. 이 마찰은 패턴 삭제가 사고가 발생하는 곳이기 때문에 유용합니다.
삭제하기 전에:
redis-cli --scan --pattern 'user:*' | head -50
redis-cli --scan --pattern 'user:*' | wc -l
첫 번째 샘플을 살펴보세요. 대상 크기를 계산하세요. 예상 정리가 "몇 천 개의 버려진 세션"이었는데 개수가 "데이터베이스의 대부분"이라면 중지하고 패턴을 수정하세요.
정리를 지루하게 만드는 명명 규칙을 사용하세요:
app:prod:session:<id>
app:prod:rate-limit:<user-id>
app:prod:cache:product:<id>
이것은 session:<id>보다 더 장황하지만 네임스페이스를 정확하게 대상으로 지정할 수 있습니다. Redis Cluster에서 키 이름에는 슬롯 배치를 위한 cart:{user123}:items와 같은 해시 태그가 포함될 수도 있습니다. 광범위한 패턴을 작성하기 전에 이러한 규칙을 알고 있어야 합니다.
FLUSHDB와 FLUSHALL은 재설정 버튼
FLUSHDB는 선택된 데이터베이스에서 모든 키를 제거합니다:
FLUSHDB
FLUSHDB ASYNC
FLUSHALL은 모든 논리적 데이터베이스에서 모든 키를 제거합니다:
FLUSHALL
FLUSHALL ASYNC
최신 Redis는 플러시 명령어에 대해 ASYNC 및 SYNC 수정자를 지원합니다. ASYNC는 백그라운드에서 해제를 예약하여 큰 동기 메모리 해제 일시 중지를 방지하는 데 도움이 됩니다. 작업을 되돌릴 수 있게 만들지는 않습니다. 키가 키스페이스에서 사라지면 애플리케이션은 사라진 것으로 봅니다.
두 명령어 중 하나를 사용하기 전에 세 가지 확인을 원합니다:
redis-cli ROLE
redis-cli INFO keyspace
redis-cli CONFIG GET dir
ROLE은 프라이머리 또는 복제본에 연결되어 있는지 확인하는 데 도움이 됩니다. INFO keyspace는 영향을 받을 내용을 보여줍니다. CONFIG GET dir은 종종 어떤 인스턴스에 있는지에 대한 또 다른 힌트를 제공합니다. 데이터 디렉토리는 환경별 경로를 포함하는 경향이 있기 때문입니다.
개발 재설정 스크립트의 경우 명시적으로 작성하세요:
redis-cli -h 127.0.0.1 -p 6379 -n 0 FLUSHDB ASYNC
기본값으로 redis-cli FLUSHALL을 실행하는 스크립트는 피하세요. 기본값은 스크립트가 다른 호스트, 다른 컨테이너 또는 다른 환경 변수를 가진 CI 실행기에서 실행될 때 변경됩니다.
삭제 후 확인
정리 후 개수와 애플리케이션 동작을 모두 확인하세요:
redis-cli --scan --pattern 'session:*' | wc -l
redis-cli INFO memory
redis-cli INFO stats | grep expired_keys
UNLINK 또는 비동기 플러시 후 메모리는 즉시 떨어지지 않을 수 있습니다. 해제가 백그라운드에서 발생하고 할당자가 재사용을 위해 메모리를 예약할 수 있기 때문입니다. 이것이 자동으로 누수는 아닙니다. used_memory, 지연 시간 및 키 개수가 예상한 방향으로 이동하는지 관찰하세요.
프로덕션 변경의 경우 실행하기 전에 정확한 명령어와 패턴을 기록해 두세요. 안전한 Redis 정리는 올바른 명령어만이 아닙니다. 올바른 명령어, 올바른 인스턴스, 샘플링한 패턴, 결과를 관찰할 수 있는 시간대에 실행하는 것입니다.
더 안전한 프로덕션 정리 실행 절차
실제 정리의 경우 명령어를 기억에서 입력하는 한 줄 명령어 대신 작은 실행 절차로 전환하는 것을 좋아합니다. 실행 절차는 화려할 필요가 없습니다. 어떤 인스턴스, 어떤 패턴, 몇 개의 키, 얼마나 빠른지의 네 가지 질문에 답해야 합니다.
읽기 전용 확인으로 시작하세요:
redis-cli -h redis.example.internal -p 6379 ROLE
redis-cli -h redis.example.internal -p 6379 INFO keyspace
redis-cli -h redis.example.internal -p 6379 --scan --pattern 'app:prod:session:*' | head -20
redis-cli -h redis.example.internal -p 6379 --scan --pattern 'app:prod:session:*' | wc -l
그런 다음 몇 가지 대표 키를 검사하세요:
redis-cli TYPE app:prod:session:sample
redis-cli TTL app:prod:session:sample
redis-cli MEMORY USAGE app:prod:session:sample
샘플이 몇 분 안에 자연스럽게 만료되어야 하는 키를 보여주면 삭제하는 대신 기다리세요. 키에 TTL이 없고 분명히 버려진 데이터에 속하는 경우 조절된 정리를 진행하세요. 지연 시간 또는 메모리가 있는 터미널을 열어 두세요:
redis-cli --latency
redis-cli INFO memory
공유 프로덕션 Redis의 경우 의도를 잃지 않고 중지할 수 있는 스크립트를 선호합니다:
redis-cli --scan --pattern 'app:prod:session:*' |
while read -r key; do
redis-cli UNLINK "$key" >/dev/null
sleep 0.002
done
이것은 가장 빠른 버전이 아닙니다. 지연 시간이 이동하거나, 클라이언트가 불평하거나, 패턴이 예상보다 광범위한 경우 알아차릴 기회를 제공하는 버전입니다. 인스턴스가 조용하고 개수가 적당할 때 xargs -L 100으로 배치 처리하는 것이 괜찮습니다. 요점은 의도적으로 속도를 선택하는 것입니다.
한 가지 더 습관이 도움이 됩니다: 사고 티켓이나 배포 노트에 전후 개수를 저장하세요. "세션 키 삭제됨"만으로는 충분하지 않습니다. "redis-cache-01의 db0에서 app:prod:session:*와 일치하는 48,213개 키를 UNLINK를 사용하여 삭제, 지연 시간 증가 관찰되지 않음"은 나중에 시간을 절약해 주는 종류의 노트입니다.