jedis源码分析-如何从连接池获取连接?如何初始化集群?

·  阅读 451

背景

本地连测试环境redis,报错:获取不到连接,套接字超时。

然后,源码调试发现有的节点不通。

最终结论就是,redis集群有的节点网络通,有的节点网络不通,导致了这个问题。之前以为网络全部开通,后面发现是有的节点网络没开通,然后开通网络就好了。

从连接池获取连接

报错信息

edis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool, dubbo version: 2.6.7, current host: 10.211.55.2
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool //获取不到连接
    at redis.clients.util.Pool.getResource(Pool.java:53) //从连接池获取连接
    at redis.clients.jedis.JedisPool.getResource(JedisPool.java:226)
    at redis.clients.jedis.JedisSlotBasedConnectionHandler.getConnectionFromSlot(JedisSlotBasedConnectionHandler.java:66)
    at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:116)
    at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:141)
    at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:141)
    at redis.clients.jedis.JedisClusterCommand.run(JedisClusterCommand.java:31)
    at redis.clients.jedis.JedisCluster.set(JedisCluster.java:114) //jedis客户端

    at xxx.xxx.util.JedisUtil.lock(JedisUtil.java:28) //应用层
    at xxx.xxx.xxxserver.impl.xxx.lockWithOrderUK(xxx.java:2013)
    at xxx.xxx.xxxserver.impl.xxx.xxx(xxx.java:69)
    at xxx.xxx.xxxserver.impl.xxx.xxxAndJsPay(xxx.java:1760)
    at com.alibaba.dubbo.common.bytecode.Wrapper1.invokeMethod(Wrapper1.java)
    at com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory$1.doInvoke(JavassistProxyFactory.java:47)
    at com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:76)
    at com.alibaba.dubbo.config.invoker.DelegateProviderMetaDataInvoker.invoke(DelegateProviderMetaDataInvoker.java:52)
    at com.alibaba.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:56)
    at com.xxx.log.rpc.dubbo.AppNameAppendFilter.invoke(AppNameAppendFilter.java:11)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)
    at com.alibaba.dubbo.rpc.filter.ExceptionFilter.invoke(ExceptionFilter.java:62)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)
    at com.alibaba.dubbo.rpc.filter.TimeoutFilter.invoke(TimeoutFilter.java:42)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)
    at com.alibaba.dubbo.rpc.filter.ExecuteLimitFilter.invoke(ExecuteLimitFilter.java:60)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)
    at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:75)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)
    at com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:78)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)
    at xxx.qrcode.common.filter.dubbo.AccessLogExtFilter.invoke(AccessLogExtFilter.java:85)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)
    at com.xxx.log.rpc.dubbo.CatTransaction.invoke(CatTransaction.java:82)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)
    at com.alibaba.dubbo.rpc.filter.ContextFilter.invoke(ContextFilter.java:73)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)
    at com.alibaba.dubbo.rpc.filter.GenericFilter.invoke(GenericFilter.java:138)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)
    at com.alibaba.dubbo.rpc.filter.ClassLoaderFilter.invoke(ClassLoaderFilter.java:38)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)
    at com.alibaba.dubbo.rpc.filter.EchoFilter.invoke(EchoFilter.java:38)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)
    at com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol$1.reply(DubboProtocol.java:104)
    at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:96)
    at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:173)
    at com.alibaba.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:51)
    at com.alibaba.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:57)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: connect timed out
    at redis.clients.jedis.Connection.connect(Connection.java:207)
    at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:93)
    at redis.clients.jedis.BinaryJedis.connect(BinaryJedis.java:1767)
    at redis.clients.jedis.JedisFactory.makeObject(JedisFactory.java:106)
    at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:819)
    at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:429)
    at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:360)
    at redis.clients.util.Pool.getResource(Pool.java:49)
    ... 48 common frames omitted
Caused by: java.net.SocketTimeoutException: connect timed out //为什么获取不到连接?本质原因是因为网络不通,即本地和测试环境的redis不通
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:579)
    at redis.clients.jedis.Connection.connect(Connection.java:184)
    ... 55 common frames omitted
复制代码

根据报错信息打断点,然后调试源码,得到调用栈

