Redis事务和管道
事务
一、概念
Redis事务是可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其他命令插入。
-
单独的隔离操作:Redis事务仅仅是保证事务里的操作会被连续独占地执行,redis命令执行是单线程架构,在执行完事务内所有指令前是不可能再去同时执行其他客户端请求。
-
没有隔离级别的概念:因为事务提交前任何指令都不会被实际执行,也就不存在“事务内的查询要看到事务里的更新,在事务外查询不能看到”这种问题了
-
不保证原子性:Redis事务不保证原子性,也就是不保证所有指令同时成功或同时失败,只有决定 是否开始执行全部指令的能力,没有执行到一半进行回滚的能力。
-
排他性:Redis会保证一个事务内的命令依次执行,而不会被其他命令插入
二、事务命令
redis的全部命令:
-
multi: 标记事务块的开始
-
exec:执行事务块内的所有命令
-
discard:取消事务,放弃事务块内的所有命令
-
watch:监视一个或多个key,如果在事务执行之前这个(或这些)key被其他命令改动,那么事务将被打断
-
unwatch:取消watch命令对所有key的监视
当一个事务正常执行时,通过multi开始事务,exec提交事务,事务块内的所有命令都正常执行
当你不想要执行事务时,可以使用discard 取消事务
如果在一个事务中出现了错误命令,那么使用exec提交事务时会报事务取消,其他的命令也不会执行
如果一个事务中的命令没有语法上的错误,但是编译会报错,那么在该事务中除了有错误的命令,其他命令都会正确执行
watch
redis使用watch来提供乐观锁,类似于CAS,乐观锁的策略是提交版本必须大于记录当前版本才能执行更新
正常监听:
在没有其他进程修改的情况下,监听后可以正常修改成功
如果在监听后,提交事务之前,其他进程修改了监听的值,那么事务整体就失败了,会报 nil
管道
为什么会有管道这个概念?
Redis是一种基于客户端-服务端模型以及请求/响应协议的tcp服务,一个请求会遵循以下步骤:
-
客户端向服务端发送命令分四步(发送命令-->命令排队-->命令执行-->返回结果),并监听Socket返回,通常以阻塞模式等待服务端响应
-
服务端处理命令,并将结果返回给客户端
上面两个步骤成为 Round Trip Time 简称RTT
如果同时需要执行大量的命令,那么就需要等待上一条命令应答后再执行,这中间不仅多了RTT,还频繁调用系统IO,发送网络请求,同时需要redis调用多次 read() 和 write() 系统方法,对系统有较大的影响,导致性能不好
管道(pipeline)可以一次性发送多条命令给服务端,服务端依次处理完毕后,通过一条响应一次性将结果返回,通过减少客户端与redis的通信次数来实现降低往返延时时间,管道的原理是队列,先进先出保证数据的顺序性
最终管道的定义是:Pipeline是为了解决RTT往返时,仅仅是将命令打包一次性发送,对整个redis的执行不产生其他影响
如何用管道进行命令的批量执行?
首先把要执行的命令放到一个 txt文件中
在没有连接redis的终端中执行 cat cmd.txt | redis-cli -a 123456 --pipe
该命令用管道修饰符连接了起来,表示第一条命令作为参数 传到 第二条命令中。
也就是 txt文件中的命令在 redis中以管道的方式去执行
Pipeline缓冲的指令只是会依次执行,不保证原子性,如果执行中指令发生异常,将会继续执行后续指令
使用pipeline组装的命令个数不能太多,不然数据量过大客户端阻塞的时间可能过久,同时服务端此时也被迫回复一个队列答复,占用很多内存