Redis脚本使用总结

Redis脚本使用总结:

Redis 2.6.0开始支持对lua脚本的解析运行,使用内置的lua解析器,就可以对lua脚本进行求值运算。至于lua本身详细的总结介绍,请留意后续关于lua专门的文章总结,这里只做lua在Redis中的使用分析总结介绍,并在结合前面文章的例子说明。

 

·     关于lua

·     几个命令

·     类型转换

·     通信协议

·     例子验证

·     注意事项

 

1、关于lua

参考博文《Lua安装及使用总结》

http://blog.csdn.net/why_2012_gogo/article/details/51298226

 

2、几个命令

在Redis中,单单只提供lua的解析是不够的,还需要除了解析编译之外的lua脚本的求值和逻辑处理功能,所以下面的EVAL及相关的命令是必须要知道的:

命令

作用

EVAL

对缓存在服务器中的脚本进行求值。

EVALSHA

根据SHA1校验码,对缓存在服务器中的脚本进行求值运算。

SCRIPT EXISTS

根据脚本的校验码,检测指定的脚本是否存在于脚本缓存中。

SCRIPT FLUSH

清除所有脚本缓存。

SCRIPT KILL

关闭或杀死当前运行的脚本。

SCRIPT LOAD

将脚本加载入脚本缓存,但不立即运行。

 

EVAL与EVALSHA区别:

EVAL命令会在每次执行脚本的时候都发送一次脚本主体,它不会每次都重新编译,但是很多时候它付出了无必要的带宽来传递主体;而EVALSHA命令,它的作用与EVAL相同,但是它解决上面EVAL的带宽消耗,也就是它接受的第一个参数不是脚本而是脚本的SHA1校验和SUM。

 

NOTE:

A、如果服务器还存在给定的 SHA1 校验和所指定的脚本,那么就执行这个脚本;如果服务器不存在给定的 SHA1 校验和所指定的脚本,那么它返回一个特殊的错误:提醒用户使用 EVAL 代替 EVALSHA。

B、KEYS和ARGV:

EVAL的第一个参数是Lua脚本程序,它运行在 Redis 服务器中;

EVAL的第二个参数是参数的个数,后面的参数(从第三个参数),表示在脚本中所用到的那些 Redis 键,这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,…);

在命令的最后,那些不是键名参数的附加参数 arg [arg …] ,可以在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1]、ARGV[2],…)。

例如:

> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 mykey

 

3、类型转换

在Redis中使用lua,那么讨论的数据类型转换自然就是在Redis和lua之间转换了。当Lua通过call()或pcall()函数执行Redis命令时,命令的返回结果被转换为Lua数据结构;而Lua在Redis内置解析器中运行时,Lua脚本返回值被转换为Redis协议,然后由EVAL将处理的结果返回给客户端处理(需要时,可直接参考转换)。

A、Redis与Lua转换对照表(存在对应关系)

Redis

Lua

integer

number

bulk

string

multi bulk

table

status

table中状态信息ok

error

table中状态信息err

nil bulk/multi bulk

false

 

B、Lua到Redis换转对照表(不存在对应关系)

Lua

Redis

true

1

 

 

 

 

Lua中的boolean值true到 Redis中的integer值为1;

 

NOTE:

Lua中整数和浮点数之间没有区别。所以,我们始终将Lua的数字转换成整数的回复,这样将舍去小数部分。如果就是希望Lua返回一个浮点数,那么应该将它作为一个字符串,比如ZSCORE命令。

 

4、通信协议

Redis基于C/S通信机制,也就是需要在客户端和Redis服务端交互通信,而大多的C/S通信是需要通信协议的约束,而Redis与外部的通信也不例外。

A、\r\n结尾

客户端与服务端交互的每一个命令及数据都必须以\r\n结尾,这只是规定没有需要特别的说明。

 

B、通用格式

*<number of arguments>

$<number of bytes of argument 1>

<argument data>

$<number of bytes of argument n>

<argument data>

 

例如:

"*2\r\n$3\r\nSET\r\n$5\r\nmykey\r\n"

 

5、例子验证

1)例子一:

同步Mysql数据到Redis的sql脚本为例说明,这里使用了管道技术,目的只为提高效率,对于管道的内容可查看资料,推荐如下:

博文:《Redis管道技术使用总结》,

博客地址:http://blog.csdn.net/why_2012_gogo/article/details/51260264

 

A、.sql脚本

SELECT CONCAT(

'*14\r\n',

'$',LENGTH(redis_cmd),'\r\n',redis_cmd,'\r\n',

'$',LENGTH(redis_key),'\r\n',redis_key,'\r\n',

'$',LENGTH(id_key),'\r\n',id_key,'\r\n','$',LENGTH(id_val),'\r\n',id_val,'\r\n',

'$',LENGTH(account_key),'\r\n',account_key,'\r\n','$',LENGTH(account_val),'\r\n',account_val,'\r\n',

'$',LENGTH(password_key),'\r\n',password_key,'\r\n','$',LENGTH(password_val),'\r\n',password_val,'\r\n',

'$',LENGTH(nickname_key),'\r\n',nickname_key,'\r\n','$',LENGTH(nickname_val),'\r\n',nickname_val,'\r\n',

'$',LENGTH(email_key),'\r\n',email_key,'\r\n','$',LENGTH(email_val),'\r\n',email_val,'\r\n',

'$',LENGTH(address_key),'\r\n',address_key,'\r\n','$',LENGTH(address_val),'\r\n',address_val,'\r'

)

