前言

简单介绍一下Lua。

正文

为了保证多条命令组合的原子性,Redis提供了简单的事务功能以及集 成Lua脚本来解决这个问题。

前面提及到pipline,也提及到pipline 并不是原子性的,如果多条命令想达到一定的原子性怎么破呢?

多条语句达到原子性,一般而言,我们想到的会是事务。

简单地说,事务表示一 组动作,要么全部执行,要么全部不执行。

Redis提供了简单的事务功能,将一组需要一起执行的命令放到multi和 exec两个命令之间。multi命令代表事务开始,exec命令代表事务结束,它们之间的命令是原子顺序执行的。

multi命令代表事务开始,exec命令代表事务结束,它们之间的命令是原子顺序执行的。

这里需要解释一下?

前面的pipline是不是原子性的,为什么这么说呢? 因为前面pipline 也是将加入队列,但是不能保证原子性。

如果要停止事务的执行,可以使用discard命令代替exec命令即可。

如果事务中的命令出现错误,Redis的处理机制也不尽相同。

这是我们开发需要关注的地方。

  1. 命令错误,这是比较幸运的错误。

整个事务是不会去执行的,这种错误还是比较好解决。

  1. 运行时候错误

就是说运行了第1、2条,然后第3条出错,或者写错了。

可以看到Redis并不支持回滚功能,sadd user:a:follow user:b命令已 经执行成功,开发人员需要自己修复这类问题。

同样即使我们没有发生错误,那么事务也是可能有问题的。

思考一下mysql 有几种情况发生,什么不可重复读等。

这些都是锁的问题,那么就看一下redis里面的锁吧。

有些应用场景需要在事务之前,确保事务中的key没有被其他客户端修 改过,才执行事务,否则不执行(类似乐观锁)。

Redis提供了watch命令来 解决这类问题。

下面执行一下下面的流程,看下变化。

然后你发现该事务没有执行成功。

也就是说一但watch有变化,那么执行就不会进行下去。

Redis提供了简单的事务,之所以说它简单,主要是因为它不支持事务 中的回滚特性,同时无法实现命令之间的逻辑关系计算,当然也体现了 Redis的“keep it simple”的特性.

Lua语言提供了如下几种数据类型:booleans(布尔)、numbers(数 值)、strings(字符串)、tables(表格),和许多高级语言相比,相对简 单。下面将结合例子对Lua的基本数据类型和逻辑处理进行说明

https://www.runoob.com/lua/lua-tutorial.html

上面可以去看看,很快就能学会。

那么看下Lua语言对redis的处理。

  1. 看下在redis中如何执行Lua语言。

在Redis中执行Lua脚本有两种方法:eval和evalsha。

eval 脚本内容 key个数 key列表 参数列表

除了使用eval,Redis还提供了evalsha命令来执行Lua脚本。

首先要将Lua脚本加载到Redis服务端,得到该脚本的SHA1校验和, evalsha命令使用SHA1作为参数可以直接执行对应Lua脚本,避免每次发送 Lua脚本的开销。这样客户端就不需要每次执行脚本内容,而脚本也会常驻 在服务端,脚本功能得到了复用。

加载脚本:script load命令可以将脚本内容加载到Redis内存中,例如下 面将lua_get.lua加载到Redis中,得到SHA1 为:"7413dc2440db1fea7c0a0bde841fa68eefaf149c"

执行脚本:evalsha的使用方法如下,参数使用SHA1值,执行逻辑和 eval一致。

有点像存储过程。

Lua的Redis API:

Lua可以使用redis.call函数实现对Redis的访问,例如下面代码是Lua使用 redis.call调用了Redis的set和get操作:

redis.call("set", "hello", "world") redis.call("get", "hello")
eval 'return redis.call("get", KEYS[1])' 1 hello "world"

除此之外Lua还可以使用redis.pcall函数实现对Redis的调用,redis.call和 redis.pcall的不同在于,如果redis.call执行失败,那么脚本执行结束会直接返 回错误,而redis.pcall会忽略错误继续执行脚本,所以在实际开发中要根据 具体的应用场景进行函数的选择。