makeObject:101, JedisFactory (redis.clients.jedis) //由于网络不通,导致创建连接失败
create:819, GenericObjectPool (org.apache.commons.pool2.impl) //创建新的连接
borrowObject:429, GenericObjectPool (org.apache.commons.pool2.impl)
borrowObject:360, GenericObjectPool (org.apache.commons.pool2.impl) //连接池底层实现是pool
getResource:49, Pool (redis.clients.util) //从连接池获取连接
getResource:226, JedisPool (redis.clients.jedis)
getConnectionFromSlot:66, JedisSlotBasedConnectionHandler (redis.clients.jedis)
runWithRetries:116, JedisClusterCommand (redis.clients.jedis)
runWithRetries:141, JedisClusterCommand (redis.clients.jedis)
run:31, JedisClusterCommand (redis.clients.jedis)
set:114, JedisCluster (redis.clients.jedis)
lock:28, JedisUtil (xxx.xxx.util)
lockWithOrderUK:2013, xxx (xxx.xxx.xxxserver.impl)
xxx:69, xxx (xxx.xxx.xxxserver.impl)
xxxAndJsPay:1760, xxx (xxx.xxx.xxxserver.impl)
invokeMethod:-1, Wrapper1 (com.alibaba.dubbo.common.bytecode)
doInvoke:47, JavassistProxyFactory$1 (com.alibaba.dubbo.rpc.proxy.javassist)
invoke:76, AbstractProxyInvoker (com.alibaba.dubbo.rpc.proxy)
invoke:52, DelegateProviderMetaDataInvoker (com.alibaba.dubbo.config.invoker)
invoke:56, InvokerWrapper (com.alibaba.dubbo.rpc.protocol)
invoke:11, AppNameAppendFilter (com.xxx.log.rpc.dubbo)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:62, ExceptionFilter (com.alibaba.dubbo.rpc.filter)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:42, TimeoutFilter (com.alibaba.dubbo.rpc.filter)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:60, ExecuteLimitFilter (com.alibaba.dubbo.rpc.filter)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:75, MonitorFilter (com.alibaba.dubbo.monitor.support)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:78, TraceFilter (com.alibaba.dubbo.rpc.protocol.dubbo.filter)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:85, AccessLogExtFilter (xxx.qrcode.common.filter.dubbo)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:82, CatTransaction (com.xxx.log.rpc.dubbo)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:73, ContextFilter (com.alibaba.dubbo.rpc.filter)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:138, GenericFilter (com.alibaba.dubbo.rpc.filter)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:38, ClassLoaderFilter (com.alibaba.dubbo.rpc.filter)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
invoke:38, EchoFilter (com.alibaba.dubbo.rpc.filter)
invoke:72, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
reply:104, DubboProtocol$1 (com.alibaba.dubbo.rpc.protocol.dubbo)
handleRequest:96, HeaderExchangeHandler (com.alibaba.dubbo.remoting.exchange.support.header)
received:173, HeaderExchangeHandler (com.alibaba.dubbo.remoting.exchange.support.header)
received:51, DecodeHandler (com.alibaba.dubbo.remoting.transport)
run:57, ChannelEventRunnable (com.alibaba.dubbo.remoting.transport.dispatcher)
runWorker:1145, ThreadPoolExecutor (java.util.concurrent)
run:615, ThreadPoolExecutor$Worker (java.util.concurrent)
run:745, Thread (java.lang)
复制代码

源码分析

Pool

public T getResource() {
  try {
    return internalPool.borrowObject(); //从连接池获取连接
  } catch (NoSuchElementException nse) {
    throw new JedisException("Could not get a resource from the pool", nse);
  } catch (Exception e) { //如果网络不通,就会报错:套接字超时(上面报错信息里就是这个错误)
    throw new JedisConnectionException("Could not get a resource from the pool", e);
  }
}
复制代码

GenericObjectPool

