Redis中pop出队列多个元素思考

 更新时间:2022年05月23日 09:00:49   作者:code_boy  
本文主要介绍了Redis中pop出队列多个元素思考,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

最近,在工作中遇到了一个关于Redis中list集合一次性pop所有数据的问题,相信很多小伙伴也会碰到拿到同样的问题,所以就拿出来聊一聊了。

业务场景及问题的提出

业务的情景是这样的,服务A 是面向客户的服务,主要是用了Redis作为存储的,而服务B是面向业务人员使用的,服务A 的数据服务B 是需要拿到的,所以我会把每次服务A 的请求参数放到一个Redis的队列中,而服务B 会起一个线程来定时的获取我队列的数据,其实这里涉及到了一个简易RPC框架的设计,下篇文章会来聊一聊我们这个简易RPC 框架的设计变迁,大致的架构如下:

所以现在问题就来了,内部的定时服务如果一次pop一个那性能可就太差了,所以现在我们就需要支持一个可以自定义pop出队列元素个数的方法,而redis本身是没有这种方法的,所以得我们自己来设计,一起来聊一聊吧。

解决方案

1.多次请求

这应该是正常人都可以想到的办法了,任何问题都可以使用一个for循环来解决,如果不行,那就再来一个for循环,我们来看下这个简单的代码:

      public List<String> multiRPopForCycle(String key, int size) {
        // 获取当前队列里的值
        int curSize = Math.toIntExact(redisTemplate.opsForList().size(key));
        if (curSize == 0) {
            return Collections.emptyList();
        }
        // 最终可以取出的数量
        int finalSize = Math.toIntExact(Math.min(curSize, size));
        List<String> resultList = new ArrayList<>();
        for (int i = 0; i < finalSize; i++) {
            String popElement = redisTemplate.opsForList().rightPop(key);
            resultList.add(popElement);
        }
        return resultList;
    }

这个代码写出来很简单,但是它好危险啊,如果我们需要pop出的数据很多怎么办,每次都需要进行通信,这来来回回就会产生很多时耗,上生产我们是没办法接受的,所以必须改进。 因为pop出多个元素,我们不可避免的需要进行for循环进行pop然后收集返回,也就是说我们需要执行多次redis的pop命令,为了减少通信时耗,我们可以一次性将所有的命令都发过去,一起执行,而实现这种方案我们有以下两种方法:

2.利用Redis事务

利用redis的事务来实现:拿到连接后,开启事务,然后进行执行pop命令,代码如下:

         /**
     * 通过事务机制来pop出多个元素
     *
     * @param key       键
     * @param size      需要取出的元素个数
     * @return          返回取出的元素集合
     */
    public List<String> multiRPopTx(String key, int size) {
        // 获取当前队列里的值
        int curSize = Math.toIntExact(redisTemplate.opsForList().size(key));
        if (curSize == 0) {
            return Collections.emptyList();
        }
        // 最终可以取出的数量
        int finalSize = Math.toIntExact(Math.min(curSize, size));
        // 事务支持
        return redisTemplate.execute(new SessionCallback<List<Object>>() {
            @Override
            public List<Object> execute(RedisOperations redisOperations) throws DataAccessException {
                redisOperations.multi();
                for (int i = 0; i < finalSize; i++) {
                    redisOperations.opsForList().rightPop(key);
                }
                return redisOperations.exec();
            }
        }).stream().map(obj -> (String) obj).collect(Collectors.toList());
    }

3.利用Pipeline