开发提示:

Lua可以使用redis.log函数将Lua脚本的日志输出到Redis的日志文件中, 但是一定要控制日志级别。 Redis3.2提供了Lua Script Debugger功能用来调试复杂的Lua脚本,具体 可以参考:http://redis.io/topics/ldb。

案例

Lua脚本功能为Redis开发和运维人员带来如下三个好处:

·Lua脚本在Redis中是原子执行的,执行过程中间不会插入其他命令。

·Lua脚本可以帮助开发和运维人员创造出自己定制的命令,并可以将这 些命令常驻在Redis内存中,实现复用的效果。

·Lua脚本可以将多条命令一次性打包,有效地减少网络开销。

案例:

实现:

管理Lua 脚本

Redis提供了4个命令实现对Lua脚本的管理,下面分别介绍。

  1. script load script

  2. script exists

此命令用于判断sha1是否已经加载到Redis内存中.

script exists a5260dd66ce02462c5b5231c727b3f7772c0bcc5

这样就说明没有被加载进去。

  1. script flush

此命令用于清除Redis内存已经加载的所有Lua脚本

  1. script kill

此命令用于杀掉正在执行的Lua脚本。如果Lua脚本比较耗时,甚至Lua 脚本存在问题,那么此时Lua脚本的执行会阻塞Redis,直到脚本执行完毕或 者外部进行干预将其结束。

模拟一下。

eval 'while 1==1 do end' 0

Redis提供了一个lua-time-limit参数,默认是5秒,它是Lua脚本的“超时 时间”,但这个超时时间仅仅是当Lua脚本时间超过lua-time-limit后,向其他 命令调用发送BUSY的信号,但是并不会停止掉服务端和客户端的脚本执 行,所以当达到lua-time-limit值之后,其他客户端在执行正常的命令时,将 会收到“Busy Redis is busy running a script”错误,并且提示使用script kill或者 shutdown nosave命令来杀掉这个busy的脚本

此时Redis已经阻塞,无法处理正常的调用,这时可以选择继续等待, 但更多时候需要快速将脚本杀掉。使用shutdown save显然不太合适,所以选 择script kill,当script kill执行之后,客户端调用会恢复.

那么kill 是否一定能成功呢? 不一定。

有一点需要注意,如果当前Lua脚本正在执行写操作,那么script kill将不会生效。

上面提示Lua脚本正在向Redis执行写命令,要么等待脚本执行结束要么 使用shutdown save停掉Redis服务。可见Lua脚本虽然好用,但是使用不当破 坏性也是难以想象的。

这种算是灾难模式。

下一节bitmaps,这个还是比较关键的,二进制存储,很多业务上需要。

