1.發現問題
生產環境發現有一些redis報錯日志 connection pool exhausted。如果redis中沒有數據 就直接回源 查DB。暫時不會有什么大問題。中文意思是連接池耗盡。
2.追蹤問題
查看源碼
我們用的redis客戶端類似於redigo 按照錯誤提示搜索到了一段代碼(基於最新的redigo 源碼版本分析)
// Handle limit for p.Wait == false.
if !p.Wait && p.MaxActive > 0 && p.active >= p.MaxActive {
p.mu.Unlock()
return nil, ErrPoolExhausted
}
源碼解析
這段代碼的意思是 如果沒有配置為等待模式。且配置了連接池的最大活躍個數 如果當前活躍個數大於配置的最大活躍 則返回連接池耗盡的錯誤。所以需要調大這個MaxActive參數。
MaxIdle 參數
除了MaxActive 之外還有一個MaxIdle參數。
func (p *Pool) put(pc *poolConn, forceClose bool) error {
p.mu.Lock()
if !p.closed && !forceClose {
pc.t = nowFunc()
p.idle.pushFront(pc)
if p.idle.count > p.MaxIdle {
pc = p.idle.back
p.idle.popBack()
} else {
pc = nil
}
}
if pc != nil {
p.mu.Unlock()
pc.c.Close()
p.mu.Lock()
p.active--
}
if p.ch != nil && !p.closed {
p.ch <- struct{}{}
}
p.mu.Unlock()
return nil
}
連接池的具體實現是通過一個鏈表來實現的。如果發現連接池里面的空閑個數超過了MaxIdle,就會把尾部的連接刪除 把最新的連接放到頭部。類似將老的連接刪掉,加入最新的。
3.解決問題
最終通過調大 MaxActive 和 MaxIdle 參數解決了連接池耗盡的問題