/**
 * Borrow an object from the pool using the specific waiting time which only
 * applies if {@link #getBlockWhenExhausted()} is true.
 * <p>
 * If there is one or more idle instance available in the pool, then an
 * idle instance will be selected based on the value of {@link #getLifo()},
 * activated and returned. If activation fails, or {@link #getTestOnBorrow()
 * testOnBorrow} is set to <code>true</code> and validation fails, the
 * instance is destroyed and the next available instance is examined. This
 * continues until either a valid instance is returned or there are no more
 * idle instances available.
 * <p>
 * If there are no idle instances available in the pool, behavior depends on
 * the {@link #getMaxTotal() maxTotal}, (if applicable)
 * {@link #getBlockWhenExhausted()} and the value passed in to the
 * <code>borrowMaxWaitMillis</code> parameter. If the number of instances
 * checked out from the pool is less than <code>maxActive,</code> a new
 * instance is created, activated and (if applicable) validated and returned
 * to the caller.
 * <p>
 * If the pool is exhausted (no available idle instances and no capacity to
 * create new ones), this method will either block (if
 * {@link #getBlockWhenExhausted()} is true) or throw a
 * <code>NoSuchElementException</code> (if
 * {@link #getBlockWhenExhausted()} is false). The length of time that this
 * method will block when {@link #getBlockWhenExhausted()} is true is
 * determined by the value passed in to the <code>borrowMaxWait</code>
 * parameter.
 * <p>
 * When the pool is exhausted, multiple calling threads may be
 * simultaneously blocked waiting for instances to become available. A
 * "fairness" algorithm has been implemented to ensure that threads receive
 * available instances in request arrival order.
 *
 * @param borrowMaxWaitMillis The time to wait in milliseconds for an object
 *                            to become available
 *
 * @return object instance from the pool
 *
 * @throws NoSuchElementException if an instance cannot be returned
 */
public T borrowObject(long borrowMaxWaitMillis) throws Exception {
    assertOpen();

    AbandonedConfig ac = this.abandonedConfig;
    if (ac != null && ac.getRemoveAbandonedOnBorrow() &&
            (getNumIdle() < 2) &&
            (getNumActive() > getMaxTotal() - 3) ) {
        removeAbandoned(ac);
    }

    PooledObject<T> p = null;

    // Get local copy of current config so it is consistent for entire
    // method execution
    boolean blockWhenExhausted = getBlockWhenExhausted();

    boolean create;
    long waitTime = 0;

    while (p == null) {
        create = false;
        if (blockWhenExhausted) {
            p = idleObjects.pollFirst();
            if (p == null) {
                create = true;
                p = create(); //创建新的连接
            }
            if (p == null) {
                if (borrowMaxWaitMillis < 0) {
                    p = idleObjects.takeFirst();
                } else {
                    waitTime = System.currentTimeMillis();
                    p = idleObjects.pollFirst(borrowMaxWaitMillis,
                            TimeUnit.MILLISECONDS);
                    waitTime = System.currentTimeMillis() - waitTime;
                }
            }
            if (p == null) {
                throw new NoSuchElementException(
                        "Timeout waiting for idle object");
            }
            if (!p.allocate()) {
                p = null;
            }
        } else {
            p = idleObjects.pollFirst();
            if (p == null) {
                create = true;
                p = create();
            }
            if (p == null) {
                throw new NoSuchElementException("Pool exhausted");
            }
            if (!p.allocate()) {
                p = null;
            }
        }

        if (p != null) {
            try {
                factory.activateObject(p);
            } catch (Exception e) {
                try {
                    destroy(p);
                } catch (Exception e1) {
                    // Ignore - activation failure is more important
                }
                p = null;
                if (create) {
                    NoSuchElementException nsee = new NoSuchElementException(
                            "Unable to activate object");
                    nsee.initCause(e);
                    throw nsee;
                }
            }
            if (p != null && getTestOnBorrow()) {
                boolean validate = false;
                Throwable validationThrowable = null;
                try {
                    validate = factory.validateObject(p);
                } catch (Throwable t) {
                    PoolUtils.checkRethrow(t);
                    validationThrowable = t;
                }
                if (!validate) {
                    try {
                        destroy(p);
                        destroyedByBorrowValidationCount.incrementAndGet();
                    } catch (Exception e) {
                        // Ignore - validation failure is more important
                    }
                    p = null;
                    if (create) {
                        NoSuchElementException nsee = new NoSuchElementException(
                                "Unable to validate object");
                        nsee.initCause(validationThrowable);
                        throw nsee;
                    }
                }
            }
        }
    }

    updateStatsBorrow(p, waitTime);

    return p.getObject();
}
复制代码
/**
 * Creates a new wrapped pooled object.
 *
 * @return The new wrapped pooled object
 *
 * @throws Exception if the creation of the pooled object fails
 */
