redis集群下使用pipline进行批处理操作(spring/springboot+jedis)

我们都知道redis集群下对于mget、mset、pipeline、事务的支持不太好。

当然对于mget和mset有这么几种方法:

1、串行遍历key依次执行(这种就是把批量拆开了)

2、使用hash_tag包装key,在计算key的slot时候,如果key包含{},就会使用第一个{}内部的字符串作为hash key,这样就可以保证拥有同样{}内部字符串的key就会拥有相同slot(这种方式其实就是把一次批量操作的key全部放到了集群的一个节点进行操作,屏蔽掉多节点的问题)。

3、自己手动进行批量的key做处理,通过CRC16算法对所有的key进行分组(相同slot的分成一组),然后不同的分组keys,使用不同的集群节点进行处理。

本文就是适用了第三种方式,通过 pipeline来操作批处理,减少网络请求次数,加快处理速度。

使用jedis封装的工具类,源码也是分析的jedis。

1、通过源码看下原理

对于jedis,集群的操作使用的JedisCluster类,看下它的继承实现关系图:

f961488e4f2bf953b47953eb68b00cf9c9b.jpg

通过继承实现管理可以看到,JedisCluster继承自 BinaryJedisCluster ,以及实现了其他接口。我们再查看下 BinaryJedisCluster源码。

cf4011fa70284d414748e7a653e8f54c586.jpg

在图中我们注意到:JedisClusterConnectionHandler 这个类,字面意思redis集群连接处理器,同时这个connectionHandler变量在此类中还没有公共的获取方法。我们再往后看,我们进去到JedisClusterConnectionHandler 源码看下。

eccc9581e2e99bc211554a6eb681216a7b0.jpg

这个类中有一个内部变量JedisClusterInfoCache cache,看着字面意思是Redis集群信息缓存,但是JedisClusterConnectionHandler中没有获取cache的公共方法,往下看下JedisClusterConnectionHandler中的方法,initializeSlotsCache()

29fc93da19c0997b46e1ffaa0a77b3c855c.jpg

这个变量中存储了所有的redis集群节点信息(包含了host和端口),那这里面有没有集群的其他信息呢?比如slots哈希槽数据,我们再看下JedisClusterInfoCache的源码。

317ae7b4f2c40d9a8985acaca1ac8b5c63f.jpg

看到这里相信你已经明白了,就是这个cache存储了redis集群节点数据和哈希槽对应的节点关系数据,同时这俩变量还是私有的,往下看下源码有没有直接获取这俩变量的方法呢,答案是看下图。

c9c08b408f9c08e84db93bbb6d58cf8322a.jpg

只有获取节点信息(host+ip对应的连接池数据集合)的方法,没有获取哈希槽对应的节点数据的方法。但是有通过slot获取节点连接池的方法,这个也是jedis中JedisCluster集群操作类可以处理集群操作的关键。我们通过getSlotPool(int slot)方法内部实现可以知道,slots集合中存储的关系就是slot对应redis集群节点连接池,这里就是我们后面实现集群下操作的关键,先记一下。

2、通过反射获取内部私有变量

反射的知识请自行百度下或者看下其他人的博客,简单说,它很强大,可以通过它获取这个类或对象中的任何东西,包含私有变量、方法。

直接看下代码实现:

        String clusterNodes="172.16.16.90:16379,172.16.16.90:16380,172.16.16.91:16379,172.16.16.91:16380,172.16.16.92:16379,172.16.16.92:16380";
        int redirects=3;
        int timeOut=2000;
        String[] serverArray = clusterNodes.split(",");
        Set<HostAndPort> nodes = new HashSet<HostAndPort>();
        for (String ipPort : serverArray) {
            String[] ipPortPair = ipPort.split(":");
            nodes.add(new HostAndPort(ipPortPair[0].trim(), Integer.valueOf(ipPortPair[1].trim())));
        }
                
        JedisCluster cluster=new JedisCluster(nodes, timeOut, redirects);
        
        Field hfield = cluster.getClass().getDeclaredField("connectionHandler");//获的变量名为connectionHandler的变量
        hfield.setAccessible(true);//打开访问权限
        JedisClusterConnectionHandler connectionHandler = (JedisClusterConnectionHandler)hfield.get(cluster);
        Field cfield = connectionHandler.getClass().getDeclaredField("cache");//获的变量名为cache的变量
        cfield.setAccessible(true);//打开访问权限
        JedisClusterInfoCache cache = (JedisClusterInfoCache)cfield.get(connectionHandler);
        //获取ip+port对应的连接池
        Map<String, JedisPool> nodes2 = cache.getNodes();//这个我们没怎么
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值