キー・スペース通知

重要 keyspace notifications は 2.8.0 以上で提供される機能です。

機能概要

keyspace notifications は、Redis データセットに対するなんらかの変更イベントを、クライアントが Pub/Sub チャネルで受け取るための仕組みです。

以下は、受け取れるイベントの例です:

  • あるキーに作用するすべてのコマンド

  • LPUSH 操作を受けたすべてのキー

  • database 0 の中で、expire されたすべてのキー

イベントは、ノーマルな Redis の Pub/Sub レイヤを介して配信されます。そのため、Pub/Sub を実装しているクライアントであれば、修正を加えることなくこの機能が利用できます。

Redis の Pub/Sub は現在のところ fire and forget であるため、 信頼性のある通知 を必要とするアプリケーションで使うことはできません。つまり、Pub/Sub クライアントが接続を失って、後に再接続をしても、接続が途切れていた間に配信されたイベントの情報は失われます。

将来的にはより信頼性のあるイベント配信の提供も検討されていますが、おそらくそれは Pub/Sub 自身の信頼性を上げていくか、または Lua スクリプトで Pub/Sub メッセージを捉えてリストにプッシュするなどの方法で、より上位のレベルで対応されることになるでしょう。

イベントタイプ

keyspace notifications は、Redis データセットに作用する各操作に対し、2 つの異なるタイプのイベントを送信するように実装されています。たとえば database 0 の ‘mykey’ に対する DEL 操作は 2 つのメッセージを配信します。メッセージは以下の 2 つの PUBLISH コマンドと等価です。

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

一方のチャネルで ‘mykey’ に対するすべてのイベントを検知でき、もう一方のチャネルからは ‘del’ 操作の対象となったすべてのキーに関する情報を取得できることが、簡単に推測できるでしょう。

‘keyspace’ から始まる、最初のイベントタイプは Key-space notification と呼ばれ、2 つめの ‘keyevent’ から始まるイベントタイプは Key-event notification と呼ばれます。

上述の例では、’del’ イベントが ‘mykey’ に対して発行されています。起こることは以下です:

  • Key-space チャネルはイベント名を受信する

  • Key-event チャネルはキー名を受信する

関心のあるイベントのサブセットだけを配信するため、どちらかの通知のみを有効にすることも可能です。

設定

この機能は少なからず 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
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$lshzxe, so that the "AKE" string means all the events.

少なくとも、’K’ または ‘E’ が指定される必要があります。そうでないと、残りの文字列にかかわらずいずれのイベントも配信されません。

たとえばリストに関する Key-space events の通知だけを有効にするには、パラメータは ‘Kl’ と設定します。その他も同様です。

‘KEA’ という文字列を指定すると、発生しうるすべてのイベントに関する通知を有効にします。

各コマンドにより生成されるイベント

