redis的pipeline和事务讨论

事务

redis事务有一些特点,需要注意:

1、redis事务失败不会回滚,比如下面3条命令在multi后执行:
set checked 1
lset l1 3 b3
lset l1 0 a1
如果第2条命令执行出错,最终的结果是命令1和3仍然生效,仅仅是命令2失败而已。
因此,redis事务并不具备DB事务那样的数据一致性保证,其仅仅作出了弱原子性保证:确保事务中的这批命令在EXEC执行时不会被其它client的命令干扰。

顺带说一下,假如3条命令中任何一条存在语法错误,最终exec时会导致整个事务被discard,redis报错:(error) EXECABORT Transaction discarded because of previous errors.

2、未EXEC的redis事务并不会阻塞其它client的修改操作
当你用MULTI起一个事务,只要没有EXEC,其它client的操作仍然可以修改你这个事务所涉及的key。看来MULTI只是把命令缓存到事务队列,而不能对涉及到的数据提供保护。

这个特点完全不同于数据库事务,后者在事务T启动时就会锁住要修改的key,其它client对该key的操作会被挂起直到T结束。

正是基于这一点(保命令而不保数据),我们说,redis事务仅提供了弱原子性保证

3、保证一致性需要结合watch和事务,但这个只是乐观锁机制,失败的话是需要反复重试的。

4、redis的强原子性只能使用lua脚本来解决(由于redis的单线程模式,一个lua脚本可以认为是一个在启动之初就独占redis server的事务)。

5、 阻塞式的命令,例如blpop,如果在事务(multi/exec对)中执行,将会退化为相应的普通命令(例如lpop),这是因为如果还保持阻塞,根据事务的原子性,其间其他client的命令是不会执行的,包括用于解阻塞的rpush命令,这样事务就会陷入永久的等待。至于lua脚本,则根本不让阻塞式命令运行,会报:This Redis command is not allowed from scripts的错误。

pipeline

我们说redis比数据库快,是有几个前提的:

  • 从应用服务器到redis和到DB的网络时延是接近的;
  • 操作的数据量大小及操作方式是接近的,比如:批量操作10000条数据。

第2点要特别注意,如果数据库是批插,redis是单个命令一条条的执行,很可能前者会远快于后者,因为在后者里面网络通信的开销占了大头。

所以,发挥redis的性能优势,其批处理能力也很重要,redis的批处理就依赖于pipeline。

pipeline的原理,下面的文章讲的很清晰,推荐阅读:

https://blog.csdn.net/ldw201510803006/article/details/126093441

有必要强调一下,pipeline和redis事务是不同的概念。pipeline就是命令批处理,它连弱原子性都没有!执行期间会被其它client的命令干扰,它纯粹就是执行效率的优化手段。

pipeline的redisson代码样例:

@Test
    public void testRedisBatch_ShouldSucc() {
        Ticker tk = new Ticker();
        int n = 10000;

        RBatch batch = getRedissonClient().createBatch();
        RMapAsync<String, Integer> mapInBatch = batch.getMap("counterBatch", IntegerCodec.INSTANCE);
        for (int i=0; i<n; ++i) {
            mapInBatch.putAsync("k" +i, i);
        }
        batch.execute();
        log.info("do batch cost:{}ms", tk.count());

        RMap<String, Integer> map = getRedissonClient().getMap("counter", IntegerCodec.INSTANCE);
        for (int i=0; i<n; ++i) {
            map.put("k" +i, i);
        }
        log.info("do one by one cost:{}ms", tk.count());

    }

这里用10000条记录插入map的操作来对比pipeline和非pipeline的效率,前者只要600ms,后者则要350s,差异巨大!

注意:理论上,pipeline 每次只能作用在一个 Redis 节点上。不过,redisson库已处理了cluster的pipeline问题。

其它库(jedis或lettuce)对cluster下支持pipeline还存在问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值