前言
redis在2.6之后推出了脚本功能. 允许开发者使用lua语言编写的脚本上传到redis中运行.在执行的过程中可以调用大部分的redis命令.
好处
使用脚本的好处:
- 减少网络开销:
如果按照我们正常编写客户端代码, 比如py, 执行的时候就是向redis服务发送了多次请求命令, 但是如果使用脚本, 就只需要发送一次请求就好了, 减少网络延迟 - 原子操作:
redis会将整个脚本作为一个整体执行. 中间不会被别的命令插入, 所以无需使用事务. - 复用:
客户端发送的脚本会永久的存在redis中, 所以可以被复用(其他语言也可以)
lua脚本
lua是一个高效的轻量级脚本语言. 能方便的嵌入到其他的语言这种
lua的特性
- 轻量级:
标准c编写, 并以源代码形式开放. 编辑后仅仅一百余K, 方便嵌入到其他的程序中 - 可扩展:
Lua提供了非常易于使用的扩展接口和机制:由宿主语言(通常是C或C++)提供这些功能,Lua可以使用它们,就像是本来就内置的功能一样。 - 其他:
- 支持面向过程(procedure-oriented)编程和函数式编程(functional programming);
- 自动内存管理;只提供了一种通用类型的表(table),用它可以实现数组,哈希表,集合,对象;
- 语言内置模式匹配;闭包(closure);函数也可以看做一个值;提供多线程(协同进程,并非操作系统所支持的线程)支持;
- 通过闭包和table可以很方便地支持面向对象编程所需要的一些关键机制,比如数据抽象,虚函数,继承和重载等。
lua应用场景
- 游戏开发
- 独立应用脚本
- web应用脚本
- 扩展和数据库插件
- 安全系统
语法
数据类型
lua是动态类型语言, 和Python一样
变量
lua变量分为全局变量和局部变量. 全局变量不需要声明就可以直接使用, 默认值是nil1
2
3a = 1 # 全局变量a赋值
print (b) # 无需声明就可以使用, 打印nil
a = nil # 删除全局变量就是将其赋值为nil
在redis中不允许使用全局变量, 只允许使用局部变量防止脚本之间的互相影响
局部变量使用local声明:1
2
3local c
local d = 1
local e, f
声明一个局部函数:1
2
3local say_ho = function()
print 'hi'
end
局部函数的作用域从声明的时候开始到所在层的语句块末尾, 比如:1
2
3
4
5
6
7
8
9
10
11local x = 10
if true then:
local x = x + 1
print(x)
do
local x = x +1
print(x)
end
print(x)
end
print(x)
结果是这样的:1
2
3
411
12
11
10
注释
单行: –
多行: –[[开始, 到]]结束
赋值
可以多重赋值
操作符
if语句
注意: 只有遇到nil和false才是假
循环
支持 while, repeat, for
while
1
2
3while (条件) do
语句块
dorepeat
1
2
3repeat
语句块
until 条件表达式for
1
2
3for 变量=初值, 终值, 步长 do
语句块
end
步长可以省略
表类型
表是lua中唯一的数据结构
其实就可以理解为python中的dict或者java中的map
函数
1 | --[[ 函数返回两个值的最大值 --]] |
标准库
lua标准库提供了一些实用的函数
redis和lua
编写redis脚本的目的就是读写数据库
在脚本中调用redis命令
1 | redis.call('set', 'foo', 'bar') |
从脚本中返回
多数情况需要lua有返回值, 如果没有返回值, 则是nil
脚本相关命令
- eval
编写完脚本之后最重要的就是执行脚本, redis提供了eval命令可以使开发者像调用其他redis内置命令一样调用脚本.
格式是:
eval 脚本内容 key参数的数量 [key …] [arg …]
可以通过key和arg这两个参数向脚本传递数据, 比如我们实现SET命令1
return redis.call('SET', KEYS[1], ARGV[1])
现在redis-cli中调用
eval “return redis.call(‘SET’, KEYS[1], ARGV[1])” 1 foo bar
- evalsha
考虑在脚本如果比较长的情况下, 如果每次把脚本传给redis, 比较占用带宽. redis提供了evalsha命令允许开发者通过脚本内容的SHA1摘要来执行脚本