private PooledObject<T> create() throws Exception {
    int localMaxTotal = getMaxTotal();
    long newCreateCount = createCount.incrementAndGet();
    if (localMaxTotal > -1 && newCreateCount > localMaxTotal ||
            newCreateCount > Integer.MAX_VALUE) {
        createCount.decrementAndGet();
        return null;
    }

    final PooledObject<T> p;
    try {
        p = factory.makeObject(); //创建连接
    } catch (Exception e) {
        createCount.decrementAndGet();
        throw e;
    }

    AbandonedConfig ac = this.abandonedConfig;
    if (ac != null && ac.getLogAbandoned()) {
        p.setLogAbandoned(true);
    }

    createdCount.incrementAndGet();
    allObjects.put(p.getObject(), p);
    return p;
}
复制代码

JedisFactory

@Override
public PooledObject<Jedis> makeObject() throws Exception {
  final HostAndPort hostAndPort = this.hostAndPort.get();
  final Jedis jedis = new Jedis(hostAndPort.getHost(), hostAndPort.getPort(), connectionTimeout,
      soTimeout, ssl, sslSocketFactory, sslParameters, hostnameVerifier);

  try {
    jedis.connect(); //创建连接
    if (null != this.password) {
      jedis.auth(this.password);
    }
    if (database != 0) {
      jedis.select(database);
    }
    if (clientName != null) {
      jedis.clientSetname(clientName);
    }
  } catch (JedisException je) { //如果网络不通,报错:套接字连接超时
    jedis.close();
    throw je;
  }

  return new DefaultPooledObject<Jedis>(jedis);

}
复制代码

初始化连接池

方法调用栈

启动项目,调用栈如下:

discoverClusterNodesAndSlots:53, JedisClusterInfoCache (redis.clients.jedis)
initializeSlotsCache:39, JedisClusterConnectionHandler (redis.clients.jedis)
<init>:17, JedisClusterConnectionHandler (redis.clients.jedis)
<init>:20, JedisSlotBasedConnectionHandler (redis.clients.jedis)
<init>:15, JedisSlotBasedConnectionHandler (redis.clients.jedis)
<init>:41, BinaryJedisCluster (redis.clients.jedis)
<init>:83, JedisCluster (redis.clients.jedis)
afterPropertiesSet:80, JedisClusterConfig (com.xxx.redis.business) //1.在配置文件会配置这个自定义类的数据
2.afterPropertiesSet方法就是初始化redis集群配置

invokeInitMethods:1571, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
initializeBean:1509, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
doCreateBean:521, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:458, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
getObject:296, AbstractBeanFactory$1 (org.springframework.beans.factory.support)
getSingleton:223, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
doGetBean:293, AbstractBeanFactory (org.springframework.beans.factory.support)
getBean:194, AbstractBeanFactory (org.springframework.beans.factory.support)
preInstantiateSingletons:610, DefaultListableBeanFactory (org.springframework.beans.factory.support)
finishBeanFactoryInitialization:932, AbstractApplicationContext (org.springframework.context.support)
refresh:479, AbstractApplicationContext (org.springframework.context.support)
configureAndRefreshWebApplicationContext:389, ContextLoader (org.springframework.web.context)
initWebApplicationContext:294, ContextLoader (org.springframework.web.context)
contextInitialized:112, ContextLoaderListener (org.springframework.web.context)
listenerStart:5197, StandardContext (org.apache.catalina.core)
startInternal:5720, StandardContext (org.apache.catalina.core)
start:145, LifecycleBase (org.apache.catalina.util)
addChildInternal:1018, ContainerBase (org.apache.catalina.core)
addChild:994, ContainerBase (org.apache.catalina.core)
addChild:662, StandardHost (org.apache.catalina.core)
manageApp:1899, HostConfig (org.apache.catalina.startup)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:57, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:606, Method (java.lang.reflect)
invoke:301, BaseModelMBean (org.apache.tomcat.util.modeler)
invoke:819, DefaultMBeanServerInterceptor (com.sun.jmx.interceptor)
invoke:801, JmxMBeanServer (com.sun.jmx.mbeanserver)
createStandardContext:619, MBeanFactory (org.apache.catalina.mbeans)
createStandardContext:566, MBeanFactory (org.apache.catalina.mbeans)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:57, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:606, Method (java.lang.reflect)
invoke:301, BaseModelMBean (org.apache.tomcat.util.modeler)
invoke:819, DefaultMBeanServerInterceptor (com.sun.jmx.interceptor)
invoke:801, JmxMBeanServer (com.sun.jmx.mbeanserver)
invoke:468, MBeanServerAccessController (com.sun.jmx.xxx.security)
doOperation:1487, RMIConnectionImpl (javax.management.xxx.rmi)
access$300:97, RMIConnectionImpl (javax.management.xxx.rmi)
run:1328, RMIConnectionImpl$PrivilegedOperation (javax.management.xxx.rmi)
doPrivileged:-1, AccessController (java.security)
doPrivilegedOperation:1427, RMIConnectionImpl (javax.management.xxx.rmi)
invoke:848, RMIConnectionImpl (javax.management.xxx.rmi)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:57, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:606, Method (java.lang.reflect)
dispatch:322, UnicastServerRef (sun.rmi.server)
run:202, Transport$2 (sun.rmi.transport)
run:199, Transport$2 (sun.rmi.transport)
doPrivileged:-1, AccessController (java.security)
serviceCall:198, Transport (sun.rmi.transport)
handleMessages:567, TCPTransport (sun.rmi.transport.tcp)
run0:828, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
access$400:619, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
run:684, TCPTransport$ConnectionHandler$1 (sun.rmi.transport.tcp)
run:681, TCPTransport$ConnectionHandler$1 (sun.rmi.transport.tcp)
doPrivileged:-1, AccessController (java.security)
run:681, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
runWorker:1145, ThreadPoolExecutor (java.util.concurrent)
run:615, ThreadPoolExecutor$Worker (java.util.concurrent)
run:745, Thread (java.lang)
复制代码

