本文参考: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%的可靠服务。代码需要能够捕获异常和异常处理,而不是应用程序报错。