Redis集群测试-java

集群环境搭建见另外一篇文章https://blog.csdn.net/dongzhongyan/article/details/100141898
连接池工具类,内部使用了Redis连接池,通过源码可以看到,集群操作数据时,通过Redis连接池获取连接,用完后会释放连接,把Redis归还给连接池。
源码
执行sadd命令

@Override
  public Long sadd(final String key, final String... member) {
    return new JedisClusterCommand<Long>(connectionHandler, maxAttempts) {
      @Override
      public Long execute(Jedis connection) {
        return connection.sadd(key, member);
      }
    }.run(key);
  }

在执行run后,releaseConnection(connection);会释放连接。

 private T runWithRetries(final int slot, int attempts, boolean tryRandomNode, JedisRedirectionException redirect) {
    if (attempts <= 0) {
      throw new JedisClusterMaxAttemptsException("No more cluster attempts left.");
    }

    Jedis connection = null;
    try {

      if (redirect != null) {
        connection = this.connectionHandler.getConnectionFromNode(redirect.getTargetNode());
        if (redirect instanceof JedisAskDataException) {
          // TODO: Pipeline asking with the original command to make it faster....
          connection.asking();
        }
      } else {
        if (tryRandomNode) {
          connection = connectionHandler.getConnection();
        } else {
          connection = connectionHandler.getConnectionFromSlot(slot);
        }
      }

      return execute(connection);

    } catch (JedisNoReachableClusterNodeException jnrcne) {
      throw jnrcne;
    } catch (JedisConnectionException jce) {
      // release current connection before recursion
      releaseConnection(connection);
      connection = null;

      if (attempts <= 1) {
        //We need this because if node is not reachable anymore - we need to finally initiate slots
        //renewing, or we can stuck with cluster state without one node in opposite case.
        //But now if maxAttempts = [1 or 2] we will do it too often.
        //TODO make tracking of successful/unsuccessful operations for node - do renewing only
        //if there were no successful responses from this node last few seconds
        this.connectionHandler.renewSlotCache();
      }

      return runWithRetries(slot, attempts - 1, tryRandomNode, redirect);
    } catch (JedisRedirectionException jre) {
      // if MOVED redirection occurred,
      if (jre instanceof JedisMovedDataException) {
        // it rebuilds cluster's slot cache recommended by Redis cluster specification
        this.connectionHandler.renewSlotCache(connection);
      }

      // release current connection before recursion
      releaseConnection(connection);
      connection = null;

      return runWithRetries(slot, attempts - 1, false, jre);
    } finally {
      releaseConnection(connection);
    }
  }

连接池工具类,可能不太严谨,在高并发情况下不一定会保证唯一性,可以做成单例模式。

package utils;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;

import java.util.HashSet;
import java.util.Set;

/**
 * @author dongzy
 * @Desc
 * @date 2019/8/28.
 */

public class RedisClusterUtil {
    private static JedisCluster jedis = null;

    static {
        int connectTimeOut = 10000;//连接超时
        int soTimeOut = 5000;//读写超时
        int maxAttemts = 10;//重试次数

        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(Integer.valueOf(80)); //连接池最大连接数
        poolConfig.setMaxIdle(Integer.valueOf(10));//连接池中最大空闲的连接数
        //当连接池用尽后,调用者的最大等待时间(单位为毫秒),默认值为-1 表示永不超时,一直等待,一般不建议使用默认值。
        //连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
        poolConfig.setBlockWhenExhausted(true);
        //设置的逐出策略类名, 默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数)
        poolConfig.setEvictionPolicyClassName("org.apache.commons.pool2.impl.DefaultEvictionPolicy");
        //是否启用pool的jmx管理功能, 默认true
        poolConfig.setJmxEnabled(true);
        //MBean ObjectName = new ObjectName("org.apache.commons.pool2:type=GenericObjectPool,name=" + "pool" + i); 默 认为"pool", JMX不熟,具体不知道是干啥的...默认就好.
        poolConfig.setJmxNamePrefix("pool");
        //是否启用后进先出, 默认true
        poolConfig.setLifo(true);
        //获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1
        poolConfig.setMaxWaitMillis(-1);
        //逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
        poolConfig.setMinEvictableIdleTimeMillis(1800000);
        //最小空闲连接数, 默认0
        poolConfig.setMinIdle(10);
        //每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
        //做空闲连接检测时,每次的采样数,默认3
        poolConfig.setNumTestsPerEvictionRun(3);
        //对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断  (默认逐出策略)
        poolConfig.setSoftMinEvictableIdleTimeMillis(1800000);
        //在空闲时检查有效性, 默认false
        poolConfig.setTestWhileIdle(false);
        //逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
        poolConfig.setTimeBetweenEvictionRunsMillis(-1);

        Set<HostAndPort> nodes = new HashSet<HostAndPort>();
        nodes.add(new HostAndPort("172.16.8.87", 8001));
        nodes.add(new HostAndPort("172.16.8.87", 8002));
        nodes.add(new HostAndPort("172.16.8.87", 8003));
        nodes.add(new HostAndPort("172.16.8.87", 8004));
        nodes.add(new HostAndPort("172.16.8.87", 8005));
        nodes.add(new HostAndPort("172.16.8.87", 8006));
        jedis = new JedisCluster(nodes, poolConfig);
    }

     /**
	  * 获取集群连接
	  * @return
     */
	 public static JedisCluster JedisCluster() {
		 if(jedis == null){
	 		 return jedis;
		 }
	  }

	 /**
  	  * 关闭集群连接
 	  */
  	 public static void releaseJedisCluster() {
    	  if (jedis != null) {
	        jedis.close();
	  	  }
	  }
}

测试类,通过对数据分析,发现集群模式下的节点中数据被随机存储。且主从节点数据一致

package rediscluster;

import redis.clients.jedis.JedisCluster;
import utils.RedisClusterUtil;

/**
 * @author dongzy
 * @Desc
 * @date 2019/8/28.
 */

public class RedisCluster {
    public static void main(String[] args) {
        for (int i = 0; i < 12; i++) {
            int finalI = i;
            new Thread() {
                @Override
                public void run() {
                    for (int j = 0; j < 1000000; j++) {
                        JedisCluster redisCluster = RedisClusterUtil.JedisCluster();
                        redisCluster.sadd("thread" + String.valueOf(finalI), "" + j);
                        System.out.println("thread" + String.valueOf(finalI) + redisCluster);
                    }
                }
            }.start();
        }
    }
}

8001、8002、8003是主节点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值