源码分析

自定义redis集群配置类

1.在项目配置文件里配置自定义类

<bean name="genericObjectPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> //redis连接池配置类
 <property name="maxWaitMillis" value="3000" />
 <property name="maxTotal" value="200" />
 <property name="minIdle" value="10" />
 <property name="maxIdle" value="50" />
</bean>

<!-- 属性文件里 key的前缀 soTimeout: 返回值的超时时间 maxAttempts:出现异常最大重试次数-->
<bean id="jedisClusterConfigA" class="com.xxx.redis.business.JedisClusterConfig"> //自定义配置类
 <property name="addressConfig">
  <value>classpath:redis.properties</value>
 </property>
 <property name="addressKeyPrefix" value="addressA" />
 <property name="timeout" value="10000" />
 <property name="maxRedirections" value="3" />
 <property name="genericObjectPoolConfig" ref="genericObjectPoolConfig" /> //使用连接池
</bean>
复制代码

2.自定义类核心代码
启动项目的时候,初始化redis集群配置

@Override  
public void afterPropertiesSet() throws Exception {  
    Set<HostAndPort> haps = this.parseHostAndPort();  
      
    jedisCluster = new JedisCluster(haps, timeout, maxRedirections,genericObjectPoolConfig);  
      
} 
复制代码

JedisClusterInfoCache

public class JedisClusterInfoCache {
  private final Map<String, JedisPool> nodes = new HashMap<String, JedisPool>(); //4主4从,总共8个节点
  private final Map<Integer, JedisPool> slots = new HashMap<Integer, JedisPool>(); //4个主
 
public void discoverClusterNodesAndSlots(Jedis jedis) {
  w.lock();

  try {
    reset();
    List<Object> slots = jedis.clusterSlots();

    for (Object slotInfoObj : slots) { //slots是4个主
      List<Object> slotInfo = (List<Object>) slotInfoObj;

      if (slotInfo.size() <= MASTER_NODE_INDEX) {
        continue;
      }

      List<Integer> slotNums = getAssignedSlotArray(slotInfo);

      // hostInfos
      int size = slotInfo.size();
      for (int i = MASTER_NODE_INDEX; i < size; i++) {
        List<Object> hostInfos = (List<Object>) slotInfo.get(i);
        if (hostInfos.size() <= 0) {
          continue;
        }

        HostAndPort targetNode = generateHostAndPort(hostInfos);
        setupNodeIfNotExist(targetNode);
        if (i == MASTER_NODE_INDEX) {
          assignSlotsToNode(slotNums, targetNode);
        }
      }
    }
  } finally {
    w.unlock(); //方法执行完成之后,slots和nodes初始化完毕
  }
}
复制代码

总结

套接字超时问题,基本上都是网络不通。

参考

juejin.cn/post/691715…

分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改