redis 简单整理——Lua[十一]的更多相关文章

  1. Redis进阶实践之十九 Redis如何使用lua脚本

    一.引言               redis学了一段时间了,基本的东西都没问题了.从今天开始讲写一些redis和lua脚本的相关的东西,lua这个脚本是一个好东西,可以运行在任何平台上,也可以嵌入 ...

  2. Redis知识整理

    Redis知识整理 转自:https://www.cnblogs.com/rjzheng/p/9096228.html 1.单线程模型 Redis客户端对服务端的每次调用都经历了发送命令,执行命令,返 ...

  3. 新姿势!Redis中调用Lua脚本以实现原子性操作

    背景:有一服务提供者Leader,有多个消息订阅者Workers.Leader是一个排队程序,维护了一个用户队列,当某个资源空闲下来并被分配至队列中的用户时,Leader会向订阅者推送消息(消息带有唯 ...

  4. Redis中的原子操作(2)-redis中使用Lua脚本保证命令原子性

    Redis 如何应对并发访问 使用 Lua 脚本 Redis 中如何使用 Lua 脚本 EVAL EVALSHA SCRIPT 命令 SCRIPT LOAD SCRIPT EXISTS SCRIPT ...

  5. .NET Web开发技术简单整理

    在最初学习一些编程语言.一些编程技术的时候,做的更多的是如何使用该技术,如何更好的使用该技术解决问题,而没有去关注它的相关性.关注它的理论支持,这种学习技术的方式是短平快.其实工作中有时候也是这样,公 ...

  6. [redis] session 保存到 redis 简单实现

    参考资料: [session保存到redis简单实现]http://blog.csdn.net/ppt0501/article/details/46700221 [Redis学习]http://blo ...

  7. 转载:.NET Web开发技术简单整理

    在最初学习一些编程语言.一些编程技术的时候,做的更多的是如何使用该技术,如何更好的使用该技术解决问题,而没有去关注它的相关性.关注它的理论支持,这种学习技术的方式是短平快.其实工作中有时候也是这样,公 ...

  8. Java中Redis简单入门

    Redis是一个开源的,先进的 key-value 存储可用于构建高性能,可扩展的 Web 应用程序的解决方案. Redis官方网网站是:http://www.redis.io/,如下: Redis ...

  9. MYBATIS 简单整理与回顾

    这两天简单整理了一下MyBatis 相关api和jar包这里提供一个下载地址,免得找了 链接:http://pan.baidu.com/s/1jIl1KaE 密码:d2yl A.简单搭建跑项目 2.进 ...

  10. 哪些CSS是可以被继承的--简单整理

    那些CSS是可以被继承的--简单整理1.文本相关属性是继承的:font-size,font-family,line-height,text-index等2.列表相关属性是继承的:list-style- ...

随机推荐

  1. 新零售SaaS架构:订单履约系统架构设计(万字图文总结)

    什么是订单履约系统? 订单履约系统用来管理从接收客户订单到将商品送达客户手中的全过程. 它连接了上游交易(客户在销售平台下单环)和下游仓储配送(如库存管理.物流配送),确保信息流顺畅.操作协同,提升整 ...

  2. CPNtools协议建模安全分析---实例(三)

    对于复杂的系统的建模或者协议的建模,各种颜色集的定义以及变量的声明很重要,要区分明确,对于函数行业进程的定义更加复杂.CPN对协议的描述只适合简单逻辑性的协议分析,如果协议包括复杂的算法,那么CPN就 ...

  3. 文心一言 VS 讯飞星火 VS chatgpt (210)-- 算法导论16.1 1题

    一.根据递归式(16.2)为活动选择问题设计一个动态规划算法.算法应该按前文定义计算最大兼容活动集的大小 c[i,j]并生成最大集本身.假定输入的活动已按公式(16.1)排好序.比较你的算法和GREE ...

  4. Spring事务(五)-事务隔离级别

    Spring @Transactional注解isolation属性 @Transactional注解通过isolation属性设置事务隔离级别.如下: @Transactional(isolatio ...

  5. Failed to execute goal on project WebBackend: Could not resolve dependencies for project com.lang.yi:WebBackend:jar:1.0.0

    一.问题由来 自己在搭建项目的时候报一个错误,如标题所示,具体错误信息如下: Failed to execute goal on project WebBackend: Could not resol ...

  6. 2层for循环生成 TreeView

    C# TreeView 利用2层for循环生成,代码如下: //生成树 treeView1.Nodes.Clear(); //封装了数据库查询方法 MyDS_Grid = MyDataClass.ge ...

  7. epoll反应堆理解

    https://www.aliyundrive.com/s/oBvP7BcjsCS https://blog.csdn.net/weixin_36750623/article/details/8354 ...

  8. django(cookie与session、中间件、auth模块)

    一 cookie与session 1 发展史及简介 """ 发展史 1.网站都没有保存用户功能的需求,所有用户访问返回的结果都是一样的 eg:新闻.博客.文章 2.出现了 ...

  9. Python配置文件使用教程

    在 Python 应用程序开发过程中,配置文件扮演着重要的角色.配置文件可以用来存储应用程序的各种设置.选项和参数,使得程序更加灵活和可配置.本文将介绍 Python 中如何使用配置文件,并提供一些常 ...

  10. 记录--vue组件划分的思考

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 对vue项目来说,组件是构成项目的基本单元,为了方便理解,这里定义两类组件:页面组件,功能组件.为什么需要划分这两类组件是从组件复用来考虑 ...