MySQL中經典的too many connection怎么破


 

文章來源:雲棲社區,經同意授權轉載

鏈接:https://yq.aliyun.com/articles/226984?spm=5176.8091938.0.0.nCksaV

 

錯誤解決記錄:
java druid  連接池頻繁初始化后導致的too many connection數據庫報錯。

修改/etc/my.cnf

#加大連接列表數量

max_connections = 2000

# 調整失效連接清理時長 縮短

wait_timeout=7200

interactive_timeout=7200

以上兩個配置項配合使用。

 

 

一、什么是too many connection

 

1、重要參數

 

max_user_connections: The maximum number of simultaneous connections permitted to any given MySQL user account

允許的每個用戶最大鏈接數,如果超過這個數值,則會報: ERROR 1203 (42000): User dba already has more than 'max_user_connections' active connections。

 

一般這樣的報錯只會出現在業務機器上,並不會在DB server層報錯,這樣的話DBA就無法真正感知到錯誤,MySQL也非常貼心的推出了一個status供DBA查看:Connection_errors_max_connections

 

<section class="135brush" style="margin: 10px 0px; padding: 15px 20px 15px 45px; font-size: 14px; line-height: 22.39px; outline: 0px; border-width: 0px; border-style: initial; border-color: currentcolor; color: rgb(62, 62, 62); vertical-align: baseline; box-sizing: border-box; background-image: url(" https:="" mmbiz.qlogo.cn="" mmbiz_jpg="" tibrg3aoijtvy5gucqkfy5hqooqnktqmcc1e2igtetiaodqfbqphxthjdmycxagsoko2flsvbtyh2tekiklw2vcg="" 0?wx_fmt="jpeg&quot;);" ="" background-position:="" 1%="" 5px;="" background-repeat:="" no-repeat;"=""> Connection_errors_max_connections : The number of connections refused because the server max_connections limit was reached.

細心的同學就會發現:那如果出現'max_user_connections' 的報錯,就無法發現啦,這塊目前我還沒找到對應status。

 

二、什么情況下會發生too many connection

 

1、slow query 引起

 

  • 真正的slow:該query的確非常慢

  • 偽裝的slow:該query本身並不慢,是受其它因素的影響導致

 

2、sleep 空連接引起

 

  • 沒有任何query,只是sleep,這種情況一般是代碼里面沒有主動及時釋放鏈接導致。

 

三、實戰案例

 

1、sleep 空鏈接引起的TMC(too many connection簡稱)

 

原因

 

由於代碼沒有主動及時的釋放鏈接,那么在DB Server中存在大量的sleep鏈接,一旦超過max_connections則報錯。

 

解決方案

 

(1)遇到這樣的報錯,如果沒有及時解決,則會導致后面的業務都一直連不上數據庫,影響面很大。

 

(2)所以我們第一件事情必須是保護數據庫,kill掉這些sleep鏈接。關於kill這件事,又有很多技巧可以談:

 

  • 如果是人工kill,這簡直無法完成這樣艱巨的任務,因為業務會時刻產生這樣的sleep鏈接,有無盡頭

  • 如果自己寫腳本,沒秒去kill,當然可行。但是我們卻碰到過非常極端的情況,那就是MySQL無法響應你的kill請求。

  • 所以,這里還有一個更加靠譜的方案就是:設置wait_timeout, 它會自動幫你完成這項龐大且艱巨的任務,且一定可以kill掉

 

(3)完成上面幾個步驟之后,只能保證你的數據庫不會被壓到,且你有機會登陸進去做一些管理事情,但要徹底解決還必須讓業務方處理這些sleep鏈接。

 

  • 業務團隊排查沒有釋放鏈接的原因。

  • 通常,如果可以,DBA協助業務方提供TMC期間top ip,讓業務方排查服務哪里異常。

 

(4)啟用thread_pool功能可能可以解決這個問題,但是由於種種原因沒有使用。

 

  • MySQL官方社區版不支持

  • 無法解決slow query引起的TMC

  • 可能因為該組件導致其本身的問題

 

2、 slow query 引起的TMC

 

(1)先來說說真正的slow query

 

一般這種情況,也非常清晰明了,找到它,優化它,當然前提是你的數據庫還活着。

 

我們通常有SQL防火牆保護,大大降低了這樣的風險。預知SQL防火牆為何物,且聽下回分享。

 

(2)偽裝的slow query

 

好了,終於開始介紹這種最難的故障場景。


難點就是:因為它不是真正的slow,優化點難以尋找,所謂對症下葯,就是要找到對應的症狀,這也是難點所在。


廢話不多說,這里介紹下前一段時間遇到的一次真實的案例。

故障症狀

 

  1. too many connection error

  2. threads_runnig 非常多

  3. 幾乎找不到有問題的query,沒有明顯慢的query

  4. 幾乎任何語句都變得非常慢

  5. 服務器IO壓力並不大

故障分析

 

  重要參數詳解

 

官方文檔的解釋我不多說,這里簡單介紹下自己的理解。

 

  • innodb_thread_concurrency : 進入innodb存儲引擎的線程數量,如果數量滿了,就要排隊

  • innodb_thread_sleep_delay : 排隊等候進入innoDB的時候需要睡眠多長時間

  • innodb_adaptive_max_sleep_delay : 設置一個自適應的最大睡眠時間

  • innodb_concurrency_tickets: 一旦進入innoDB,就會獲取一個票據tickets,在票據期間可以隨意進入innoDB不需要排隊,如果用完了,理論上則要排隊(實測后發現並不是嚴格這套機制)

 

測試故障重現

 

表結構

 

關鍵參數設置

 

set global innodb_thread_concurrency = 1; --方便模擬

測試用例,三個語句開始執行時間不差1秒

 

跟蹤結果

 

 

總結  

 

1. 通過以上測試和結果分析得出:當query超過innodb_thread_concurrency時,其余query會等待,及時這樣的query非常快,也還是會等待,這就是所謂的偽裝的slow query。

 

2. 通過trx_started,now()分析得出:這些query直接的切換輪詢並不是真正意義上的平均公平分配,里面有一套自己的自適應算法,這里面我沒有深究下去,有興趣的同學可以繼續了解源碼。

 

3. 既然真正的原因找到,那么解決方案也就很快出來,那就是讓並發線程少一點,通過我們的omega平台可以很方便地得出這段時間哪些query和connect最多,那么協助業務一起溝通業務場景和優化方案,問題得到解決。

 

 


免責聲明!

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



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