[번역] Redis Keyspace Notifications

ma2sql·2020년 11월 22일
1

Redis Keyspace Notifications

원문: https://redis.io/topics/notifications

IMPORTANT Keyspace notifications is a feature available since 2.8.0

Feature overview

키 스페이스 노티피케이션(Keyspace notifications)은 클라이언트가 레디스의 데이터 셋이 어떠한 형태로 영향을 받은 이벤트를 수신하기 위해서 Pub/Sub 채널을 구독하게 하는 것이다.

수신할 수 있는 이벤트의 예는 다음과 같다.

  • 주어진 키에 대해 영향이 있었던 모든 커맨드
  • LPUSH 오퍼레이션이르 수신하는 모든 키
  • 데이터베이스 0내의 만료중인 모든 키

이벤트는 레디스의 일반적인 Pub/Sub 계층을 이용해서 전달되며, 그렇기 때문에 Pub/Sub을 구현하는 클라이언트는 변경없이 이 기능을 이용하는 것이 가능하다.

레디스 Pub/Sub은 fire and forget이기 때문에, 만약 당신의 어플리케이션이 이벤트에 대한 신뢰할 수 있는 통지(reliable notification)에 대한 요구가 있다면, 현재는 이 기능을 이용할 방법이 없을 것이다. 당신의 Pub/Sub 클라이언트가 한 번 연결을 끊고 나서 다시 연결을 맺을 때, 클라이언트는 접속이 끊겼던 시간 동안에 전달된 모든 이벤트들을 잃게 된다.

향후에는 좀 더 신뢰할 수 있는 이벤트의 딜리버리가 가능하도록 하려는 계획이 있지만, 아마도 이것은 좀 더 일반적인 수준으로 다루어질 것이다. Pub/Sub 그 자체가 신뢰성을 갖게 되는 것이나, 또는 루아(Lua) 스크립트가 Pub/Sub 이벤트를 리스트로 푸시하는 것과 같은 오퍼레이션을 수행하기 위해 Pub/Sub 메시지를 가로챌 수 있도록 하는 것 등이다.

Type of events

키 스페이스 노티피케이션은 레디스 데이터 스페이스에 영향을 주는 모든 오퍼레이션마다 두 가지의 구별되는 형태의 이벤트를 보냄으로써 구현된다. 예를 들어, 데이터베이스 0 안에 있는 mykey라고 이름이 붙여진 키에 대한 DEL 오퍼레이션은 두 가지 메시지를 발생시킬 것이고, 이는 다음의 두 PUBLISH 커맨드와 정확히 동일하다.

PUBLISH __keyspace@0__:mykey del
PUBLISH __keyevent@0__:del mykey

어떻게 우리는 한 채널로부터 mykey에 대한 이벤트를 모두 수신할 수 있는지, 그리고 어떻게 또 다른 채널로부터 del 오퍼레이션의 대상이 되는 모든 키에 대한 정보를 얻을 수 있는지를 쉽게 알 수 있을 것이다.

채널 내에서 keyspace 프리픽스를 가진 첫 번째 종류의 이벤트는 키-스페이스 노티피케이션 (key-space notification) 이라고 부른다. 반면에 keyevent 프리픽스를 가진 두 번째 종류의 이벤트는 키-이벤트 노티피케이션 (key-event notification) 이라고 부른다.

위의 예에서, del 이벤트는 mykey에 대해서 발생되었는데, 이에 대해 일어난 일은 다음과 같다.

  • Key-space 채널은 이벤트의 이름을 메시지로 수신한다.
  • Key-event 채널은 키의 이름을 메시지로 수신한다.

우리가 관심이 있는 이벤트의 일부만을 전달받기 위해, 오직 하나의 종류의 노티피케이션만 활성화하는 것이 가능하다.

Configuration

기본적으로 키 스페이스 이벤트 노티피케이션은 비활성화되어 있는데, 이 기능은 눈에 띌 만큼은 아니지만 CPU 자원을 일부 사용하기 때문이다. 노티피케이션은 redis.conf의 notify-keyspace-events 옵션을 사용하거나 CONFIG SET을 통해서 활성화될 수 있다.

이 파라미터를 빈 문자열로 설정하는 것은 노티피케이션을 비활성화한다. 이 기능을 활성화하기 위해서 비어있지 않은 문자열이 사용되는데, 이 문자열은 여러 문자들로 구성되며, 모든 문자들은 다음의 테이블에 따라 특별한 의미를 가진다:

K     Keyspace events, published with __keyspace@<db>__ prefix.
E     Keyevent events, published with __keyevent@<db>__ prefix.
g     Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ...
$     String commands
l     List commands
s     Set commands
h     Hash commands
z     Sorted set commands
t     Stream commands
x     Expired events (events generated every time a key expires)
e     Evicted events (events generated when a key is evicted for maxmemory)
A     Alias for g$lshztxe, so that the "AKE" string means all the events.

