赞
踩
业务中使用到了Jedis连接池,近期生产业务频繁出现“java.net.SocketException: Broken pipe”的异常堆栈信息,虽然没有影响到生产业务,但是非常烦人,打算来排除一下问题。
这类问题一般是Jedis客户端与服务端之间的服务连接断开了,但是连接池没有及时检测出来,导致坏链一直保存在池中,业务从连接池中取出坏链,导致抛异常。
看一下连接池的配置:
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(PropsUtils.redisPoolMaxIdle);
poolConfig.setMaxIdle(PropsUtils.redisPoolMinIdle);
poolConfig.setMaxTotal(PropsUtils.redisPoolMaxTotal);
poolConfig.setBlockWhenExhausted(PropsUtils.redisPoolBlockWhenExhausted);
poolConfig.setMaxWaitMillis(PropsUtils.redisPoolMaxWaitMillis);
poolConfig.setTestWhileIdle(PropsUtils.redisPoolTestOnIdle);
poolConfig.setTimeBetweenEvictionRunsMillis(PropsUtils.redisPoolTimeBetweenEvictionRunsMillis);
return poolConfig;
设置了TestWhileIdle以及TimeBetweenEvictionRunsMillis,没有设置TestOnBorrow和TestOnReturn.
最简单粗暴的做法应该是直接添加TestOnBorrow和TestOnReturn两项配置为true,可以直接解决问题。
但是这两项配置对性能影响很大,不是最佳实践。 按照规范来说,配置了TestWhileIdle应该足以能够检测出坏链了,为何没有生效。
跟代码看一下TestWhileIdle的执行逻辑:
@Override
public boolean evict(final EvictionConfig config, final PooledObject<T> underTest,
final int idleCount) {
if ((config.getIdleSoftEvictTime() < underTest.getIdleTimeMillis() &&
config.getMinIdle() < idleCount) ||
config.getIdleEvictTime() < underTest.getIdleTimeMillis()) {
return true;
}
return false;
}
只有在当前空闲连接数大于minIdle的时候,才会执行坏链的驱逐。
再看我的minIdle配置,是10, 也就是说,当前业务负载如果比较低,连接数少于10,即使其中有一个空闲坏链, 也无法将其驱逐, 导致业务拿到坏链。
修改将minIdle的配置删除,保持默认配置0,即可解决问题。
P.S. “ java.net.SocketException: Broken pipe”异常只在生产环境有, 测试环境不出现,因为生产环境带了F5,并且定期关闭链接,而测试环境则不会。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。