FROM(

SELECT

'HMSET' AS redis_cmd,CONCAT(account,password,'_hash') AS redis_key,

'id' AS id_key,id AS id_val,

'account' AS account_key,account AS account_val,

'password' AS password_key,password AS password_val,

'nickname' AS nickname_key,nickname AS nickname_val,

'email' AS email_key,email AS email_val,

'address' AS address_key,address AS address_val

FROM t_user_info

) AS t

 

B、如何运行

$mysql  -h 127.0.0.1  -uroot –Dcwteam  --skip-column-names  --raw <

/redis/sql/mysql_to_redis.sql | redis-cli -eval

/redis/lua/redis_table_json.lua --pipe

 

 

NOTE:

.sql->实现查询内容Redis协议化,并组装获得数据集;

.lua->使用cjson依赖库,实现查询结果json格式化;

-eval->执行并计算lua脚本求值;

--pipe->代表启用了管道技术支持;

 

C、.lua脚本

for k,v in pairs(ok) do

for key,val in pairs(v) do

if key%2 == 0 then

tmp[v[key-1]] = v[key];

end

end

ret[k]=tmp;

end

ngx.say(cjson.encode(ret));

 

NOTE:

最后一行通过ngx.say()函数,调用cjson依赖库的encode()将前面的json数组转为json格式数据并返回给Redis服务端。

 

2)例子二:

利用Redis的高效的I/O特点,实现固定时间内,限制客户端访问服务端次数,目的是为了防止客户端非法刷新或恶意攻击网站等用途。

 

A、.lua脚本

local cells = redis.call('incr',KEYS[1])

if cells == 1 then

  redis.call('expire',KEYS[1],ARGV[1])

end

if cells > tonumber(ARGV[2]) then

   return 0

end

return 1

 

NOTE:

KEYS->获取键名参数,这里指incr的值;

ARGV->获取非键名参数,这里指访问的次数;

call()和pcall()区别:

call()和pcall()很类似,唯一的区别是redis命令执行结果返回错误时,redis.call()将返回给调用者一个错误;而pcall()会将捕获的错误以Lua表的形式返回。

 

B、如何运行

$redis-cli  --eval  /redis/lua/cell_limiting.lua  cell_limiting:127.0.0.1, 5 2

 

NOTE:

--eval代表通知redis-cli使用eval命令调用脚本;

/redis/lua/cell_limiting.lua为.lua文件的位置;

cell_limiting:127.0.0.1代表模拟的访问ip地址动作;

5 2 代表5秒之内只允许访问2次;

 

结果:

正如上图所示,如果5秒内访问的次数小于等于2次,则返回1,否则返回0,捕获到0这个状态之后,我们就可以做出对应的解决办法了。

 

6、注意事项

A、全局变量

为了防止数据泄漏进Lua环境,Redis 脚本不允许创建全局变量。如果一个脚本需要在多次执行之间维持某种状态,应该使用Redis key来进行状态保存。如果试图在脚本中访问一个全局变量(不论这个变量是否存在)将引起脚本停止。

 

NOTE:

为了防止这个问题,这里有个好的建议:将脚本中用到的所有变量,都使用local关键字显式的声明为局部变量,这也是个好的习惯。

 

B、脚本缓存

Redis保证所有被运行过的脚本都会被永久保存在脚本缓存当中,当EVAL 命令在一个 Redis实例上成功执行某个脚本后,针对这个脚本的所有EVALSHA命令都会成功执行。

 

另外,刷新脚本缓存的唯一办法是显式调用SCRIPTFLUSH 命令,这个命令会清空运行过的所有脚本的缓存,通常只有在云计算环境中,Redis 实例被改作其他客户或者别的应用程序的实例时,才会执行这个命令。

 

缓存可以长时间储存而不产生内存问题的原因是,它们的体积非常小,而且数量也非常少,即使脚本在概念上类似于实现一个新命令,或者在一个大规模程序里有成百上千的脚本,即使这些脚本会经常修改,储存这些脚本的内存仍然是微不足道的。实际上,用户会发现 Redis 不移除缓存中的脚本是一个好的设计。因为对于一个和 Redis 保持持久化连接的程序来说,执行过一次的脚本会一直保留在内存中,因此它可以在管道中使用 EVALSHA 命令而不必担心因为找不到所需的脚本而产生错误。

 

 

好了,到这里已经介绍了Redis实际使用中的方方面面,如有新的发现和总结会在后续文章迭代更新博文,谢谢。

 

 

技术讨论群:

489451956(新)

 

 

 

 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
在OpenResty中使用Redis的过程是通过Lua脚本来实现的。首先,需要进行准备工作,确保OpenResty和Redis环境的配置正确。OpenResty主要用于解决高并发问题,而为了避免数据库成为高并发的瓶颈,操作Redis变得不可避免。 如果对OpenResty不太了解,可以参考相关文章进行学习。在Windows系统下,可以使用ZeroBrane Studio进行开发和调试OpenResty代码。 在使用OpenResty操作Redis之前,需要将相关的代码添加到配置文件中。具体的配置数据可以根据自己的Redis数据库情况进行修改。配置文件中包含了连接信息、超时时间以及Redis的库等信息。 在使用OpenResty时,可以根据具体的需求和场景,编写Lua脚本来操作Redis,实现数据的读取、写入和删除等操作。通过调用相关的Redis命令,可以实现与Redis的交互。 总结来说,OpenResty中使用Redis的过程是通过Lua脚本Redis进行交互,通过配置文件设置Redis的连接信息和相关参数,然后根据需求编写Lua脚本来操作Redis中的数据。这样可以有效地解决高并发问题并提升系统性能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [OpenResty高并发最佳实践--Redis操作](https://blog.csdn.net/lupengfei1009/article/details/86160652)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云水之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值