生產環境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,在業務高峰期,服務器資源緊張,新來的請求如果獲取不到資源,立即報錯返回,保證現有業務的正常運行算是一種權衡的辦法。