jedis连接池爆满导致的服务不可用

时间:2022-08-30 17:28:38

生产环境was线程数300,jedis连接池连接数100.

在业务高峰期,查看日志发现大量could not get a resource from a pool的异常,抓取javacore文件发现was线程大量进入parked状态,查看jedis源码发现连接池底层使用common-pool实现,而common-pool其中有这样一段代码:

if (p == null) {
if (borrowMaxWaitMillis < 0) {
p = idleObjects.takeFirst();
} else {
p = idleObjects.pollFirst(borrowMaxWaitMillis,
TimeUnit.MILLISECONDS);
}
}
新来的线程会从jedis自己实现的LinkedBlockingQueue中拿链接,如果连接池没有空闲链接并且已键连接数已达上限,那么
public E pollFirst(long timeout, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(timeout);
lock.lockInterruptibly();
try {
E x;
while ( (x = unlinkFirst()) == null) {
if (nanos <= 0) {
return null;
}
nanos = notEmpty.awaitNanos(nanos);
}
return x;
} finally {
lock.unlock();
}
}
当前线程也就是was线程就会parked等待notEmpty信号,导致大量请求进不来堵死,首先我们考虑参数配置不合理,业务高峰期热点数据在redis中,大量的redis访问,我们改成300was链接,200redis链接,情况明显好转,但是在高峰期仍有部分请求时间超长,was线程parked的现象出现,更改jedis连接池参数,把maxWaitMillis参数调小,从最初的2000毫秒调到500,在业务高峰期,服务器资源紧张,新来的请求如果获取不到资源,立即报错返回,保证现有业务的正常运行算是一种权衡的办法。