当然了,还可以使用我们之前讲的pipeline来实现:

     /**
     * 一次性pop出指定数量的数据
     *
     * @param key       键
     * @param size      需要取出的元素个数
     * @return          返回取出的元素集合
     */
    public List<String> multiRPopPipeline(String key, int size) {
        // 获取当前队列里的值
        int curSize = Math.toIntExact(redisTemplate.opsForList().size(key));
        if (curSize == 0) {
            return Collections.emptyList();
        }
        // 判断操作次数
        return redisTemplate.executePipelined(new SessionCallback<String>() {
            @Override
            public String execute(RedisOperations redisOperations) throws DataAccessException {
                final int finalSize = Math.toIntExact(Math.min(curSize, size));
                for (int i = 0; i < finalSize; i++) {
                    redisOperations.opsForList().rightPop(key);
                }
                return null;
            }
        }).stream().map(obj -> (String) obj).collect(Collectors.toList());
    }

其实在我们这种场景中是没必要使用事务的,使用事务还会带来一定的性能损耗,所以最终选择的是方案三,即基于管道来实现pop多个元素。

到此这篇关于Redis中pop出队列多个元素思考的文章就介绍到这了,更多相关Redis pop队列内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • ASP.NET Core中预压缩静态文件的方法步骤

    ASP.NET Core中预压缩静态文件的方法步骤

    这篇文章主要给大家介绍了关于ASP.NET Core中如何预压缩静态文件的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用ASP.NET Core具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-03-03
  • Asp.Net 网站优化系列之数据库优化措施 使用主从库(全)

    Asp.Net 网站优化系列之数据库优化措施 使用主从库(全)

    网站规模到了一定程度之后,该分的也分了,该优化的也做了优化,但是还是不能满足业务上对性能的要求;这时候我们可以考虑使用主从库。
    2010-06-06
  • ASP.NET MVC 导出Word报表

    ASP.NET MVC 导出Word报表

    本文主要介绍了ASP.NET MVC 导出Word报表的方法,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • asp.net post方法中参数取不出来的解决方法

    asp.net post方法中参数取不出来的解决方法

    调试client端调用web api的代码,服务器端的post方法的参数死活取不出来,下面有个不错的解决方法,希望对大家有所帮助
    2014-01-01
  • Win2008 server + IIS7 设置身份模拟(ASP.NET impersonation)

    Win2008 server + IIS7 设置身份模拟(ASP.NET impersonation)

    IIS7 与 IIS 6 相比有了很大的改动,原来在 IIS 6 下可以的设置到了 IIS 7 下有的会发生变化。身份模拟的配置上,IIS7 和 IIS6有很大不同,网上IIS6的身份模拟的文章比较多,但介绍IIS7的比较少,我把的一些折腾的经验在这篇博客中写下来,以供参考
    2011-10-10
  • ASP.NET Core 实现基本认证的示例代码

    ASP.NET Core 实现基本认证的示例代码

    这篇文章主要介绍了ASP.NET Core 实现基本认证的示例代码吗,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • C# Math.Round()函数问题

    C# Math.Round()函数问题

    Math.Round()准确的说,这个函数不是四舍五入,而是四舍六入五凑偶,就是说小于4或大于6的该舍该入是没有争议的,而5处在正中间,如果四舍五入则会造成数据的整体偏差,所以采取的原则是:如果舍入位为5,则舍入后最后一位为偶数,这是国际惯例。
    2008-12-12
  • MVC使用MvcPager实现分页效果

    MVC使用MvcPager实现分页效果

    这篇文章主要为大家详细介绍了MVC使用MvcPager实现分页效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • 解决uploadify使用时session发生丢失问题的方法

    解决uploadify使用时session发生丢失问题的方法

    这篇文章主要为大家详细介绍了uploadify使用时发现session发生丢失问题的解决方法,遇到过类似问题的朋友可以参考本文进行解决
    2016-05-05
  • ASP.NET中Web API的简单实例

    ASP.NET中Web API的简单实例

    Web API框架是一个面向Http协议的通信框架,Web API 框架是一个面向Http协议的通信框架。Web API 框架目前支持两种数据格式的序列化:Json 及 Xml。在不做任何配置的情况下,则 Web API 会自动把数据使用xml进行序列化,否则使用 json 序列化,需要的朋友可以参考下
    2015-10-10

最新评论