RedisLuaスクリプトLUAスクリプトの高頻度インタビューの質問の詳細な説明

一緒に書く習慣を身につけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して6日目です。クリックしてイベントの詳細をご覧ください

Redisは2.6でスクリプト関数を起動しました。これは、Lua言語で記述し、実行のためにRedisに渡すことができます。

スクリプトの利点:

  1. ネットワークオーバーヘッドの削減:元の5つのネットワークリクエストは1つのリクエストで完了でき、元の5つのリクエストロジックはredisサーバーに送信されて完了します。パイプと同様に、ネットワークのラウンドトリップ遅延が減少しました。
  2. アトミック操作:Redisは、他のコマンドを介さずに、スクリプト全体を実行します。
  3. Redisのトランザクション機能の置き換え:Redisに付属のトランザクション機能は非常に味がなく、redisのluaスクリプトは従来のトランザクション機能をほぼ実現しています。redisのトランザクション機能を使用する場合は、次のことを検討することをお勧めします。代わりにluaを使用します。

スクリプトの使用方法

組み込みのluaインタープリターを使用して、EVALコマンド。コマンドの形式は次のとおりです。

# 脚本格式
EVAL script numkeys key [key ...] arg [arg ...]
# 示例
127.0.0.1:6379> EVAL "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 k1 k2 a1 a2 
1) "k1"
2) "k2"
3) "a1"
4) "a2"
复制代码

パラメータの説明:

最初のスクリプトパラメーターはLuaスクリプトであり、redisサーバーのコンテキストで実行されます。このスクリプトはlua関数として定義されていません(定義されるべきではありません)。

2番目のnumkeysパラメーターは、キー名パラメーターの数を指定するために使用されます。

3番目のパラメーター(キー名パラメーターkey)から始まり、スクリプトで使用されるRedisキー(キー)を表します。これらのキー名パラメーターKEYS1、ベースアドレスから始まるグローバル変数配列を介してLuaでアクセスできますKEYS[1],KEYS[2]

コマンドの最後で、キー名パラメーターではない追加のパラメーターにarg [arg ...]、グローバル変数ARGV配列、添え字も。から始まり1ます。

redis.call()関数をLuaスクリプトで使用して、redisコマンドを実行できます。

ジェダイ控除在庫ケースコールの例:

try (Jedis jedis = jedisPool.getResource()) {
    // 初始化商品id为100的库存
    jedis.set("product_stock_100", "10000");
    // @formatter:off
    String script = "local count =  redis.call('get',KEYS[1]) " +
            "local a = tonumber(count) " + 
            "local b = tonumber(ARGV[1]) " + 
            "if a >= b then " + 
            "redis.call('set',KEYS[1],a-b) " + 
            "return 1 " + 
            "end " + 
            "return 0";
    // @formatter:on
    Object decrResult = jedis.eval(script, Arrays.asList("product_stock_100"), Arrays.asList("100"));
    System.out.println(decrResult);
}
复制代码

**注:** luaスクリプトに無限ループや時間のかかる操作を行わないでください。そうしないと、** redisがブロック**して他のコマンドを受け入れないため、上記を使用しないように注意してください。

Redisはシングルプロセスのシングルスレッド実行スクリプトであり、パイプラインはredisをブロックしません。

Redis LUAスクリプトはコマンドロールバックを実行しますか?

luaスクリプトを使用すると、一連のredisコマンドを実行するときに特定のアトミック性を実現できます(luaスクリプトで複数の命令を実行している間は新しい命令は挿入されません)が、コマンドの実行が失敗した場合は以前の結果をロールバックできません

次のコードスニペットを使用して検証し、コードを実行する前にredisデータをクリアします。

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> KEYS *
(empty array)
复制代码

次に、次のコードを実行します。完全なコードは公式アカウントに注意を払い一个程序猿的异常、キーワードLUAGet。

try (Jedis jedis = jedisPool.getResource()) {
    // @formatter:off
    String script = " redis.call('SET', 'success','100') " 
                    // 模拟redis 出现异常信息,-1索引在bitmap不存在会报错
                    + " redis.call('SETBIT', 'bit_test','-1','1')  "
                    + " redis.call('SET', 'fail','100') " 
                    + " return 1";
    // @formatter:on
    Object eval = jedis.eval(script);
    System.out.println(eval);
}
复制代码

実行後にredisでデータを表示します。

127.0.0.1:6379> KEYS *
1) "success"
127.0.0.1:6379> get success
"100"
复制代码

結論:luaスクリプトを使用すると、一連のredisコマンドを実行するときに特定のアトミック性を実現できます(luaスクリプトで複数の命令を実行している間は新しい命令は挿入されません)が、コマンドの実行が失敗した場合は以前の結果をロールバックできません

おすすめ

転載: juejin.im/post/7088963946534666271