redisでluaスクリプトを使用するためのチュートリアル
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. 変換ルールの追加
- 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/commands/eval
今回の記事は、redisでのluaスクリプトの簡単な使い方についてです。redisでのluaスクリプトの使い方については、スクリプトハウスの過去記事を検索するか、引き続き以下の関連記事を閲覧してください。
関連
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Redisクラスタのマスターノードとスレーブノードを縮小する詳細チュートリアル
-
redis分散ロックについて解説(redis分散ロックの最適化処理とRedissonの利用について)
-
Redisのインクリメント呼び出しが失敗する理由と推奨される使い方を大きな白い嘘で解説
-
redisプラグインbloom-filterをcentosにインストールする方法
-
Redisは携帯電話の認証コードを送信する機能を模倣している
-
redisを使ってnearly peopleの機能を実装する
-
Redisの高同期スパイクを防ぐために、ソースコードソリューションを売られすぎ
-
Redisの文字列はどのように実装されているか
-
RedisClusterが16,384個のスロットを持つ設計になっている理由
-
redis アプリケーション編 ---- スパイク、サインイン、セッション共有