[Redis] 클러스터 구성에서 복수의 키 삭제

Sangboak Lee
6 min readJul 12, 2022

--

복수의 키를 삭제하는 방법

레디스는 DEL/UNLINK 커맨드를 이용해서 복수의 키를 명시적으로 삭제는 할 수 있다. (DEL은 블로킹, UNLINK는 논블로킹)

DEL key1 key2 key3
UNLINK key1 key2 key3

하지만 패턴을 이용한 키의 벌크 딜리트를 지원하지 않는다.

패턴을 이용해서 복수의 키를 삭제하기 위해서는 redis-clixargs를 조합하는 방법이 있다.

아래의 커맨드를 이용하면 users:* 패턴과 일치하는 키를 일괄 삭제 할 수 있다.

redis-cli --scan --pattern users:* | xargs redis-cli unlink

좀 더 세부적으로 들여다보면 다음과 같다.

첫번째 명령어는 패턴에 해당하는 키를 한줄에 하나씩 출력한다.

> redis-cli --scan --pattern users:*
"users:foo"
"users:bar"
"users:baz"

두번째 명령어는 출력된 결과물을 개행 문자열 기준으로 잘라서 인자로 넘기게 된다.

redis-cli unlink users:foo users:bar users:baz

이처럼 두 명령어의 조합으로 패턴에 해당하는 복수의 키를 삭제할 수 있다.

클러스터 환경에서는 외않되?

하지만 위의 스크립트를 클러스터 모드의 레디스를 대상으로 실행하면 아래와 같은 에러를 만나게 된다.

(error) CROSSSLOT Keys in request don't hash to the same slot

요청에 포함된 키들이 같은 slot에 hash 되지 않았다라는 건데…

이는 레디스 클러스터의 데이터 분산을 위해 사용된 Hash Slot이라는 개념때문에 발생하는 문제이다.

복잡한 내용을 간단하게 요약하자면, 레디스 클러스터는 키들이 클러스터의 어느 노드에 저장될 지 정하는 모종의 hashing 알고리즘이 있고

해당 알고리즘으로 인해서 도출된 숫자(슬롯 넘버)에 따라서 각각의 노드에 배정된다.

문제는 이런 분산 환경에서 다른 슬롯, 즉 복수의 노드에 영향을 미치는 작업을 수행할 경우 얘기치 못한 문제가 발생할 수 있다는 것이다.

그렇기 때문에 레디스는 이런 ‘요청에 포함된 키들이 같은 slot에 속하지 않는’ 경우에는 명령의 처리를 거부하는 것이다.

다시 한줄로 요약하면, 다른 슬롯에 속하는 복수의 키를 하나의 명령으로 처리할 수 없다는 이야기다.

방법 1: CLI 조합

문제를 해결하는 방법은 의외로 간단하다. 성능상의 손해를 감수하더라도 하나의 키만 하나의 명령에 전달되도록 위의 스크립트를 변형하면 된다.

redis-cli --scan --pattern users:* | xargs -L 1 redis-cli -c unlink

-L 1 옵션을 넣음으로써 아래의 명령에서 출력된 결과를 한줄씩 잘라서 명령을 실행하게 한다. (참고: https://www.gnu.org/software/findutils/manual/html_node/find_html/xargs-options.html)

> redis-cli --scan --pattern users:*
"users:foo"
"users:bar"
"users:baz"

결과적으로 기존의 명령이 다음과 같이 변형되는 것이다.

xargs redis-cli -c unlink users:foo users:bar users:baz
=>
redis-cli -c unlink users:foo
redis-cli -c unlink users:bar
redis-cli -c unlink users:baz

그런데…우리 레디스에선 안된다! 외않되?!

주의사항) 키에 있는 공백

안되는 원인을 파악하기 위해 xargs 명령에 -t 옵션을 줘보았다. 해당 옵션을 주면 실제로 xargs로 인해서 실제로 어떤 명령이 실행되었는지 보여준다.

redis-cli --scan --pattern users:* | xargs -L 1 -t redis-cli -c unlink
=>
redis-cli -c unlink users::SimpleKey [13,2022-07-08T17:30]
redis-cli -c unlink users::SimpleKey [200,2022-07-18T17:30]
...

출력된 줄을 복사해서 실제로 실행해보면 실패한다. 원인은 키에 포함된 공백으로인해 두개의 키를 받는 것으로 판단하는 것이다.

위의 명령에 아래처럼 “”를 추가하면 명령이 성공한다. Aㅏ…!

redis-cli -c unlink "users::SimpleKey [13,2022-07-08T17:30]"

그러면 xargs로 실행되는 명령에 넘기는 인자를 따옴표로 감싸려면 어떻게 해야하느냐…

redis-cli --scan --pattern users:* | xargs -L 1 -I {} redis-cli -c unlink "{}"
=>
(integer) 1
(integer) 1
(integer) 1
...

아아…삽질 끄읕…!

방법2: 특정 키들을 동일 슬롯(같은 노드)으로 강제하는 방법

Hash tags 기능을 이용하면 복수의 키를 같은 슬롯, 즉 같은 노드에 위치하도록 강제할 수 있다. 그러면 multi key 작업도 같은 노드에 있기 때문에 정상적으로 수행된다.

해당 기능은 키 이름에 {} 를 포함시켜주면 동작하게 된다. {} 안에 있는 문자를 기준으로 해쉬 슬롯을 계산하게 된다.

아래의 키들은 hash tag 없이는 다른 슬롯으로 배정되지만 {} 를 사용함으로써...같은 슬롯에 배정된다.

{users}::SimpleKey [13,2022-07-08T17:30]
{users}::SimpleKey [200,2022-07-18T17:30]

추가로 살펴봐야할 것

  • — pipe 사용으로 성능 개선
  • You do still need to run this against every master node in your cluster. If you have a large number of nodes, it’s probably possible to automate the process further by parsing the output of CLUSTER NODES.

참고

Sign up to discover human stories that deepen your understanding of the world.

--

--

Sangboak Lee
Sangboak Lee

Written by Sangboak Lee

Software engineer at Woowa Bros. Previously worked for Tapjoy

No responses yet

Write a response