多くの人は、SQLデータベースにプロシージャを保存する機能について知っています。これについては、たくさんのふさふさしたマニュアルや記事が書かれています。 ただし、Redisにバージョン2.6.0以降同様の機能があることを知っている人はほとんどいません。 しかし、Redisはリレーショナルデータベースではないため、ストアドプロシージャを記述するための原則はまったく異なります。 Redisのストアドプロシージャはほぼ完全なLuaスクリプトです(執筆時点では、Lua 5.1はインタープリターとして使用されています)。
さらに物語は、Redis APIの基本的な紹介と、 redis-serverプロセスがlocalhost:6379で実行されていることを前提としています 。 Redisを初めて使用する場合は、次の資料を読む前に、 Redisとは何かについての簡単な情報をお読みください。 また、少なくとも部分的には、 このインタラクティブガイドをご覧ください 。
こんにちは世界!
redis-cliを使用して、データベースから文字列「Hello world!」を返します。
redis-cli EVAL 'return "Hello world!"' 0
結果:
"Hello world!"
何が起こったのか見てみましょう:
- 2つの引数を持つRedis組み込みEVALコマンドの呼び出し。 最初に
return "Hello world!"
0
- サーバー上のプログラムテキストを解釈し、Lua文字列値を返す
- Lua文字列をredis一括返信に変換する
- redis-cliで結果を取得する
- redis-cliはstdoutへの一括返信を出力します
Redisのストアドプロシージャは通常のLua関数であるため、引数を受け取って返す原理は似ています。
注: Luaは、mul-return(関数から複数の結果を返す)をサポートしています。 ただし、redisから複数の値を返すには、マルチバルク応答を使用する必要があり、Luaのテーブルが表示されているため、以下の例は期待どおりに機能しません。
redis-cli EVAL 'return "Hello world!", "test"' 0
"Hello world!"
結果は1つの戻り値(最初)に切り捨てられます。
こんにちは%username% !
先に進みます。 引数のない関数は特に重要ではないため、引数の処理を関数に追加します。
ドキュメントによると、EVALを介して実行される関数は、LuaテーブルKEYSおよびARGVを介して任意の数の引数を受け入れることができます。 名前を含む文字列が引数として渡される場合、これを使用して%username%に挨拶します。そうでない場合は、Habrに挨拶します。
引数なしで呼び出します。LuaのARGVテーブル配列は空です。つまり、ARGV [1]はnilを返します。
redis-cli EVAL 'return "Hello " .. (ARGV[1] or "Habr") .. "!"' 0
結果:
"Hello Habr!"
そして、文字列「Innocent」をパラメーターとして渡します。
redis-cli EVAL 'return "Hello " .. (ARGV[1] or "Habr") .. "!"' 0 ''
結果:
"Hello \xd0\x98\xd0\xbd\xd0\xbd\xd0\xbe\xd0\xba\xd0\xb5\xd0\xbd\xd1\x82\xd0\xb8\xd0\xb9!"
注: Redisは文字列をutf8に保存し、redis-cliのクライアント側の問題を回避するために、asciiにない文字はエスケープシーケンスとして表示されます。 bashで読み取り可能な文字列を表示するには、次のようにします。
echo -e $(redis-cli EVAL 'return "Hello " .. ARGV[1] .. "!"' 0 '')
スクリプトからのRedis APIアクセス
各Luaスクリプトで、インタープリターはこれらのライブラリーをロードします。
string, math, table, debug, cjson, cmsgpack
最初の4つはLuaの標準です。 最後の2つは、それぞれjsonとmsgpackを操作するためのものです。
リポジトリ内のデータを操作するために、「redis」モジュールがLuaにエクスポートされました。 このモジュールのcall関数を使用して、 redis-cliからのコマンドに対応する形式でコマンドを実行できます。
データベースにユーザーが存在するかどうかを確認し、存在する場合は、一致するログイン/パスワードのペアを確認するサンプルスクリプトでredis.callを使用することを検討してください。
データベースに、ログインとパスワードのペアを含むテストデータセットを作成します。
redis-cli HMSET 'users' 'ivan' '12345' 'maria' 'qwerty' 'oleg' '1970-01-01'
OK
すべてが本当に問題ないことを確認してください。
redis-cli HGETALL 'users'
1) "ivan" 2) "12345" 3) "maria" 4) "qwerty" 5) "oleg" 6) "1970-01-01"
スクリプト入力に1つの引数、json文字列を次の形式で指定します。
{ "login":"userlogin", "password":"userpassword" }
ユーザーが存在し、jsonのパスワードがデータベースのパスワードと一致する場合、スクリプトは1を返します。それ以外の場合は0です。たとえば、入力形式が正しくない場合、引数はスクリプトに渡されなかった(ARGV [1] == nil )、またはjsonで必須フィールドの1つが欠落しています、エラー情報を含む読み取り可能な文字列を返します。
解析とパッケージ化のために、json redisはcjsonモジュールをLuaにエクスポートします。 スクリプトでは、このモジュールのデコード機能を使用します。 パラメーターとして、関数はjsonを含むLua-stringを取り、戻り値はLua-tableで、そのストリングキーはjson-fieldsです。
次の内容でlogin.luaファイルを作成します。
Login.luaスクリプトコード
local jsonPayload = ARGV[1] if not jsonPayload then return 'No such json data' end local user = cjson.decode(jsonPayload) if not user.login then return 'User login is not set' end if not user.password then return 'User password is not set' end -- redis API Lua API redis. local expectedPassword = redis.call('HGET', 'users', user.login) if not expectedPassword then return 0 end if expectedPassword ~= user.password then return 0 end return 1
使用例:
- パスワードが一致
redis-cli EVAL "$(cat login.lua)" 0 '{"login":"maria","password":"qwerty"}'
(integer) 1
- パスワードが一致しません
redis-cli EVAL "$(cat login.lua)" 0 '{"login":"maria","password":"12345"}'
(integer) 0
- JSONにはパスワードフィールドがありません
redis-cli EVAL "$(cat login.lua)" 0 '{"login":"maria","pwd":"12345"}'
"User password is not set"
- JSONを含む引数が渡されませんでした
redis-cli EVAL "$(cat login.lua)" 0
"No such json data"
注: Redisのすべてのキーは、SETおよびGETを介して操作するだけでなく、文字列表現を持ちます。 Redisには整数型はなく、フロートもありません。 これを理解することが重要です。 次の例では、テストキーの値を文字列として返します。
redis-cli SET test 5
OK
保存された値のタイプを調べます。
redis-cli TYPE test
string
戻りますが、スクリプトを通じて:
redis-cli EVAL "return redis.call('GET', 'test')" 0
"5"
同時に、整数を返すことを誰も禁止していません(整数一括返信として):
redis-cli EVAL "return tonumber(redis.call('GET', 'test'))" 0
(integer) 5
Luis番号をredis.call関数のパラメーターとして渡すことに注意してください。
redis-cli EVAL "return redis.call('SET', 'test', 5.6)" 0
OK
値はより小さい整数に切り捨てられます。
redis-cli EVAL "return tonumber(redis.call('GET', 'test'))" 0
(integer) 5
しかし、実際に内部にあるのは:
redis-cli GET test
"5.5999999999999996"
「正しい」方法:
redis-cli EVAL "return redis.call('SET', 'test', tostring(5.6))" 0
OK
redis-cli GET test
"5.6"
どうやら、Lua番号変換はLuaインタープリターではなく、Cで書かれたRedisのネイティブ部分で発生します。
今日は以上です。
こちらもご覧ください
redis.io/commands/eval
www.redisgreen.net/blog/intro-to-lua-for-redis-programmers
redislabs.com/blog/5-methods-for-tracing-and-debugging-redis-lua-scripts