2016-04-06 4 views
1

私はRedis/Luaスクリプトを理解しようとしており、次のコードで誰かが問題を抱えているかどうかを知りたいと思っています。CAS(チェック・アンド・セット)を実装するRedis Luaスクリプト?

非常に単純な「CAS」セマンティクスを実装しようとしました.1つのキーと2つの引数でコールします。サーバー上のそのキーに関連付けられた値が最初の引数で始まるかどうかチェックし、もしそうであれば、2番目の引数にキーの新しい値を設定し、そうでなければ0を返します。キーが文字列以外のデータ型に関連付けられている場合、このようなキー/値の組み合わせでSETコマンドを実行した場合と同様に、Redisはエラーを返します。呼び出しの前にキーが存在しない場合、関数は0(失敗)を返します。ここで

はスクリプトです:

local x=string.len(ARGV[1]); 
if redis.call('GETRANGE', KEYS[1], 0, x-1) == ARGV[1] then 
    redis.call('SET', KEYS[1], ARGV[2]); 
    return 1; 
    end; 
return 0 

はここ(のRedis-CLIで) "バー" のプレフィックス値とキー "foo" という上のスクリプトを呼び出す例です

eval "local x=string.len(ARGV[1]); if redis.call('GETRANGE', KEYS[1], 0, x-1) == ARGV[1] then redis.call('SET', KEYS[1], ARGV[2]); return 1; end; return 0" 1 foo bar barbazzle 

これは、 "フェンシングトークン"とキーを持つ値の両方を保存したい場合があると思います...並行しているクライアントがtを保持している場合に値を更新できるようにします彼はフェンシングトークンを修正する。

これはWATCH/MULTI/EXECセマンティクスの代わりに安全な使用パターンと思われますか? (現在の値をフェッチしたり、ローカルコードのフェンシングトークンを分割したり、新しい値を作成したり、WATCH/MULTI/EXEC呼び出しより混乱しにくいセマンティクスが好きなときはいつでも、キーを更新しようとするようです。

(私のスクリプトのセマンティクスは、memcached CASコマンドと少し異なります;これは意図的です)。

これは私の限られたテストに合格します...私は本当に潜在的な並行性/アトミック性の問題と、Luaに何か愚かなものがあるかどうかを尋ねています。

+0

グレート質問:私はあなたがターミナルにあるとき、実際にあなたがevalの中のluaスクリプトファイルを呼び出すことができます

eval "your_raw_code" key_count keys argv 

を使用していることに気づきました、完璧に提示され、あなたは完全に親和性/並行性/その他の点でOKですが、キーが文字列である限り –

答えて

0

あなたはRedis's documentationによると、原子の面で罰金になります:

Redisのは、すべてのコマンドを実行するために、同じLuaのインタプリタを使用しています。また、Redisは、スクリプトがアトミックな方法で実行されることを保証します。スクリプトの実行中に他のスクリプトやRedisコマンドは実行されません。この意味は、MULTI/EXECの意味に似ています。他のすべてのクライアントの観点から見ると、スクリプトの効果はまだ見えないか、すでに完了しているかのいずれかです。

ただし、スクリプトが遅すぎると問題が発生します。したがって、スクリプトは、いくつかの論理と原子性を必要とする軽い操作に最適です。

落ちるかもしれないもう一つの抜け穴は、途中でスクリプトが何らかの形で失敗した場合、スクリプトがエラーを返すものの、ロールバックできなかった呼び出しです。

E.G: あなたはこのようなスクリプトを持っている:

redis.call('set', 'foo', 1) 
redis.call('rpush', 'foo', 2) 

スクリプトの実行がエラーを返しますが、fooはすでに1としてのRedisに設定されています。あなたの質問に関係のない


何か:

> redis-cli eval "$(cat path/to/script/script_name.lua)" key_count keys argv 
関連する問題