redis的事务与管道

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35923749/article/details/85252043

redis的事务与管道

一、redis的管道

1. 使用管道技术的原因
redis是一个客户端-服务器(CS)模型请求/响应协议的TCP服务器,使用和http类似的请求响应协议。一个client可以通过一个socket连接发起多个请求命令。每个请求命令发出后client通常会阻塞并等待redis服务处理,redis处理完请求命令后会将结果通过响应报文返回给client。所以,如果一个业务逻辑中需要多次发送redis操作时,每一条命令在网络传输中的往返时延(计算机网络了解一下)会远远大于执行时间,这也是为什么说影响redis性能的最大难题是网络时延。
而管道(pipeline)可以一次性发送多条命令并在执行完后一次性将结果返回,pipeline通过减少客户端与redis的通信次数来实现降低往返延时时间,而且Pipeline 实现的原理是队列,而队列的原理是时先进先出,这样就保证数据的顺序性。
单个执行与管道执行对比图
在这里插入图片描述

2. Redis管道的特点
redis自带的命令行是没有管道技术的,只存在于各个客户端语音中,因为管道作用主要是,客户端在远程操作redis时,减少发送多个命令造成的网络时延TTL。

通过pipeline方式当有大批量的操作时候。我们可以节省很多原来浪费在网络延迟的时间。但是,需要注意到用pipeline方式打包命令发送,redis必须在处理完所有命令前先缓存起所有命令的处理结果。打包的命令越多,缓存消耗内存也越多。所以并是不是打包的命令越多越好。此外,pipeline期间将“独占”当前redis连接,此期间将不能进行非“管道”类型的其他操作,直到该pipeline关闭。

pipeline不是原子性的,中间可能会存在部分失败的情况,也就是说不能保证每条命令都能执行成功,如果中间有命令出现错误,redis不会中断执行,而是直接执行下一条命令,然后将所有命令的执行结果(执行成果或者执行失败)放到列表中统一返回,如果需要每条命令都执行成功,我们在批量执行过程中需要监控执行数量和返回的成功数量是否一致。

3. pipeline管道使用场景
Pipeline在某些场景下非常有用,比如有多个command需要被及时提交,而且他们对相应结果没有互相依赖,对结果响应也无需立即获得,那么pipeline就可以充当这种批处理的工具;

4. jedis实现pipeline的demo如下

        Pipeline pipeline = conn.pipelined();
        for (User user : users){
            String age= "age:" + user.getId();
            pipeline.incry(age);
        }

        List<Object> response = pipeline.syncAndReturnAll();

二、redis的简单事务##

为什么说redis的事务是简单事务呢?
关系型数据库具有ACID特性,redis能保证A(原子性)和I(隔离性),D(持久性)看是否有配置RDB或者AOF持久化操作,但无法保证一致性,因为redis事务不支持回滚。

事务中出现错误的两种情况

如果在EXEC指令被提交之前,Redis-server即检测到提交的某个指令存在语法错误,那么此事务将会被提前标记为DISCARD,此后事务提交也将直接被驳回;
如果在EXEC提交后,在实施数据变更时(Redis将不会预检测数据类型,比如你对一个“非数字”类型的key执行INCR操作),某条命令执行导致了ERROR,那么redis仍然不会回滚此前已经执行成功的操作,而且也不会中断ERROR之后的其他操作继续执行,这点是跟pipeline是一样的。所以对于我们开发者而言,我们需要关注事务执行后返回的结果(结果将是一个集合,按照操作提交的顺序排列,对于执行失败的操作,结果将是一个ERROR)。

事务与pipeline的区别
事务与pipeline都是不支持回滚;中间命令出现错误,不会影响前面已经执行成功的命令,也不会中断后面的命令继续执行;
事务可以实现原子性和隔离性,我的理解是,虽然pipeline中的命令是以队列发送到redis中执行的,但如果其他redis连接同时发送了命令,那么pipeline中的命令放到redis的排队执行队列中时可能会被拆开,即pipeline中的多个命令被其他命令插队。
如下pipeline的事例:
redis连接1:

command1 command2 command3

redis连接2:

command_n

redis最后的执行队列中

command1 command_n command2 command3

Redis提供实现“事务”的方式
MULTI,EXEC,DISCARD,WATCH/UNWATCH指令用来操作事务。
1) MUTIL:开启事务,此后所有的操作将会添加到当前链接的事务“操作队列”中。
2) EXEC:提交事务
3) DISCARD:取消事务,记住,此指令不是严格意义上的“事务回滚”,只是表达了“事务操作被取消”的语义,将会导致事务的操作队列中的操作不会被执行,且事务关闭。
4) WATCH/UNWATCH:“观察”,在事务开启前,可以对某个KEY注册“WATCH”,如果在事务提交后,将会首先检测“WATCH”列表中的KEY集合是否被其他客户端修改,如果任意一个KEY 被修改,都将会导致事务直接被“DISCARD”;即使事务中没有操作某个WATCH KEY,如果此KEY被外部修改,仍然会导致事务取消。事务执行成功或者被DISCARD,都将会导致WATCH KEY被“UNWATCH”,因此事务之后,你需要重新WATCH。WATCH需要在事务开启之前执行。
WATCH的实现
通过CAS操作实现乐观锁。Redis使用WATCH命令实现事务的“检查再设置”(CAS)行为。作为WATCH命令的参数的键会受到Redis的监控,Redis能够检测到它们的变化。在执行EXEC命令之前,如果Redis检测到至少有一个键被修改了,那么整个事务便会中止运行,然后EXEC命令会返回一个Null值,提醒用户事务运行失败。

猜你喜欢

转载自blog.csdn.net/qq_35923749/article/details/85252043
今日推荐