EVAL と EVALSHA の違い
一連の処理を記述した lua スクリプトを redis-server に渡す事ができる。
>>> import redis >>> r = redis.StrictRedis(host='localhost', port=6379, db=0) >>> increment = 'return redis.call("INCR", KEYS[1])' >>> ret = r.execute_command('EVAL', increment, 1, ['foo']) >>> print ret 1
MySQL のストアドプロシージャのように一連の処理を redis-server に予め登録する事もできる。 LOAD した際に sha1 が返されるのでそれを使えばいい
>>> sha1 = r.execute_command('SCRIPT', 'LOAD', increment, parse="LOAD") >>> print sha1 f793247de6e1e3c553cd42d39c812df499e679e4 >>> ret = r.execute_command('EVALSHA', sha1, 1, ['foo']) >>> print ret 2
lua を使ってトランザクションできるか調べる
userA が持っているお金を userB に渡す処理を考える
- user:A:money を減らす
- user:B:money を増やす
話を簡単にするために所持金が不足しているかどうかなどの問題は考えない事にします。
>>> import redis >>> r = redis.StrictRedis(host='localhost', port=6379, db=0) >>> r.set('user:A:money', 1000) >>> r.set('user:b:money', 1000)
以下の2つのコマンドを lua で一連の処理単位(トランザクション)にしたい
>>> r.decr('user:A:money', 100) 900 >>> r.incr('user:B:money', 100) 1100
Python と Lua で書くとこうなる
>>> give_money = ''' local x = redis.call('DECRBY', KEYS[1], ARGV[1]) local y = redis.call('INCRBY', KEYS[2], ARGV[1]) return {KEYS[1], x, KEYS[2], y} ''' >>> print r.execute_command('EVAL', give_money, 2, 'user:A:money', 'user:B:money', 100) ['user:A:money', 900L, 'user:B:money', 1100L] >>> print r.execute_command('EVAL', give_money, 2, 'user:A:money', 'user:B:money', 100) ['user:A:money', 800L, 'user:B:money', 1200L]
redis-cluster では?
直接 redis-cli でやってみる。個別に処理する事は可能だった。
% redis-cli -c -p 7000 127.0.0.1:7000> set 'user:A:money' 1000 -> Redirected to slot [6288] located at 127.0.0.1:7001 OK 127.0.0.1:7001> set 'user:B:money' 1000 -> Redirected to slot [18] located at 127.0.0.1:7000 OK
もしかしてとか思ったけどやっぱりこうなった
127.0.0.1:7000> EVAL "redis.call('DECRBY', KEYS[1], ARGV[1]);redis.call('INCRBY', KEYS[1], ARGV[1]);" 2 'user:A:money' 'user:B:money' 100 (error) CROSSSLOT Keys in request don't hash to the same slot