您现在的位置是:首页 >技术教程 >Redis事务和Redis管道网站首页技术教程
Redis事务和Redis管道
什么是Redis事务:Redis事务是指将多条命令加入到队列里面,一次批量执行多条命令,每一条命令会按顺序执行,在事务执行过程中不会受到客户端所传入的命令请求的影响
1)单独的隔离操作:Redis的事务仅仅保证事务 里面的操作会被连续独占的执行,redis命令执 行是单线程架构 ,在执行完事务内所有 指令前是不可能再去同时执行其他客户端的请求的
2)没有隔离级别的概念:存在watch命令来进行事务开启之前监视任意数量的key,当进行调用exec执行事务的时候,如果任意一个被监视的key已经被其他客户端修改了,那么整个事务不再执行,直接返回失败,可以说Redis没有事务隔离级别的概念;
3)不一定会保证原子性:Redis不会提供事务回滚的功能,开发者必须在事务执行出错之后自行恢复数据库的状态,没有执行到一半回滚的能力,不能保证所执行的执行全部成功或者全部失败,只有决定事务是否开始执行全部指令的能力;
单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的
3.1)全体连坐入队错误(编译时异常):在我们开启multi命令的时候,我们执行命令set k1 v1,set k2 v2,但是当我们进行执行set k3,故意把命令写错,这样语法编译就不通过,一个语法出错,全体连坐,任何一个命令语法出错,Redis就会直接返回错误信息,所有的命令都不会被执行,
3.2)源头寨主(运行时异常),如果不是redis命令的语法错误,而是在执行命令的时候发生了错误,那么对应的命令不会执行,但是其他没有出现错误的命令则会被正常执行
如果命令在事务执行的过程中发生错误,比如说,对一个不同类型的 key 执行了错误的操作, 那么 Redis 只会将错误包含在事务的结果中, 这不会引起事务中断或整个失败,不会影响已执行事务命令的结果,也不会影响后面要执行的事务命令, 所以它对事务的一致性也没有影响
4)排他性:Redis会保证一个事务内的命令依次执行,而不会被其他命令插入;
5)持久性:因为事务不过是用队列包裹起了一组 Redis 命令,并没有提供任何额外的持久性功能,所以事务的持久性由 Redis 所使用的持久化模式决定
Redis中的事务命令:
1)discrd:取消事务,放弃执行事务块中的全部命令,它清空客户端的整个事务队列, 然后将客户端从事务状态调整回非事务状态, 最后返回字符串 OK 给客户端, 说明事务已被取消
2)exec:提交事务
3)multi:开启事务
4)unwatch:取消watch命令针对于所有key的监视
Watch原理:是一个乐观锁的实现,Redis在进行修改的时候会进行检测数据是否被修改,如果被修改了,那么执行失败
watch命令用于在事务开启之前进行监视任意数量的键,当调用 EXEC 命令执行事务时, 如果任意一个被监视的键已经被其他客户端修改了, 那么整个事务不再执行, 直接返回失败
1)悲观锁:在每一次拿到数据的时候都会认为别人会修改,因此在每一次拿数据的时候都会上锁,别人拿数据就要阻塞等待释放锁;
2)乐观锁:认为每一次拿数据的时候别人都不会进行修改,所以不会上锁,但是在进行更新的时候会进行判断一下有没有人更新过这个数据,提交版本必须大于当前版本才会执行更新
3)watch key1 key2: 监视一或多个key,如果在事务执行之前,被监视的key被其他命令改动,则事务被打断;
但是一旦执行了exec命令之前加的所有的监控锁都会被取消掉,当客户端连接丢失的时候,比如说退出链接,那么所有的东西都会被取消监视
总结:使用multi开启一个事务,入队的时候将多个命令入队到事务中,接收到这些命令并不会立即执行,而是放到等待执行的任务队列里面,最后由exex触发事务
Redis管道:
1)因为客户端向服务器发送命令分为四步,发送命令,命令排队,命令执行,返回结果,并且监听Socket返回,通常以阻塞模式等待服务器端响应,
2)服务器处理命令,并将结果返回给客户端
以上两步简称为是Round Trip Time,简称为是RTT是数据包往返于两端的时间
3)如果同时需要执行大量的命令, 那么就需要等待上一次命令应答过后再去执行,这中间不仅多了RTT(Round Time Trip),而且还需要进行频繁调用操作系统的IO,发送网络请求,同时需要Redis多次调用read()和write()的系统方法,系统方法将会将数据从用户态转移到内核态,这样就会对进程上下文产生比较大的影响了,效果不太好;
4)Pipeline是为了解决RTT往返的时候,仅仅是将命令打包一次性发送,对整个Redis的执行不会造成其他的任何的影响
管道和原生命令的区别:
1)原生批量的命令是原子性,比如说mget和mset,但是pipeline是非原子性
2)原生批量命令一次只能执行一种命令,但是pipeline是支持批量执行不同的命令
3)原生批量命令是依靠服务器端实现的,但是pipeline需要服务器端和客户端共同完成
事务和管道的区别:
1)事物具有原子性,但是管道不具有原子性
2)管道是一次性将命令发送到服务器,但是事务是一条一条的发,十五只有接收到exec命令的时候才会执行;
3)执行事务的时候会进行阻塞其他命令的执行,但是执行管道中的命令不会阻塞
总结:
1)管道的缓冲的指令只是会依次执行,是不会保证原子性的,如果执行的过程中发现指令发生异常,那么将会执行后续的指令;
2)使用管道进行组装的命令不要太多,不然会因为数据量过大导致客户端阻塞的时间可能会太久,此时服务器端也会被迫回复一个队列答复,不然会占用内存;