최소한 KE는 문자열에 지정해야하며, 그렇지 않으면 나머지 문자열에 관계없이 어떠한 이벤트도 전달되지 않는다.

예를 들어, 그저 LIST에 대해서만 키 스페이스 이벤트를 활성화하려면, 설정 값은 Kl등으로 지정해야만 한다.

KEA는 가능한 모든 이벤트를 활성화시키기 위해서 사용될 수 있다.

Events generated by different commands

각각의 커맨드는 다음의 목록에 따라 각기 다른 종류의 이벤트를 발생시킨다.

  • DEL은 모든 삭제되는 키에 대해서 del 이벤트를 발생시킨다.
  • RENAME은 두 가지 이벤트를 발생시키는데, 하나는 원본 키에 대한 rename_from이벤트이고, 다른 하나는 대상 키에 대한 rename_to이벤트이다.
  • EXPIRE는 키에 대해서 만료 시간(expire)가 설정될 때 expire이벤트를 발생시킨거나, 키에 타임아웃이 설정되고, 그 결과로 키가 삭제될 때마다 expired 이벤트가 발생하게 된다. (좀 더 많은 정보는 EXPIRE 문서를 참고할 것).
  • SORT는 새로운 키에 저장하기 위해 STORE 옵션이 사용될 때, sortstore 아벤트가 발생시킨다. 만약, 정렬한 결과 리스트가 비어있고, STORE 옵션이 사용된다면, 그리고 저장하려는 키가 이미 존재한다면, 그 키는 삭제될 것이고, 따라서 이 조건에서는 del 이벤트가 발생한다.
  • SET과 그리고 이와 비슷한 커맨드들(SETEX, SETNX,GETSET)은 set 이벤트를 발생시킨다. 그리고 SETEXexpire 이벤트 또한 발생시킨다.
  • MSET은 각각의 키별로 set 이벤트를 발생시킨다.
  • SETRANGEsetrange 이벤트를 발생시킨다.
  • INCR, DECR, INCRBY, DECRBY 커맨드들은 모두 incrby 이벤트를 발생시킨다.
  • INCRBYFLOATincrbyfloat 이벤트를 발생시킨다.
  • APPENDappend 이벤트를 발생시킨다.
  • LPUSHLPUSHX는 단일 lpush 이벤트를 발생시키는데, 가변적인 인자에 대해서도 마찬가지이다.
  • LPUSHLPUSHX는 단일 rpush 이벤트를 발생시키는데, 가변적인 인자에 대해서도 마찬가지이다.
  • RPOPrpop이벤트를 발생시키다. 만약 리스트 내의 마지막 엘리먼트가 pop되는 경우에는, 추가적으로 del 이벤트가 발생된다.
  • LPOPlpop이벤트를 발생시키다. 만약 리스트 내의 마지막 엘리먼트가 pop되는 경우에는, 추가적으로 del 이벤트가 발생된다.
  • LINSERTlinsert 이벤트를 발생시킨다.
  • LSETlset 이벤트를 발생시킨다.
  • LREMlrem 이벤트를 발생시킨다. 만약 결과 리스트가 빈 값이고, 키가 삭제된다면 추가적으로 del 이벤트를 발생된다.
  • LTRIMltrim 이벤트를 발생시킨다. 만약 결과 리스트가 빈 값이고, 키가 삭제된다면 추가적으로 del 이벤트를 발생된다.
  • RPOPLPUSHBRPOPLPUSHrpop이벤트와 lpush이벤트를 발생시킨다. 두 가지의 경우 순서는 보장된다. (lpush이벤트가 항상 rpop 이벤트의 이후에 전달된다.) 추가적으로 del이벤트가 발생하는데, 만약 결과 리스트의 길이가 0이고, 키가 삭제된다면, 추가적으로 del이벤트가 발생된다.
  • HSET, HSETNX 그리고 HMSET 모두 단일 hset이벤트를 발생시킨다.
  • HINCRBYhincrby 이벤트를 발생시킨다.
  • HINCRBYFLOAThincrbyfloat 이벤트를 발생시킨다.
  • HDEL은 단일 hdel이벤트를 발생시키고, 만약 결과 해시가 빈 값이고, 키가 삭제된다면 추가적으로 del이벤트를 발생시킨다.
  • SADD는 단일 sadd이벤트를 발생시키는데, 가변적인 인자에 대해서도 마찬가지이다.
  • SREM은 단일 srem이벤트를 발생시킨다. 만약, 결과 셋이 빈 값이고, 키가 삭제된다면 추가적으로 del이벤트가 발생된다.
  • SMOVE는 원본 키에 대해서는 srem이벤트를 발생시키고, 대상 키에 대해서는 sadd이벤트를 발생시킨다.
  • SPOPspop이벤트를 발생시킨다. 만약 결과 셋이 빈 값이고, 키가 삭제된다면 del이벤트가 발생된다.
  • SINTERSTORE, SUNIONSTORE, SDIFFSTOREsinterstore, sunionstore, sdiffstore이벤트를 각각 발생시킨다. 결과 셋이 비어있는 경우에, 그리고 저장하려는 키가 이미 존재한다면, 키가 삭제되기 때문에 del이벤트가 발생한다.
  • ZINCRzincr이벤트를 발생시킨다.
  • ZADD는 여러 엘리먼트가 추가되더라도 단일 zadd이벤트를 발생시킨다.
  • ZREM은 여러 엘리먼트가 삭제되더라도 단일 zrem이벤트를 발생시킨다. 결과 셋이 비어있고, 키가 삭제된다면, 추가적으로 del이벤트가 발생된다.
  • ZREMBYSCORE는 단일 zrembyscore이벤트를 발생시킨다. 결과 셋이 비어있고, 키가 삭제된다면, 추가적으로 del이벤트가 발생된다.
  • ZREMBYRANK는 단일 zrembyrank이벤트를 발생시킨다. 결과 셋이 비어있고, 키가 삭제된다면, 추가적으로 del이벤트가 발생된다.
  • ZINTERSTOREZUNIONSTORE은 각각 zinterstorezunionstore이벤트를 발생시킨다. 결과 셋이 비어 있고, 저장하려는 키가 이미 존재하고 있다면, 키가 삭제되기 때문에 del 이벤트가 발생한다.
  • XADDxadd이벤트를 발생시키고, MAXLEN 서브커맨드가 함께 사용될 때에는 xtrim이 뒤어어 발생할 수 있다.
  • XDEL은 여러 엔트리가 삭제되더라도 단일 xdel 이벤트를 발생시킨다.
  • XGROUP CREATExgroup-create이벤트를 발생시킨다.
  • XGROUP DELCONSUMERxgroup-delconsumer이벤트를 발생시킨다.
  • XGROUP DESTROY generates an xgroup-destroy event.
  • XGROUP DESTROYxgroup-destroy이벤트를 발생시킨다.
  • XGROUP SETIDxgroup-setid이벤트를 발생시킨다.
  • XSETIDxsetid이벤트를 발생시킨다.
  • XTRIMxtrim이벤트를 발생시킨다.
  • TTL(time to live)이 지정된 키가 만료되어 데이터 셋으로부터 삭제될 때마다,expired 이벤트가 발생한다.
  • maxmemory 정책의 결과로, 여유 메모리 확보를 위해 키가 데이터 셋으로부터 추출(eviction)될 때마나, evicted이벤트가 발생한다.

