【案例】常駐查詢引發的thread pool 效能問題之一

風塵_NULL發表於2017-02-17
問題現象
    線上某業務A的資料庫版本MySQL 從5.5 升級到5.6 版本之後多次出現RT抖動的問題,其現象主要為:
    1 rt嚴重不穩定,部分query rt非常高。
    2 orzdba間歇性阻塞。

二 原理知識

    在MySQL Thread Pool根據引數thread_pool_size被分為若干個group,每個group維護client 發起的 connections,當MySQL建立 connection 時, MySQL 根據connection的thread id 對thread_pool_size取模,將connection 發起的sql 語句分配到對應的group。每個group的最大worker數量為thread_pool_oversubscribe+1。若worker達到最大數量後還是不足以處理回話請求,則連線在本group上等待,導致sql 語句的rt 增大。

三 問題分析
    目前線上的配置引數thread_pool_size為32,thread_pool_oversubscribe 為3 ,也即是ThreadPool共有32個group,每個group最多可容許4個worker。但是業務A的場景中存在6個binlog dump任務和2個從庫和1個日誌抓取任務,因為COM_BINLOG_DUMP命令是個執行時間非常長的命令(可以理解為slow query),因此其長期持有worker。當一個group被2個及以上COM_BINLOG_DUMP命令長期持有的時候,相對於其他group其處理能力會下降到其他group的1/2甚至1/4,最嚴重的會導致完全阻塞一個group。
Thread Pool本身沒有存在group之間的均衡策略,因此新的連線還是會均勻的分配到所有的group上,當負載較大的時候,被COM_BINLOG_DUMP佔有的group出現了嚴重的排隊現象。
   在業務A場景中排隊時間大約在10-30秒之間,因此有部分query的rt達到10-30秒;而大部分query還是被分配到正常的group上,其rt還是正常的。根據觀察,一般擁堵的group在1-2個之間,因此影響1/32 ~ 1/16的query .

四 驗證
    根據以上的原理,為了更好的復現,將thread_pool_oversubscribe調整為2,即每個group有2個worker;同時將thread_pool_size調整為3.
透過鎖表阻塞的方法模擬落在group 1的2個COM_BINLOG_DUMP,此時group 1只剩下1個worker,而group 0和group 2還剩在3個worker。
併發向mysql傳送select sleep(2),來模擬業務
case 1
 
同一時間併發發起18個query。這時每個group分到6個query。因為g0和g2都有3個worker,因此這些query在4秒鐘時處理完畢,但是g1只有1個worker,需要12秒
測試結果如下:符合預期

  1. [root@rac1:/u01/test]$sh test_rt.sh 
  2. Sun Oct 12 15:13:42 CST 2014
  3. Sun Oct 12 15:13:42 CST 2014
  4. Sun Oct 12 15:13:42 CST 2014
  5. Sun Oct 12 15:13:42 CST 2014
  6. Sun Oct 12 15:13:42 CST 2014
  7. Sun Oct 12 15:13:42 CST 2014
  8. Sun Oct 12 15:13:42 CST 2014
  9. Sun Oct 12 15:13:44 CST 2014
  10. Sun Oct 12 15:13:44 CST 2014
  11. Sun Oct 12 15:13:44 CST 2014
  12. Sun Oct 12 15:13:44 CST 2014
  13. Sun Oct 12 15:13:44 CST 2014
  14. Sun Oct 12 15:13:44 CST 2014
  15. Sun Oct 12 15:13:44 CST 2014
  16. Sun Oct 12 15:13:46 CST 2014
  17. Sun Oct 12 15:13:48 CST 2014
  18. Sun Oct 12 15:13:50 CST 2014
  19. Sun Oct 12 15:13:52 CST 2014
case 2:
    開始時發起6個query,以後每隔2秒併發發起3個query。因為每個query本身耗時2秒,因此對於g0和g2完全能夠處理這種併發,但是g1只有1個worker,因此永遠都有一個query需要等待,所以被分配到g1上的query都需要等待2秒後才能被執行。
這個時候開啟orzdba就會發現有1/3的機率被hang住2秒。線上出現的就是這種現象。

五 解決
1 系統層面 透過改大thread_pool_oversubscribe和thread_pool_size可以極大的減小這種現象的發生,但是不能完全的避免;
同時大量的常駐長連線是否合理(業務A中有9個拉binlog的連線常駐),也值得商榷(減少常駐連線也可以極大的減小這種現象的發生)。
2 原始碼設計層面:針對類似於binlogdump 的常駐連結存在很多最佳化點,針對binlogdump 這種長連線最佳化worker持有策略或者計數方式。

感謝 江疑 同學的詳細分析。
test_rt.sh 指令碼內容
 
  1. #!/bin/bash
  2. function test()
  3. {
  4.     mysql.local -e \'select sleep(2)\' > /dev/null
  5.     date
  6. }

  7. function r1()
  8. {
  9.     for i in {1..18};
  10.     do
  11.         test &
  12.     done
  13. }

  14. function r2()
  15. {
  16.     for i in {1..3};
  17.     do
  18.         test &
  19.     done
  20. }

  21. function r3()
  22. {
  23.     for i in {1..9000};
  24.     do
  25.         r2
  26.         sleep 2
  27.     done
  28. }

  29. r1



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30221425/viewspace-2133749/,如需轉載,請註明出處,否則將追究法律責任。

相關文章