内容大纲
redis 里只用 eval 和 evalsha
redis 管理 Lua 脚本
php 里使用 redis 的 lua 脚本
在 redis 里使用 lua 脚本的好处
1.Lua 脚本在 Redis 中是原子执行的, 执行过程中间不会插入其他命令
2.Lua 脚本可以帮助开发和运维人员创造出自己定制的命令, 并可以将这些命令常驻在 Redis 内存中, 实现复用的效果.
3.Lua 脚本可以将多条命令一次性打包, 有效地减少网络开销
在 redis 中
eval 的语法格式
EVAL script numkeys key [key ...] arg [arg ...]
其中:
- <1> script: 你的 lua 脚本
- <2> numkeys: key 的个数
- <3> key: redis 中各种数据结构的替代符号
- <4> arg: 你的自定义参数
- eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 username age hk 20
第一个参数的字符串是 script, 也就是 lua 脚本, 2 表示 keys 的个数, KEYS[1] 就是 username 的占位符, KEYS[2] 就是
age 的占位符, ARGV[1] 就是 jk 的占位符, ARGV[2] 就是 20 的占位符, 以此类推, 所以最后的结果应该就是:{return username age hk 20}
其中要要读写的键名应该作为 key 参数, 其它的数据都作为 arg 参数
eval 命令依据第二个参数将后面的所有参数分别存入脚本中 KEYS 和 ARGV 两个表类型的全局变量.
当脚本不需要任何参数时也不能省略这个参数 (设为 0)
在 cli 中执行
- 250:0>eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 username age hk 20
- 1) "username"
- 2) "age"
- 3) "hk"
- 4) "20"
执行 Lua 脚本文件
redis-cli --eval keys.lua k1 k2 , v1 v2
key 和 value 用一个逗号隔开
- keys.lua
- return {
- KEYS,
- type(KEYS),
- '-----',
- ARGV,
- type(ARGV)
- }
- [root@centos1 lua]# redis-cli --eval keys.lua k1 k2 , v1 v2
- 1) 1) "k1"
- 2) "k2"
- 2) "table"
- 3) "-----"
- 4) 1) "v1"
- 2) "v2"
- 5) "table"
- evalsha
将 Lua 脚本加载到 Redis 服务端, 得到该脚本的 sha1 校验和, evalsha 命令使用 sha1 作为参数可以直接执行对应的 Lua 脚本,
避免每次发送 Lua 脚本的开销. 这样客户端就不需要每次执行脚本内容, 而脚本也会常驻在服务端, 脚本内容得到了复用
加载脚本: script load 命令可以将脚本内容加载到 Redis 内存中
hmgetall.lua 获取多个 hash key 的值
-- 获取指定的多个 hash key
- local result={}
- for i,v in ipairs(KEYS) do
- result[i]=redis.call('HGETALL',v)
- end
- return result
- [root@centos1 redis-lua]# redis-cli script load "$(cat hmgetall.lua)"
- "032f22e507d134837f1c948f5b4f6b979b2e8beb"
得到 sha1 的值
在 redis 里执行脚本
evalsha 脚本 sha1 值 key 个数 key 列表 参数列表
evalsha 032f22e507d134837f1c948f5b4f6b979b2e8beb 2 user:1 user:2 0
- 127.0.0.1:6379> evalsha 032f22e507d134837f1c948f5b4f6b979b2e8beb 2 user:1 user:2
- 1) 1) "name"
- 2) "hk"
- 3) "age"
- 4) "20"
- 2) 1) "name"
- 2) "hk2"
- 3) "age"
- 4) "22"
Redis 管理 Lua 脚本
1.script load
此命令用于将 Lua 脚本加载到 Redis 内存中
2.script exists
scripts exists sha1 [sha1 ...]
此命令用于判断 sha1 是否已经加载到 Redis 内存中
3.script flush
此命令用于清除 Redis 内存已经加载的所有 Lua 脚本, 在执行 script flush 后, sha1 不复存在
4.script kill
此命令用于杀掉正在执行的 Lua 脚本
为了防止某个脚本执行时间过长导致 redis 无法提供服务
redis 提供 lua-time-limit 参数限制脚本的最长运行时间, 默认为 5 秒
当脚本运行超过这一限制后, redis 将开始接收其它命令但不会执行 (以确认脚本的原子性, 因为此时脚本并没有终止), 而是返回 busy 错误
打开 2 个 redis 客户端
redis A> eval "while true do end" 0
redis B 中
127.0.0.1:6379> keys *
(error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.
此时 redis 虽然可以接收任何命令, 但实际会执行的只有 2 个 SCRIPT KILL or SHUTDOWN NOSAVE
- 127.0.0.1:6379> script kill
- OK
需要注意的是 如果当执行的是修改操作, 则 SCRIPT KILL 命令不会终止脚本的运行以防止脚本只执行了一部分 (违背原子性的要求)
redis A>eval "redis.call('set','name','hk') while true do end" 0
redis B 里
127.0.0.1:6379> keys *
(error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.
127.0.0.1:6379> script kill
(error) UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in a hard way using the SHUTDOWN NOSAVE command.
此时只能 SHUTDOWN NOSAVE
SHUTDOWN NOSAVE 不会进行持久化的操作 与 SHUTDOWN 的区别
php 里使用 redis 的 lua 脚本
- lua.php
- <?php
- require "./vendor/autoload.php";
- class HMGetAll extends \Predis\Command\ScriptCommand{
- public function getKeysCount()
- {
- return false;
- }
- public function getScript(){
- return
- <<<LUA
- local result = {}
- for i ,v in ipairs(ARGV) do
- result[i] =redis.call('HGETALL',v)
- end
- return result
- LUA;
- }
- }
- $client= new \Predis\Client(
- [
- 'scheme'=>'tcp',
- 'host' => '192.168.0.250',
- 'port' => 6379,
- ]
- );
- // 定义 hmgetall 命令
- $client->getProfile()->defineCommand("hmgetall",'HMGetAll');
- var_dump($client->hgetall('user:1'));
- var_dump($client->hgetall('user:2'));
- // 执行 hmgetall
- $value=$client->hmgetall('user:1','user:2');
- var_dump($value);
结果类似
- D:\wamp64\www\cnblogs\lua\php\lua.php:32:
- array (size=2)
- 'name' => string 'hk' (length=2)
- 'age' => string '20' (length=2)
- D:\wamp64\www\cnblogs\lua\php\lua.php:33:
- array (size=2)
- 'name' => string 'hk2' (length=3)
- 'age' => string '22' (length=2)
- D:\wamp64\www\cnblogs\lua\php\lua.php:37:
- array (size=2)
- 0 =>
- array (size=4)
- 0 => string 'name' (length=4)
- 1 => string 'hk' (length=2)
- 2 => string 'age' (length=3)
- 3 => string '20' (length=2)
- 1 =>
- array (size=4)
- 0 => string 'name' (length=4)
- 1 => string 'hk2' (length=3)
- 2 => string 'age' (length=3)
- 3 => string '22' (length=2)
- View Code
参考 redis 入门指南 (书中这块有错误 应该是 ARGV 而不是循环 KEYS)
详细代码见 https://gitee.com/hk/cnblogs/tree/master/lua/php
来源: https://www.cnblogs.com/HKUI/p/9251110.html