redis客户端连接异常

本文参考:http://mdba.cn/2015/04/02/redistwemproxy-%e5%ae%a2%e6%88%b7%e7%ab%af%e8%bf%9e%e6%8e%a5%e5%bc%82%e5%b8%b8/

对于一个DBA,客户端连接异常问题可以说是家常便饭的事情,处理多了都想吐。

root cause无疑发生在三个地方,先找自身的原因,依次排查下去:
1)服务器端db的负载,如果负载太高,创建socket太慢引起超时。另外服务器端socket的个数太多,也可以导致创建连接需要很长的时间或者创建连接不成功。
2)网络是够有抖动,包括lvs/twemproxy重启操作。
3)客户端的连接配置参数是否合理,连接池的大小,超时参数大小。还有客户端服务器的状态,负载和tcp连接状况。
下面是近三个工作日碰到的redis/twemproxy连接问题。

1、不合理的jedispool配置,连接池设置的太小
错误信息:

daemon prio=10 tid=0x00002ab367888000 nid=0x1881 in Object.wait()
[0x00002ab3e5754000] java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1315)
at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:557)
...

监控的连接数显示:redis的连接数每秒维持在200+个, 比较正常。
jedispool配置:最大允许创建的连接个数为50个,相比连接数,这个值偏小。

解决方法:
1)增大连接池的大小,但是不要太大,避免客户端和服务器端维持大量的空闲了连接。
2)可以设置minIdle和EvictIdle的时间,加快获取连接对象和释放空闲的连接。
3)设置testOnBorrow=True参数,每次get连接时候进行连接有效性检测。
ps:jedis/jedispool的很多默认参数配置并不适合用,需要按照应用需求何求调整。

下面提供一个供参考的redis配置文件:

<bean name="poolConfig" class="org.apache.commons.pool2.impl.GenericObjectPoolConfig">
        <property name="maxTotal" value="500"/>
        <property name="maxIdle" value="200"/>
        <property name="minIdle" value="50"/>
        <property name="testOnBorrow" value="true" /> 
    </bean>

    <bean name="jedisCluster" class="redis.clients.jedis.JedisCluster" scope="singleton">
        <constructor-arg index="0">
            <!-- 配置redis集群节点地址 -->
            <set>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg index="0" value="${redis.ip1}"/>
                    <constructor-arg index="1" value="${redis.port1}" type="int"/>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg index="0" value="${redis.ip2}"/>
                    <constructor-arg index="1" value="${redis.port2}" type="int"/>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg index="0" value="${redis.ip3}"/>
                    <constructor-arg index="1" value="${redis.port3}" type="int"/>
                </bean>
            </set>
        </constructor-arg>
        <!-- timeout: 超时时间 -->
        <constructor-arg index="1" value="3000"/>
        <!-- maxRedirections: 最大重定向 -->
        <constructor-arg index="2" value="5"/>
        <!-- 连接池 -->
        <constructor-arg index="3" ref="poolConfig"/>
    </bean>

2、没有返回连接对象
错误信息:
an error occurred when executing function getJedis(): Could not get a resource from the pool
jedispool连接池的使用方式:
Jedis jedis = JedisFactory.jedisPool.getResource();
try{
jedis.set("key","val");
}
finally {
JedisFactory.jedisPool.returnResource(jedis);
}
连接使用完之后,需要归还到连接池中。

3、容错处理
网络链路并不能保证绝对的稳定,db服务也不能提供99.999%的可靠服务。代码需要能够捕获异常和异常处理,而不是应用程序报错。

原文地址:https://www.cnblogs.com/janehoo/p/6123008.html