Redis에서 항상 신경써야 하는 부분은 Single Thread로 커맨드가 처리된다는 점입니다. 그렇기 때문에 O(n) 으로 처리되는 커맨드는 항상 주의를 해야하는데요. 대표적으로 keys * , flushall, flushdb, 같은 커맨드가 있습니다. 그 중에서 keys * 은 운영에 큰 영향을 끼치고 장애로 이어질 수 있기 때문에 대부분의 운영 Redis 환경에서는 rename-command 기능으로 막아놓기도 하는데요

얼마전에 한 개발자분으로부터 특정 Key를 조회하고 그 Key를 삭제하고 싶다는 요청을 받았습니다. 저희도 key 커맨드는 막아놨는지라 개발자분이 수행할 수 없는 이슈가 있는데 이럴 때 scan + pattern 커맨드로 우회할 수 있으며 keys 커맨드 사용의 위험도 회피할 수 있습니다. (다만 좀 느립니다)

원래 수행하려 했던 구문

redis-cli -h redis_server -n 0 KEYS "test*" | xargs --delim='\n' redis-cli -h redis_server -n 0 DEL
  • key 커맨드가 막혀있어서 수행 불가능하며
  • test key가 많은 경우 O(n) 으로 동작하여 앞의 keys test* 때문에 다른 커맨드들이 대기하게됨

scan –pattern 우회 구문

redis-cli -h redis_server --scan --pattern 'test*' | xargs redis-cli -h redis_server del
  • scan은 key 대체로 사용가능한 커맨드
  • test* key가 많아도 count 개수 (default 10) 만큼만 가져오기 때문에 다른 커맨드를 막지 않음 O(1) 로 동작
    • count를 너무 크게 잡으면 key 처럼 다른 커맨드 block하게 되므로 주의
  • Redis 4.0 이상일 때 del 대신 unlink 사용 시 더 안전함

key vs scan

  • test data 준비
127.0.0.1:6379> DEBUG POPULATE 10000000 test
OK
(9.20s)
127.0.0.1:6379> dbsize
(integer) 10000000
  • key
### 세션 1
$ redis-cli -h localhost -n 0 KEYS "test*" | xargs --delim='\n' redis-cli -h localhost -n 0 DEL

(integer) 10167
.
.
.

### 세션2
127.0.0.1:6379> set a hi



OK
(4.86s)

=> keys 를 사용하는 세션1 때문에 세션2가 대기함

  • scan
### 세션1
$ redis-cli -h localhost --scan --pattern 'test*' | xargs redis-cli -h localhost del
(integer) 10164
(integer) 10166
(integer) 10170
(integer) 10168
.
.
.


### 세션2
127.0.0.1:6379> set a hi
OK

=> 세션2에서 대기 없이 커맨드 수행 가능