Redis_Jedis, JedisCluster Extended keys Method Implementation

Keywords: Database Redis Jedis Java Junit

 

Recently, we have used Java to operate Redis more often, using Jedis component, below is a maven coordinate.

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
    <type>jar</type>
    <scope>compile</scope>
</dependency>

 

The operation of Redis mainly uses the following three classes.

Jedis   :

Used to operate single node Redis.

SharedJedis :

Used to operate fragmented Redis clusters, the older way is to use Jedis Cluster instead under Redis clusters.

JedisCluster :

Operational classes in Redis cluster mode are newly added to Redis.  

 

However, JedisCluster does not provide the keys method provided under Jedis in terms of performance, etc.

The keys method is mainly used for wildcard pattern matching to return keys satisfying conditions.

The keys method is still useful.

So let's expand it.

 

First, we define an interface to extend our functionality.

 

Interface class:

RedisClusterOperator.java 
package com.redis.extend;

import java.util.Set;

/**
 * Created by szh on 2018/10/16.
 *
 * @author szh
 */
public interface RedisClusterOperator {

    Set<String> keys(String pattern);

}

 

 

Implementation class:

RedisClusterExtCmd.java
package com.redis.extend.impl;

import com.redis.extend.RedisClusterOperator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;

import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

/**
 * Created by szh on 2018/10/16.
 *
 * @author szh
 */
public class RedisClusterExtCmd implements RedisClusterOperator {

    public final static Logger logger = LoggerFactory.getLogger(RedisClusterOperator.class);

    private JedisCluster jedisCluster = null;

    public RedisClusterExtCmd(JedisCluster jedisCluster) {
        this.jedisCluster = jedisCluster;
    }

    @Override
    public Set<String> keys(String pattern) {

        logger.debug("Start getting keys... ");
        TreeSet<String> keys = new TreeSet<>();
        Map<String, JedisPool> clusterNodes =
                jedisCluster.getClusterNodes();

        for (String key : clusterNodes.keySet()) {
            logger.debug("Getting keys from: {}", key);
            JedisPool jedisPool = clusterNodes.get(key);
            Jedis jedisConn = jedisPool.getResource();
            try {
                keys.addAll(jedisConn.keys(pattern));
            } catch (Exception e) {
                logger.error("Getting keys error: {}", e);
            } finally {
                logger.debug("Jedis connection closed");
                jedisConn.close();
            }
        }
        logger.debug("Keys gotten");

        return keys;
    }
}

 

Ideas for realization:

JedisCluster can get all the nodes in the cluster, and we execute keys (patterns) for each node in the cluster.

After the keys are de-duplicated, a set < String > set is returned.

 

 

In addition, by referring to the implementation of spring-redis, we can verify that the implementation ideas are consistent with our implementation ideas.

package sunyu.example.bigdata.monitor;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class RedisTests {

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Test
    public void t1() {
        stringRedisTemplate.keys()
    }

}

 

/*
 * (non-Javadoc)
 * @see org.springframework.data.redis.connection.RedisKeyCommands#keys(byte[])
*/
@Override
public Set<byte[]> keys(final byte[] pattern) {

    Assert.notNull(pattern, "Pattern must not be null!");

    Collection<Set<byte[]>> keysPerNode = clusterCommandExecutor
        .executeCommandOnAllNodes(new JedisClusterCommandCallback<Set<byte[]>>() {

            @Override
            public Set<byte[]> doInCluster(Jedis client) {
                return client.keys(pattern);
            }
        }).resultsAsList();

    Set<byte[]> keys = new HashSet<byte[]>();
    for (Set<byte[]> keySet : keysPerNode) {
        keys.addAll(keySet);
    }
    return keys;
}

 

 

Posted by KCKTechs on Tue, 29 Jan 2019 23:09:15 -0800