1. ホーム
  2. データベース
  3. レディス

redisでluaスクリプトを使用するためのチュートリアル

2022-01-15 03:31:33

I. 背景

を使用する場合 redis が必要なときがあることがわかりました。 atomicity を操作するために、redisコマンドを使用し、redis lua スクリプトはまさにそれを行うことができます。例:在庫の引き落とし操作、リミットフロー操作、など。
を使用することで、Redis pipelining コマンドのセットを一度に実行することは可能ですが、そのコマンドのセットの実行中に、前の実行ステップの結果に基づく何らかの判断が必要な場合は、この限りではありません。

II. luaスクリプトの使用

Redisは Lua 5.1 Redisのスクリプト仕様はLua 5.1/codeを使用しており、スクリプトを記述する際にLua関数を定義する必要はありません。また、グローバル変数なども使用できません。

1. luaスクリプトの書式と注意点

1、フォーマット

EVAL スクリプト numkeys key [key ...] arg [arg ...].

<ブロッククオート

127.0.0.1:6379> eval "return {KEYS[1],ARGV[1],ARGV[2]}" 1 key1 arg1 arg2
1) "キー1"。
2) "arg1"
3) "arg2"
127.0.0.1:6379>

2. 備考

Lua スクリプト内のredis操作のキーは、できればすべて KEYS に書き込むのではなく、死蔵する。そうしないと、Redis Clusterの場合に問題が発生する可能性があります。

1. 良い書き方

127.0.0.1:6379> eval "return redis.call('set',KEYS[1],'zhangsan')" 1 ユーザー名
OK
127.0.0.1:6379> ユーザー名の取得
zhangsan"

redisコマンド操作のキーは、KEYSで取得します。

2.書き込み方法が悪い

127.0.0.1:6379> eval "return redis.call('set','username','zhangsan')" 0
OK
127.0.0.1:6379> ユーザー名の取得
zhangsan"

redisコマンド操作のキーが直接書き込まれるdeath。

2. スクリプトをredisに読み込む

要件 入力パラメータ +1 の値を返す lua スクリプトを定義します。

注意事項

を置くと lua script がredisに読み込まれると、スクリプトはすぐには実行されず、キャッシュされて sha1 チェックサムを生成し、それを後で EVALSHA を実行して、このスクリプトを実行します。

ここでは、このスクリプトが読み込まれた後に返されるハッシュ値を記憶しています。これは次の実行ステップで必要となります。

<ブロッククオート

127.0.0.1:6379> スクリプトロード "return tonumber(KEYS[1])+1"
"ef424d378d47e7a8b725259cb717d90a4b12a0de"
127.0.0.1:6379>

3. luaスクリプトを実行する

1. evalで実行

127.0.0.1:6379> eval "return tonumber(KEYS[1]) + 1" 1 100
(整数) 101
127.0.0.1:6379>

2. evalsha経由で実行する

ef424d378d47e7a8b725259cb717d90a4b12a0de は、前のステップの値で script load を読み込んだ後、スクリプトを実行します。

127.0.0.1:6379> evalsha ef424d378d47e7a8b725259cb717d90a4b12a0de 1 100
(整数) 101
127.0.0.1:6379>

By evalsha 実行の利点は、帯域を節約できることです。長いluaスクリプトがある場合、プログラムは実行時にluaスクリプトをredisサーバーに送るために多くの帯域幅を使用し、ハッシュ値を送る場合は少ない帯域幅を使用することができます。

4. スクリプトがredisサーバーのキャッシュにあるかどうかの判断

127.0.0.1:6379> スクリプトロード "return tonumber(KEYS[1])+1"
"ef424d378d47e7a8b725259cb717d90a4b12a0de"
127.0.0.1:6379> スクリプトが存在する ef424d378d47e7a8b725259cb717d90a4b12a0de
1)(整数)1
127.0.0.1:6379> スクリプトが存在する not-exists-sha1
1)(整数)0
127.0.0.1:6379>

5. サーバー上のスクリプトキャッシュをクリアする

注意
特定のスクリプトのキャッシュをクリアすることはできず、すべてのスクリプトをクリアすることしかできません。また、多数のスクリプトを使用してもサーバーのメモリをあまり消費しないため、一般にキャッシュをクリアする必要はありません。

127.0.0.1:6379> スクリプトロード "return tonumber(KEYS[1])+1"
"ef424d378d47e7a8b725259cb717d90a4b12a0de"
127.0.0.1:6379> スクリプトが存在する ef424d378d47e7a8b725259cb717d90a4b12a0de
1)(整数)1
127.0.0.1:6379> スクリプトフラッシュ
OK
127.0.0.1:6379> スクリプトが存在する ef424d378d47e7a8b725259cb717d90a4b12a0de
1)(整数)0

6. 実行中のスクリプトを終了させる

127.0.0.1:6379> script kill

注意事項

  • このコマンドは実行中の read-only script .
  • データを変更したスクリプトは、このコマンドで終了させることはできず、次のコマンドで終了させます。 shutdown nosave コマンドを使用します。
  • で実行されるスクリプトは Default timeout 5 minutes を経由してアクセスできること。 redis.conf の設定ファイルです。 lua-time-limit の設定項目が変更されます。
  • タイムアウトに達してもスクリプトの実行を停止しない。これは、lua スクリプトのアトミック性に違反するため。

iii. lua と redis のデータ型変換

Lua データ型と Redis Redisのデータ型とRedisのデータ型は1対1の変換関係にあります。Redisの型をLuaの型に変換し、それをRedisの型に変換すると、結果はテストの初期値と同じになります。

1. 型変換

