redis連接釋放問題記錄


redis連接釋放問題記錄

記錄一次在壓測后發現的redisTemplate使用場景下,redis的連接資源沒有釋放的問題。

@

問題描述

springboot 版本:2.1.2(排除了lettuce的依賴)

jedis版本:2.9.1

場景:高並發情況下,RedisTemplate獲取連接失敗並阻塞線程導致TPS下降。

異常描述:如果設置了max-wait則在等待時間到后拋出異常:Timeout waiting for idle object。如果沒有設置,則線程將被一直阻塞。

問題追蹤

public T borrowObject(long borrowMaxWaitMillis) throws Exception {
    //.....
                                p = (PooledObject)this.idleObjects.takeFirst();
                            } else {
                                p = (PooledObject)this.idleObjects.pollFirst(borrowMaxWaitMillis, TimeUnit.MILLISECONDS);
                            }
                        }

                        if (p == null) {
                            throw new NoSuchElementException("Timeout waiting for idle object");
                        }
                    //.......
}

阻塞點在this.idleObjects.takeFirst()方法,如果設置了等待時間,則調用pollFirst()。debug可以發現,資源沒有釋放。

這個可以看當前對象中的borrowedCount和returnedCount發現,borrowedCount大於returnedCount。

borrowedCount:借用的資源計數

returnedCount:歸還的資源計數

問題定位

borrowObject(long borrowMaxWaitMillis):獲取資源的方法

returnObject(T obj):歸還資源的方法

本來以為是歸還資源的方法有bug導致的資源沒有歸還,但是經過多次debug分析后,發現問題點實際在於jedis的close方法上。

public void close() {
    if (this.dataSource != null) {
        if (this.client.isBroken()) {
            this.dataSource.returnBrokenResource(this);
        } else {
            this.dataSource.returnResource(this);
        }
		//問題點在於這里
        this.dataSource = null;
    } else {
        super.close();
    }
}

場景描述:

在多線程環境下,通過debug可以看到,當前jedis對象是共享的。

假如有線程1,2.

當線程1獲取的資源的持有,線程2等待資源釋放場景。

然后線程1在執行close時,通過returnResource釋放了資源,而線程2拿到了資源。

然后線程2也執行到了close方法,而線程1執行了this.dataSource = null;

這時線程2則不會歸還資源,直接執行了close,導致出現的連接沒有釋放問題。

問題解決

GitHub Issues描述

解決方式:

  1. 升級jedis版本或者回退jedis版本。
  2. 更換連接,可以考慮使用lettuce。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM