Redis Module事始め


この記事は 富士通クラウドテクノロジーズ Advent Calendar 2018 の13日目です.
昨日は @Ken-Moriizumi さんの「溜まったアレをごっそり年末に掃除する話」でした.

Redis Module 事始め

こんにちは @blue271828 です.暫くRedis を触っていなかったのですが,いつの間にか Redis Module という新しい機能が追加されたことを知りました.Luaスクリプティング機能だと届かなかった痒い所に手が届く感じで素敵だったので紹介したいと思います.

Redis Module とは

Redis Module とは Redis 4.0 より追加された機能で,C, C++ で実装したモジュールを Redis にロードすることで色々な拡張機能を実現することができる仕組みです.例えば複数の key を一度のコマンドで操作したり,独自データ型が作れたりします.

やってみる

redismodule.h をインクルードして実装します.引数の文字列を key にして,"Hello, World!" をリスト型に追加するシンプルな処理です.

helloworld.c
#include "redismodule.h"
#include <stdlib.h>
#include <string.h>

int HelloWorld_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  /* 引数の数をチェック */
  if (argc != 2) return RedisModule_WrongArity(ctx);


  /* 引数の値をkeyにしてLPUSH */
  const char *hello = "Hello, World!";
  RedisModuleKey *key =RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE);
  RedisModuleString *str = RedisModule_CreateString(ctx, hello, strlen(hello));
  if (RedisModule_ListPush(key, REDISMODULE_LIST_TAIL, str) == REDISMODULE_ERR)
    return REDISMODULE_ERR;
  RedisModule_CloseKey(key);

  /* クライアントに値を返却 */
  if (RedisModule_ReplyWithString(ctx, str) == REDISMODULE_ERR)
    return REDISMODULE_ERR;

  return REDISMODULE_OK;
}

int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
  if (RedisModule_Init(ctx, "helloworld", 1, REDISMODULE_APIVER_1)
      == REDISMODULE_ERR) return REDISMODULE_ERR;

  if (RedisModule_CreateCommand(ctx,"helloworld",
                                HelloWorld_RedisCommand, "write", 1, 1, 1) == REDISMODULE_ERR)
    return REDISMODULE_ERR;

  return REDISMODULE_OK;
}

実装したファイルは,コンパイル後に Redis にロードすることで利用することができます.コンパイルは次のように行います.

$ gcc -O2 -shared -fPIC helloworld.c -o helloworld.so

ロードは Redisクライアントからロードする方法と,redis.conf などの設定ファイルに記述する方法があります.Redisクライアントで読み込む場合は,次のように入力します.正しくロードされると "OK" と表示されます.

> MODULE LOAD /path/to/helloworld.so

設定ファイルに記述する方法は次のよう書きます.

loadmodule /path/to/helloworld.so

動かしてみる

ロード後に実装したコマンドを使用すると,利用できるなることが確認できると思います.

127.0.0.1:6379> LRANGE hoge 0 -1
(empty list or set)
127.0.0.1:6379> HELLOWORLD hoge
"Hello, World!"
127.0.0.1:6379> HELLOWORLD hoge
"Hello, World!"
127.0.0.1:6379> LRANGE hoge 0 -1
1) "Hello, World!"
2) "Hello, World!"

Redis Cluster の場合ですが,通常のコマンドと同様に key hash に応じて各ノードにリダイレクトされます.ここで少し注意しなければならないのは,全ノードにモジュールがロードされていないとリダイレクト語に unknown command のエラーになってしまうため,Redis Cluster でモジュールを利用する為には事前に対象ノードにロードしておく必要があるようです.

127.0.0.1:7000> HELLOWORLD hoge
"Hello, World!"
127.0.0.1:7000> HELLOWORLD hogehoge
"Hello, World!"
127.0.0.1:7000> HELLOWORLD hogehogehoge
-> Redirected to slot [5990] located at 173.17.0.3:7001
"Hello, World!"

あとがき

コマンドという形で Redis を拡張できるようになることから,Luaスクリプティング機能とは違った形で活用できる場面があると思います.個人的にはロードした処理をハッシュで呼ばなくてよくなるだけでも,かなり有難かったりします.また今回はあまり深堀りしませんでしたが,恐らく Redis Module ならではの拡張もあるのではないかと思いますので,また機会があれば紹介できたらと思います.

ちなみに明日ですが,どうやら @foobaron さんが何かネットワークネタをやってくれるそうです.お楽しみに!