IMPORTANT 모든 커맨드는 대상 키가 실제로 변경된 경우에만 이벤트를 발생시킨다. 예를 들어, SREM이 셋으로부터 존재하지 않는 엘리먼트를 삭제하는 것은 실제로 키의 값을 변경시키기 않기 때문에, 아무런 이벤트도 발생하지 않는다.

주어진 커맨드에 대해 이벤트가 어떻게 발생하는 지에 대해 의심스러운 경우에 가장 간단히 할 수 있는 것은, 직접 보는 것이다:

$ redis-cli config set notify-keyspace-events KEA
$ redis-cli --csv psubscribe '__key*__:*'
Reading messages... (press Ctrl-C to quit)
"psubscribe","__key*__:*",1

이 시점에서 커맨드를 레디스 서버로 보내기 위해 또 다른 터미널에서 redis-cli를 사용하고, 발생되는 이벤트를 관찰한다:

"pmessage","__key*__:*","__keyspace@0__:foo","set"
"pmessage","__key*__:*","__keyevent@0__:set","foo"
...

Timing of expired events

TTL이 설정된 키들은 레디스에 의해 다음의 2가지 방법으로 만료된다.

  • 특정 키에 대해 커맨드에 의한 접근이 발생했고, 만료된 사실이 발견되었을 때
  • 절대 접근될 수 없는 키를 수집할 수 있도록, 백그라운드에서 순차적으로 만료된 키를 찾는 백그라운드 시스템을 통해서

expired 이벤트는 위의 시스템 중 하나에 의해서 키로 접근이 발생하고, 만료된 사실이 발견되었을 때 발생한다. 그 결과, 레디스 서버가 키의 TTL이 0에 도달한 시점에 expired 이벤트를 발생시키는 것은 보장되지 않는다.

만약 특정 키를 대상으로하는 커맨드가 계속해서 없고, TTL이 설정된 키가 매우 많다면, 키의 TTL이 0이 된 시간과 expired 이벤트가 발생한 시간 사이에는 상당한 딜레이가 있을 수 있다.

기본적으로 expired 이벤트는 레디스 서버가 키를 삭제할 때 발생되는 이벤트이고, 이론적으로 TTL이 0으로 도달했을 때 발생하지는 않는다.

1개의 댓글

comment-user-thumbnail
2021년 2월 14일

많이 도움 받았습니다. 감사합니다!

답글 달기