RedisからLuaconversionへの変換テーブル。

  • Redis の整数値 reply -> Lua の数値
  • Redis一括応答 -> Lua文字列
  • Redisマルチ一括応答 -> Luaテーブル(他のRedisデータ型がネストされている場合があります。) Redis status reply -> ステータスを含む1つのokフィールドを持つLuaテーブル。
  • Redis error reply -> Lua table with single err field containing the error(エラーを含む単一のerrフィールドを持つLuaテーブル
  • Redis Nil一括応答およびNil複数一括応答 -> Lua false boolean type

LuaからRedisconへの変換表です。

  • Lua number -> Redis integer reply (数値は整数に変換されます)
  • Lua文字列 -> Redis一括応答
  • Lua テーブル (配列) -> Redis マルチ一括応答 (Lua 配列内の最初の nil まで切り捨て)
  • OKフィールドを1つ持つLuaテーブル -> Redisステータス応答
  • errフィールドを1つ持つLuaテーブル -> Redisエラー応答
  • Lua boolean false -> Redis Nil一括応答。

2. 変換ルールの追加

  1. LuaのBoolean型、LuaのTrueはRedisの1へ変換されます。

3. 3つの重要なルール

1. 番号の種類

Luaでは、1つだけです。 number の型があり、整数と浮動小数点数の違いはありません。Luaで浮動小数点数を返す場合、実際には整数を返していることになり、浮動小数点数を返すには、文字列として返す必要があります。

127.0.0.1:6379> eval "return 3.98" 0
(整数) 3
127.0.0.1:6379> eval "戻り値 '3.98'" 0
"3.98"。

2. lua の配列は nil が存在する。

RedisがLua配列をRedisプロトコルに変換する際、nilに遭遇すると変換が停止します。つまり、nil以降の値が返されない。

127.0.0.1:6379> eval "return {1,2,'data',nil,'can not return value','vv'}" 0
1) (整数) 1
2) (整数) 2
3) "データ"
127.0.0.1:6379>

3. Luaのテーブル型はビルドとバリューを含む

この場合、返されるredisは空の配列である

127.0.0.1:6379> eval "return {key1 ='value1',key2='value2'}" 0
(空の配列)
127.0.0.1:6379>

IV. luaスクリプトでログを出力する

これは一般的に、スクリプトをデバッグするときに便利です。

<ブロッククオート

redis.log(loggelvel,メッセージ)

loglevelの値の範囲。

  • redis.LOG_DEBUG
    
    redis.LOG_VERBOSE
    redis.LOG_NOTICE
    redis.LOG_WARNING

V. 流れを制限するシンプルなケース

1. 必要条件

メソッドの最大同時実行数は、1秒間に5個までです。

1sと5が引数として渡される。

2. 実装手順

1. luaスクリプトの作成

-- Output the parameters passed in by the user
for i, v in pairs(KEYS) do
    redis.log(redis.LOG_NOTICE, "limit: key" . i ... " = " ... v)
end
for i, v in pairs(ARGV) do
    redis.log(redis.LOG_NOTICE, "limit: argv" . i ... " = " ... v)
end

-- key for limit flow
local limitKey = tostring(KEYS[1])
-- the number of times to limit the flow
local limit = tonumber(ARGV[1])
-- how long to expire
local expireMs = tonumber(ARGV[2])

-- the number of times the current has been executed
local current = tonumber(redis.call('get', limitKey) or '0')

-- set a breakpoint
redis.breakpoint()

redis.log(redis.LOG_NOTICE, "limit key: " . tostring(limitKey) ... " in [" ... tostring(expireMs) ... "] ms has been accessed within " ... tostring(current) ... ", can be accessed up to: " ... limit ... " " times")

-- Limit the flow
if (current + 1 > limit) then
    return { true }
end

-- access limit not reached
-- accesses +1
redis.call("incrby", limitKey, "1")
if (current == 0) then
    -- Set the expiration time
    redis.call("pexpire", limitKey, expireMs)
end

return { false }

2. プログラム内のluaスクリプトを実行する

フルコードです。 https://gitee.com/huan1993/spring-cloud-parent/tree/master/springboot/springboot-redis-lua

VI. luaスクリプトのデバッグ

luaスクリプトを書いた後、実行中にエラーが発生した場合、どのように修正すればよいのでしょうか。ここでは、luaスクリプトのデバッグ方法について説明します。

1. luaスクリプトのちょっとしたコマンド

スクリプト内でブレークポイントを打つ

<ブロッククオート

redis.breakpoint()

2. ブレークポイントデバッグ

1. コマンドを実行する

redis-cli --ldb --eval limit.lua invoked , 1 1000

limit.lua requires a debug lua file
invoked is the value passed to the KEYS in the lua script
1 and 1000 are the values passed to the ARGV in the lua script

, splitting out the KEYS and ARGV values


2. いくつかのデバッグコマンド

  • help : 利用可能なデバッグコマンドの一覧
  • s または n : 現在の行まで実行して停止(現在の行はまだ実行されていない)
  • c : 次のブレークポイントまで実行します。 redis.breakpoint() メソッド
  • list : 現在の行の周辺にあるソースコードを一覧表示します
  • p : すべてのローカル変数の値を出力します。
  • p <var> : 特定のローカル変数の値を表示します。
  • r : redisコマンドの実行

-- eg:
r セットキー値
r キーを取得

3.実行結果のデバッグ

VII. 参考文献

https://redis.io/topics/ldb

https://redis.io/commands/eval

今回の記事は、redisでのluaスクリプトの簡単な使い方についてです。redisでのluaスクリプトの使い方については、スクリプトハウスの過去記事を検索するか、引き続き以下の関連記事を閲覧してください。