协会网站建设计划书,阿里巴巴代加工平台,注册网站在哪里注册,电子商务网站建设商城网站文章目录一.引言二.eval简介三.lua数据类型和redis数据类型之间转换四.脚本的原子性五.错误处理六.纯函数脚本七.选择内部脚本一.引言
eval和evalsha命令使用内置的lua解释器#xff0c;可以对lua脚本进行求值。
二.eval简介
第一个参数是一段脚本程序第二个参数是参数的个…
文章目录一.引言二.eval简介三.lua数据类型和redis数据类型之间转换四.脚本的原子性五.错误处理六.纯函数脚本七.选择内部脚本一.引言
eval和evalsha命令使用内置的lua解释器可以对lua脚本进行求值。
二.eval简介
第一个参数是一段脚本程序第二个参数是参数的个数后面的参数表示脚本中所用到的那些redis键这些键名参数可以在lua中通过全局变量KEYS数据以1为基址的形式访问KEYS[1],KEYS[2]…。那些不是键名的附加参数ARGV[],可以在lua中通过全局变量ARGV数组访问访问的形式和KEYS变量类似(ARGV[1],ARGV[2]…)
注意eval命令所有键都应该由KEYS数组来传递因为不仅仅是eval命令所有的redis命令在执行之前都会被分析借此来确定命令会对哪些键进行操作。对于eval命令来说必须使用正确的形式来传递键才能确保分析工作正确地执行。而且可以确保redis集群可以将你的请求发送到正确的集群节点。
例如
127.0.0.1:6379 eval return {KEYS[1],ARGV[1]} 1 foo bar
1) foo
2) bar返回结果是redis multi bulk replies的lua数组这是一个redis的返回类型您的客户端可能会将他们转换成数组类型
lua脚本中使用lua函数调用redis命令的例子
redis.call()redis.pcall()
两种方式的区别当reis命令执行结果返回错误是redis.call()将返回给调用者一个错误而redis.pcall()会将捕获的错误以lua表的形式返回。
三.lua数据类型和redis数据类型之间转换
当lua通过call()或pcall()函数执行redis命令的时候命令的返回值会被转换成lua数据结构。同样地当lua脚本在redis内置的解释器里运行时lua脚本的返回值也会被转换成reids协议然后由eval将值返回给客户端。
数据类型转换之间遵循这样一个设计原则将一个redis值转换成lua值之后再将转换所得的lua值转换回redis值那么这个转换所得的redis值应该和最初的redis值一样。
redis-lua:
redis integer reply - lua numberredis bulk reply - lua stringredis multi bulk reply - lua tableredis status reply - lua table with a single err field containing the errorredis error reply - lua table with a single err field containing the errorredis nil reply and nil multi bulk reply - lua false boolean type
lua-redis:
lua number - redis integer replylua string - redis bulk replylua table - redis multi bulk replylua table with a single ok field - redis status replylua table with a single err field - redis error replylua boolean false - redis nil bulk reply
特殊lua-redis转换:
redis boolean true - redis integer reply with value of 1
注意
lua中整数和浮点数之间没有任何区别。因此我们如果将lua的数字转换成整数的回复这样将舍去小数部分。如果想从lua返回一个浮点数你应该将它视作一个字符串。nil 作为一个回复的结束后面的值将不会被返回
例子 eval return {1,2,{3,Hello World!}} 0
1) (integer) 1
2) (integer) 2
3) 1) (integer) 32) Hello World! eval return redis.call(get,foo) 0
bar eval return {1,2,3.3333,foo,nil,bar} 0
1) (integer) 1
2) (integer) 2
3) (integer) 3
4) foo四.脚本的原子性
redis使用单个lua脚本解释器去运行所有脚本并且redis也播啊这呢个脚本会以原子性的方式执行当某个脚本正在运行的时候不会有其他脚本或者redis命令被执行。这和使用MULTI/EXEC包围的事物很类似。在其他客户端看来脚本的效果只能是不可见或是已完成。要注意慢脚本的问题一个蜗牛脚本执行是其他客户端会因为服务器正忙而无法执行命令。
五.错误处理 当redis.call()在执行命令的过程中发生错误时脚本会停止执行并返回一个脚本错误 del foo
(integer) 1lpush foo a
(integer) 1eval return redis.call(get,foo) 0
(error) ERR Error running script (call to f_6b1bf486c81ceb7edf3c093f4c48582e38c0e791): ERR Operation against a key holding the wrong kind of value和redis.call()不同redis.pcall()出错时并不引发错误而是返回一个带err域的lua表用于表示错误 redis 127.0.0.1:6379 EVAL return redis.pcall(get, foo) 0
(error) ERR Operation against a key holding the wrong kind of value六.纯函数脚本
脚本应该被写成纯函数脚本。脚本应该具有以下属性
对于同样的数据集输入给定相同的参数脚本的redis写命令总是相同的。脚本执行的操作不能依赖于任何吟唱非显式数据不能依赖于脚本在执行过程中、或在不同执行时间之间可能变更的状态并且也不能依赖于任何来自IO设备的外部输入。
使用系统时间调用randomkey那样的随机命令或者使用lua的随机数生成器渴死以上的这些操作都会遭整脚本的求值无法每次都得出同样的结果。为了保证上述脚本的属性redis做了以下工作
lua没有方位系统时间或者其他内部状态的命令执行随机命令randomkeytime时redis会返回一个错误阻止这样的脚本运行lua脚本中调用哪些返回无序元素的命令时执行命令所得的数据在返回给lua之前会先执行一个静默的字典排序。如调用redis.call(“smembers”, KEYS[1]) 返回的总是排过序的元素对lua的伪随机数生成函数math.random,math.randomseed进行修改使得每次在运行新脚本的时候总是拥有同样的seed值。者意味着每次运行脚本是只要不使用math。randomseed那么math.random产生的随机数序列总是相同的
为了防止不必要的数据泄漏进lua环境redis脚本不允许创建全局变量。如果一个脚本需要在多次执行之间维持某种状态它应该使用reids key来进行状态保存企图在脚本中访问一个全局变量将引起脚本停止eval命令会返回一个错误。
七.选择内部脚本
lua脚本之影响脚本本身的执行但不修改当前客户端调用脚本时选定的数据库。
可用库 base lib table lib string lib math lib debug lib struct lib 拆装箱处理 127.0.0.1:6379 eval return struct.pack(HH, 1, 2) 0
\x01\x00\x02\x00
127.0.0.1:6379 eval return {struct.unpack(HH, ARGV[1])} 0 \x01\x00\x02\x00
1) (integer) 1
2) (integer) 2
3) (integer) 5
127.0.0.1:6379 eval return struct.size(HH) 0
(integer) 4cjson lib json处理 redis 127.0.0.1:6379 eval return cjson.encode({[foo] bar}) 0
{\foo\:\bar\}
redis 127.0.0.1:6379 eval return cjson.decode(ARGV[1])[foo] 0 {\foo\:\bar\}
barcmsgpack lib 简单快速的message pack操纵 127.0.0.1:6379 eval return cmsgpack.pack({foo, bar, baz}) 0
\x93\xa3foo\xa3bar\xa3baz
127.0.0.1:6379 eval return cmsgpack.unpack(ARGV[1]) 0 \x93\xa3foo\xa3bar\xa3baz
1) foo
2) bar
3) bazbittop lib 为lua位运算模块增加了按位操作数 127.0.0.1:6379 eval return cmsgpack.pack({foo, bar, baz}) 0
\x93\xa3foo\xa3bar\xa3baz
127.0.0.1:6379 eval return cmsgpack.unpack(ARGV[1]) 0 \x93\xa3foo\xa3bar\xa3baz
1) foo
2) bar
3) bazredis.sha1hex function