【案例】常駐查詢引發的thread pool 效能問題之一
一 問題現象
線上某業務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秒
測試結果如下:符合預期
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 指令碼內容
線上某業務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秒
測試結果如下:符合預期
- [root@rac1:/u01/test]$sh test_rt.sh
-
Sun Oct 12 15:13:42 CST 2014
-
Sun Oct 12 15:13:42 CST 2014
-
Sun Oct 12 15:13:42 CST 2014
-
Sun Oct 12 15:13:42 CST 2014
-
Sun Oct 12 15:13:42 CST 2014
-
Sun Oct 12 15:13:42 CST 2014
-
Sun Oct 12 15:13:42 CST 2014
-
Sun Oct 12 15:13:44 CST 2014
-
Sun Oct 12 15:13:44 CST 2014
-
Sun Oct 12 15:13:44 CST 2014
-
Sun Oct 12 15:13:44 CST 2014
-
Sun Oct 12 15:13:44 CST 2014
-
Sun Oct 12 15:13:44 CST 2014
-
Sun Oct 12 15:13:44 CST 2014
-
Sun Oct 12 15:13:46 CST 2014
-
Sun Oct 12 15:13:48 CST 2014
-
Sun Oct 12 15:13:50 CST 2014
- Sun Oct 12 15:13:52 CST 2014
開始時發起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 指令碼內容
- #!/bin/bash
-
function test()
-
{
-
mysql.local -e \'select sleep(2)\' > /dev/null
-
date
-
}
-
-
function r1()
-
{
-
for i in {1..18};
-
do
-
test &
-
done
-
}
-
-
function r2()
-
{
-
for i in {1..3};
-
do
-
test &
-
done
-
}
-
-
function r3()
-
{
-
for i in {1..9000};
-
do
-
r2
-
sleep 2
-
done
-
}
-
- r1
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30221425/viewspace-2133749/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【案例】常駐查詢引發的thread pool 效能問題之二thread
- 優化案例--重建索引引發的sql效能問題優化索引SQL
- 【效能測試】常見的效能問題分析思路(二)案例&技巧
- 一次效能問題原因查詢
- reflow和repaint引發的效能問題AI
- Oracle多層級查詢相容的效能問題Oracle
- mysql 的thread poolMySqlthread
- 由VIP漂移引發的演算法異常問題調查和解決演算法
- Oracle效能問題檢查 - 常用查詢指令碼(final)Oracle指令碼
- BIEB:關於CRM系統查詢效能問題
- sql server datediff函式引發的效能問題SQLServer函式
- 分頁及查詢引數傳遞問題分享
- 併發查詢資料庫問題資料庫
- select查詢之一:普通查詢
- Oracle優化案例-IB網及會話登陸審計引發的效能問題(十七)Oracle優化會話
- 【案例】RAID卡寫策略改變引發的問題AI
- Hystrix Thread Pool 解析thread
- DUBBO Thread pool is EXHAUSTED!thread
- 一個使用JDBC按Date查詢查詢的問題JDBC
- 效能為王:SQL標量子查詢的優化案例分析SQL優化
- 分頁查詢的排序問題排序
- 模板中的名字查詢問題
- Hibernate的Criteria查詢問題。
- 批次查詢的翻頁問題
- sql 模糊查詢問題SQL
- Xilinx問題查詢
- 斷號查詢問題
- 【MySQL】子查詢之一MySql
- Thread pool引數引起的程式連線資料庫響應慢thread資料庫
- .net異常處理的效能問題
- SQL SERVER資料庫datediff函式引發的效能問題SQLServer資料庫函式
- log4j2同步日誌引發的效能問題
- 一次TiDB GC阻塞引發的效能問題分析TiDBGC
- Django ORM 引發的資料庫 N+1 效能問題DjangoORM資料庫
- 一個MySQL多表查詢的問題MySql
- 分頁查詢的排序問題(二)排序
- 從trc查詢死鎖的問題
- 關於Hibernate的查詢問題