• 在Redis集群中使用pipeline批量插入


    由于项目中需要使用批量插入功能, 所以在网上查找到了Redis 批量插入可以使用pipeline来高效的插入, 示例代码如下:

    String key = "key";
    Jedis jedis = new Jedis("xx.xx.xx.xx");
    Pipeline p = jedis.pipelined();
    List<String> myData = .... //要插入的数据列表
    for(String data: myData){
        p.hset(key, data);
    }
    p.sync();
    jedis.close();

    但实际上遇到的问题是,项目上所用到的Redis是集群,初始化的时候使用的类是JedisCluster而不是Jedis. 去查了JedisCluster的文档, 并没有发现提供有像Jedis一样的获取Pipeline对象的 pipelined()方法.

    Google了一下, 发现了解决方案.

    Redis集群规范有说: Redis 集群的键空间被分割为 16384 个槽(slot), 集群的最大节点数量也是 16384 个。每个主节点都负责处理 16384 个哈希槽的其中一部分。当我们说一个集群处于“稳定”(stable)状态时, 指的是集群没有在执行重配置(reconfiguration)操作, 每个哈希槽都只由一个节点进行处理。

    所以我们可以根据要插入的key知道这个key所对应的槽的号码, 再通过这个槽的号码从集群中找到对应Jedis. 具体实现如下

    //初始化得到了jedis cluster, 如何获取HostAndPort集合代码就不写了
    
    Set<HostAndPort> nodes = .....
    
    JedisCluster jedisCluster = new JedisCluster(nodes);
    
    
    
    Map<String, JedisPool> nodeMap = jedisCluster.getClusterNodes();
    
    String anyHost = nodeMap.keySet().iterator().next();
    
    //getSlotHostMap方法在下面有
    
    TreeMap<Long, String> slotHostMap = getSlotHostMap(anyHost); 
        private static TreeMap<Long, String> getSlotHostMap(String anyHostAndPortStr) {
            TreeMap<Long, String> tree = new TreeMap<Long, String>();
            String parts[] = anyHostAndPortStr.split(":");
            HostAndPort anyHostAndPort = new HostAndPort(parts[0], Integer.parseInt(parts[1]));
            try{
                Jedis jedis = new Jedis(anyHostAndPort.getHost(), anyHostAndPort.getPort());
                List<Object> list = jedis.clusterSlots();
                for (Object object : list) {
                    List<Object> list1 = (List<Object>) object;
                    List<Object> master = (List<Object>) list1.get(2);
                    String hostAndPort = new String((byte[]) master.get(0)) + ":" + master.get(1);
                    tree.put((Long) list1.get(0), hostAndPort);
                    tree.put((Long) list1.get(1), hostAndPort);
                }
                jedis.close();
            }catch(Exception e){
                
            }
            return tree;
        }
    上面这几步可以在初始化的时候就完成. 不需要每次都调用, 把nodeMap和slotHostMap都定义为静态变量.
    //获取槽号
    
    int slot = JedisClusterCRC16.getSlot(key); 
    
    //获取到对应的Jedis对象
    
    Map.Entry<Long, String> entry = slotHostMap.lowerEntry(Long.valueOf(slot));
    
    Jedis jedis = nodeMap.get(entry.getValue()).getResource();

    建议上面这步操作可以封装成一个静态方法, 比如命名为public static Jedis getJedisByKey(String key) 之类的. 意思就是在集群中, 通过key获取到这个key所对应的Jedis对象.

    这样再通过上面的jedis.pipelined();来就可以进行批量插入了.

    注:这个方法是从Google上搜来的, 直到目前我使用起来还没发现什么问题. 如果哪位大神发现有什么不对的地方欢迎提出来.

  • 相关阅读:
    页码pageNo与SQL的limit进行换算
    Linux(centos)使用shell脚本停止启动jar包
    Linux执行脚本报错:-bash: ./xx.sh: /bin/bash^M: bad interpreter: No such file or directory
    Linux启动、停止宝塔
    Linux报错:ERROR>the input device is not a TTY
    mybatis基于注解的sql中空字符串判断
    题解 「CTSC2018暴力写挂」
    题解 Beautiful Pair
    【模板】常系数齐次线性递推
    斐波那契的最小公倍数 题解
  • 原文地址:https://www.cnblogs.com/drwong/p/4825752.html
Copyright © 2020-2023  润新知