はじめに
今回は Redis の公式ドキュメントにある Scripting with Lua について勉強する。

※ 自分はよく混同してしまうのだが、今回は Redis のサーバー上で Lua を実行する方法について述べる。(Lua プログラムから Redis クライアントを利用する方法については述べない。)
Redis と Lua について
Redis では、サーバー上で Lua スクリプトを実行させることができる。 スクリプトによってプログラムによる制御をおこなうことができ、コマンドを使ってデータベースにアクセスできる。
- スクリプトはサーバー内で実行されるため、スクリプトからのデータの読み書きは非常に効率的になる 。(PostgreSQL の PL/pgSQL に似ている)
- Redis ではスクリプトの実行にはアトミック性が保証される。スクリプトの実行中、サーバーのアクティビティはブロックされる(スクリプトがすべて作用しているか、すべて作用していないかの状態になる)
Redis で Lua を使うとできること
Lua を使用すると、アプリケーションのロジックの一部を Redis の内部で実行させることができる。例えば以下のようなことができる。
- 複数のキーを条件付きで更新する
- 複数の異なるデータ型を組み合わせて操作する
※ スクリプトは Redis に組み込まれた実行エンジンによって実行される。(Lua 5.1 のみ)
※ EVAL するスクリプトはサーバー側ではなくクライアント側アプリケーションの一部とみなされ、永続化されない。スクリプトは(サーバーの再起動後などに)見つからなくなる場合がありアプリケーションから再読み込みさせる必要がある。Redis 7 以降、Redis Functions という別の方法でサーバー自体をプログラムされた追加ロジックで拡張できるようになった。
例 1. Hello World 的なもの
> EVAL "return 'Hello, scripting!'" 0
"Hello, scripting!"
この例では EVAL
が 2 つの引数を受け取っている
- 第 1 引数: Lua のスクリプト(関数の定義ではなく、そのまま実行されるプログラムを書く)
- 第 2 引数: キーの数(今回はキーを与えていないので 0 を指定している)
例 2. スクリプトに引数を与える
以下のようなスクリプトを、
redis> EVAL "return 'Hello'" 0
"Hello"
redis> EVAL "return 'Scripting!'" 0
"Scripting!"
引数を使って以下のようにできる
redis> EVAL "return ARGV[1]" 0 Hello
"Hello"
redis> EVAL "return ARGV[1]" 0 Parameterization!
"Parameterization!"
- 第 1 引数: Lua のスクリプト
- 第 2 引数: キーの数が 0
- 第 3 引数: ARGV に入る値の 1 つ目(Lua のインデックスは 1 から始まる)
注意点:
上の例のような微妙に異なる複数のスクリプトをアプリケーション側で生成して実行させることはアンチパターンと言われている。
-
EVAL
で実行したスクリプトはサーバーの専用のキャッシュに保存されるので、さまざまなスクリプトの生成によりホストのメモリリソースを使い果たす可能性がある。
スクリプトは汎用的にして、引数を介して実行する内容をカスタマイズする必要がある。
例 3. スクリプトにキーを与える
redis> EVAL "return { KEYS[1], KEYS[2], ARGV[1], ARGV[2], ARGV[3] }" 2 key1 key2 arg1 arg2 arg3
1) "key1"
2) "key2"
3) "arg1"
4) "arg2"
5) "arg3"
- 第 1 引数: Lua のスクリプト
- 第 2 引数: キーの数が 2
- 第 3、4 引数: キー(KEYS に入る値)
- 第 5、6、7 引数: 引数(ARGV に入る値)
KEYS と ARGV の使い分け: KEYS に入る値は Redis の(キー・バリューのうちの)キーの値にする。それ以外の共通化できる引数には ARGV を利用する。
例 4. スクリプトで Redis とやりとりする
redis.call()
もしくは redis.pcall()
を利用して Redis のコマンドを実行することができる。
> EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 foo bar
OK
このスクリプトを実行すると、SET コマンドが呼び出され、キー foo
に値 "bar" が設定される。
注意点:
スクリプトを正しく実行するためにはスクリプトがアクセスするキーの名前をすべて入力キーの引数として明示的に指定する必要がある。
(スクリプトがプログラムによって生成された名前のキーやデータベースに格納されているデータに基づくキーにアクセスするようにしてはいけない。)