異なるコマンドは、異なるイベントを生成します。以下のリストに列挙します。

  • DEL は削除された各キーに対し ‘del’ イベントを生成します。

  • RENAME は 2 つのイベントを生成します。ひとつは変更元キーに対する ‘rename_from’ イベント、もうひとつは 変更先キーに対する ‘rename_to’ イベントです。

  • EXPIRE はキーに対し expire が設定されたときに ‘expires’ イベントを、expire によりキーが削除されたときに ‘del’ イベントを生成します(詳しくは EXPIRE のドキュメントを参照)。

  • SORT は、新しいキーをセットするため STORE が指定されたときに ‘sortstore’ イベントを生成します。結果のリストが空で、 STORE が指定され、かつ同名のキーが存在した場合はそのキーが削除されるため、 ‘del’ イベントが生成されます。

  • SET およびその異型(SETEX, SETNX, GETSET) は ‘set’ イベントを生成します。なお SETEX は同時に ‘expire’ イベントも生成します。

  • MSET は各キーごとに別々の ‘set’ イベントを生成します。

  • SETRANGE は ‘setrange’ イベントを生成します。

  • INCR, DECR, INCRBY, DECRBY コマンドはすべて、’incrby’ イベントを生成します。

  • INCRBYFLOAT は ‘incrbyfloat’ イベントを生成します。

  • APPEND は ‘append’ イベントを生成します。

  • LPUSHLPUSHX は、可変個の引数をとりますが、ひとつの ‘lpush’ イベントを生成します。

  • RPUSHRPUSHX は、可変この引数をとりますが、ひとつの ‘rpush’ イベントを生成します。

  • RPOP は ‘rpop’ イベントを生成します。最後の要素がリストから pop されてキーが削除された場合は、加えて ‘del’ イベントが生成されます。

  • LPOP は ‘lpop’ イベントを生成します。最後の要素がリストから pop されてキーが削除された場合は、加えて ‘del’ イベントが生成されます。

  • LINSERT は ‘linsert’ イベントを生成します。

  • LSET は ‘lset’ イベントを生成します。

  • LTRIM は ‘ltrim’ イベントを生成します。結果としてリストが空になり、キーが削除された場合は、加えて ‘del’ イベントが生成されます。

  • RPOPLPUSHBRPOPLPUSH は ひとつの ‘rpop’ イベントとひとつの ‘lpush’ イベントを生成します。両方のケースにおいて、順序は保証されます(‘lpush’ イベントは常に ‘rpop’ イベントの後に配信される)。結果としてリスト長がゼロになり、キーが削除された場合は ‘del’ イベントも生成されます。

  • HSET, HSETNX, および HMSET はすべて、ひとつの ‘hset’ イベントを生成します。

  • HINCRBY は ‘hincrby’ イベントを生成します。

  • HINCRBYFLOAT は ‘hincrbyfloat’ イベントを生成します。

  • HDEL は ‘hdel’ イベントを生成します。結果として Hash が空になりキーが削除された場合は、加えて ‘del’ イベントも生成されます。

  • SADD は可変個の引数をとりますが、ひとつの ‘sadd’ イベントを生成します。

  • SREM は ‘srem’ イベントを生成します。結果として Set が空になりキーが削除された場合は、加えて ‘del’ イベントも生成されます。

  • SMOVE は移動元キーに対して ‘srem’ イベントを、移動先キーに対して ‘sadd’ イベントを生成します。

  • SPOP は ‘spop’ イベントを生成します。結果として set が空になりキーが削除された場合は加えて ‘spop’ イベントも生成されます。

  • SINTERSTORE, SUNIONSTORE, SDIFFSTORE はそれぞれ ‘sinterstore’, ‘sunionostore’, ‘sdiffstore’ イベントを生成します。特殊なケースとして、結果セットが空で、かつ格納先のキーがすでに存在した場合は、キーが削除されるため ‘del’ イベントも生成されます。

  • ZINCRBY は ‘zincr’ イベントを生成します。

  • ZADD は、複数の要素が追加される場合でも、ひとつの ‘zadd’ イベントを生成します。

  • ZREM は、複数の要素が削除される場合でも、ひとつの ‘zrem’ イベントを生成します。結果のソート済み集合が空になり、キーが削除された場合は、加えて ‘del’ イベントも生成されます。

  • ZREMBYSCORE [訳注: ZREMRANGEBYSCORE の間違い?] は、’zrembyscore’ イベントを生成します。結果のソート済み集合が空になり、キーが削除された場合は、加えて ‘del’ イベントも生成されます。

  • ZREMBYRANK [訳注:ZREMRANGEBYRANK の間違い?] は、’zrembyrank’ イベントを生成します。結果のソート済み集合が空になり、キーが削除された場合は、加えて ‘del’ イベントも生成されます。

  • ZINTERSTOREZUNIONSTORE はそれぞれ ‘zinterstore’ イベントと ‘zunionstore’ イベントを生成します。特殊なケースとして、結果のソート済み集合が空で、かつ格納先のキーがすでに存在した場合は、キーが削除されるため ‘del’ イベントも生成されます。

  • time to live をもつキーが expire されてデータセットから削除される都度、’expired’ イベントが生成されます。

  • フリーメモリ領域の確保のため ‘maxmemory’ ポリシーによってキーがデータセットから除去される都度、’evicted’ イベントが生成されます。

重要 すべてのコマンドは、対象とするキーを実際に変更した場合にのみ、イベントを生成します。たとえば、Set に存在しない要素を ‘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’ を使って Redis サーバーにコマンドを送り、生成されるイベントを監視します:

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

expired イベントの発生タイミング

time to live が関連づけられたキーは、Redis により 2 つの方法で expire されます。

  • あるコマンドでキーがアクセスされ、すでに expire されていることに気づいたとき

  • 一切アクセスされなくなったキーを集めるため、expire されたキーをひとつずつ探すバックグラウンドシステムを介して。

‘expired’ イベントは、上記いずれかのシステムによりキーがアクセスされた時に生成されます。したがって、キーの time to live の値がゼロに達したタイミングで Redis サーバーが ‘expired’ イベントを生成するという保証はありません。

対象のキーに対してコンスタントにコマンドが実行されず、また TTL が関連づけられたキーが多く存在する場合、time to live がゼロに達したタイミングと ‘expired’ イベントが生成されるタイミングの間には、大きな遅延が発生する可能性があります。

基本的に、’expired’ イベントは Redis サーバーがキーを削除したときに生成され 、理論上において time to live の値がゼロに達したときに生成されるものではありません。