redis集群JedisCluster连接关闭问题

JedisCluster连接关闭问题

set方法为例

//伪代码
JedisCluster jedisCluster = new JedisCluster();
jedisCluster.set("testKey", "testValue");

进入到set方法

  • 类JedisCluster中;

  • 初始化一个JedisClusterCommand对象,调用run方法;

  • 需要实现一个execute方法,通过Jedis调用set方法(这里又回到单节点调用set的方式了);

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

进入到run方法

  • 类JedisClusterCommand中;
public T run(String key) {
   return runWithRetries(JedisClusterCRC16.getSlot(key), this.maxAttempts, false, null);
 }

进入到runWithRetries方法

  • 类JedisClusterCommand中;
  • 只需要关注2个地方即可;
    • return execute(connection),这里调用了之前实现的execute方法;
    • releaseConnection(connection),在finally中释放了连接;
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 {
		//此处为空,走else
      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 {
        //此处是false,走else
        if (tryRandomNode) {
          connection = connectionHandler.getConnection();
        } else {
          //这里会从池中获取一个Jedis对象
          connection = connectionHandler.getConnectionFromSlot(slot);
        }
      }
		//这里调用最开始实现的execute方法
      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);
    }
  }

进入到releaseConnection方法

  • 类JedisClusterCommand中;
  • 实际上是通过Jedis.close()关闭的,和我们用单节点时,是一样的关闭方式;
private void releaseConnection(Jedis connection) {
    if (connection != null) {
      connection.close();
    }
  }

总结

  • 使用JedisCluster时,不需要手动释放连接;
  • 在调用的过程中,会自动释放连接;
  • 实际上是JedisCluster中通过JedisPool获取Jedis来执行命令;
原文地址:https://www.cnblogs.com/xiaodf/p/12167268.html