在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
前言简单介绍一下Lua。 正文为了保证多条命令组合的原子性,Redis提供了简单的事务功能以及集 成Lua脚本来解决这个问题。 前面提及到pipline,也提及到pipline 并不是原子性的,如果多条命令想达到一定的原子性怎么破呢? 多条语句达到原子性,一般而言,我们想到的会是事务。 简单地说,事务表示一 组动作,要么全部执行,要么全部不执行。 Redis提供了简单的事务功能,将一组需要一起执行的命令放到multi和 exec两个命令之间。multi命令代表事务开始,exec命令代表事务结束,它们之间的命令是原子顺序执行的。 multi命令代表事务开始,exec命令代表事务结束,它们之间的命令是原子顺序执行的。 这里需要解释一下? 前面的pipline是不是原子性的,为什么这么说呢? 因为前面pipline 也是将加入队列,但是不能保证原子性。 如果要停止事务的执行,可以使用discard命令代替exec命令即可。 如果事务中的命令出现错误,Redis的处理机制也不尽相同。 这是我们开发需要关注的地方。
整个事务是不会去执行的,这种错误还是比较好解决。
就是说运行了第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的处理。
在Redis中执行Lua脚本有两种方法:eval和evalsha。
除了使用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操作:
除此之外Lua还可以使用redis.pcall函数实现对Redis的调用,redis.call和 redis.pcall的不同在于,如果redis.call执行失败,那么脚本执行结束会直接返 回错误,而redis.pcall会忽略错误继续执行脚本,所以在实际开发中要根据 具体的应用场景进行函数的选择。 开发提示:
案例Lua脚本功能为Redis开发和运维人员带来如下三个好处: 案例: 实现: 管理Lua 脚本Redis提供了4个命令实现对Lua脚本的管理,下面分别介绍。
此命令用于判断sha1是否已经加载到Redis内存中.
这样就说明没有被加载进去。
此命令用于清除Redis内存已经加载的所有Lua脚本
此命令用于杀掉正在执行的Lua脚本。如果Lua脚本比较耗时,甚至Lua 脚本存在问题,那么此时Lua脚本的执行会阻塞Redis,直到脚本执行完毕或 者外部进行干预将其结束。 模拟一下。
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,这个还是比较关键的,二进制存储,很多业务上需要。 |
请发表评论