成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

由FTWRL導致的MySQL從庫死鎖分析及參數深究

數據庫 MySQL
最近線上執行備份的從庫時出現復制卡死現象,分析以后發現是兩個死鎖,show full processlist的狀態如圖1所示,其中,數據庫版本是官方5.7.18版本,我們內部做了些許修改,但與此次死鎖無關。

最近線上執行備份的從庫時出現復制卡死現象,分析以后發現是兩個死鎖,show full processlist的狀態如圖1所示,其中,數據庫版本是官方5.7.18版本,我們內部做了些許修改,但與此次死鎖無關。   

                     

圖一

 

先說一下結論,圖一中:

  • 162線程是執行innobackup執行的flush tables with read lock;
  • 144是SQL線程,并行復制中的Coordinator線程;
  • 145/146是并行復制的worker線程,145/146worker線程隊列中的事務可以并行執行。

144Coordinator線程分發relaylog中事務時發現這個事務不能執行,要等待前面的事務完成提交,所以處于waiting for dependent transaction to commit的狀態。145/146線程和備份線程162形成死鎖,145線程等待162線程 global read lock 釋放,162線程占有MDL::global read lock 全局讀鎖,申請全局commit lock的時候阻塞等待146線程,146線程占有MDL:: commit lock,因為從庫設置slave_preserve_commit_order=1,保證從庫binlog提交順序,而146線程執行事務對應的binlog靠后面,所以等待145的事務提交。最終形成了145->162->146->145的死循環,形成死鎖。

同樣的,圖二中:

  • 183是備份程序執行的flush tables with read lock;
  • 165是SQL線程,并行復制的Coordinator線程;
  • 166/167是并行復制的worker線程。 

圖二

 

165Coordinator線程分發的事務還不能執行,進入waiting for dependent transaction to commit的狀態,183、166、167三個線程形成死鎖,183占有全局讀鎖,獲取全局commit鎖的時候進入阻塞,等待167釋放事務涉及到表的commit鎖;166,167的事務可以并行復制,167占有表級commit鎖,但是事務對應的binlog在后面,阻塞等待166先提交進入waiting for preceding transaction to commit的狀態;166線程事務執行時提交要獲得表級commit鎖,但已經被183占有,所以阻塞等待。這樣形成了183->167->166->183的死鎖。 

三個線程相互形成死鎖,在我的經驗中還是很少見的,又因為涉及的MDL鎖是服務層的鎖,死鎖檢測也不會起作用。 

死鎖原因分析 

1、MDL鎖 

參考:http://mysql.taobao.org/monthly/2015/11/04/ 

2、flush tables with read lock獲取兩個鎖 

MDL::global read lock 和MDL::global commit lock,而且是顯示的MDL_SHARED鎖。    

  1. //Global_read_lock::lock_global_read_lock 
  2.  
  3.     MDL_REQUEST_INIT(&mdl_request,MDL_key::GLOBAL"""", MDL_SHARED, MDL_EXPLICIT); 
  4.  
  5.     //Global_read_lock::make_global_read_lock_block_commit 
  6.  
  7.     MDL_REQUEST_INIT(&mdl_request,MDL_key::COMMIT"""", MDL_SHARED, MDL_EXPLICIT);  

3、事務執行中涉及兩個鎖 

在所有更新數據的代碼路徑里,除了必須的鎖外,還會額外請求MDL_key::GLOBAL鎖的MDL_INTENTION_EXCLUSIVE鎖;在事務提交前,會先請求MDL_key::COMMIT鎖的MDL_INTENTION_EXCLUSIVE鎖。對于scope鎖來說,IX鎖和S鎖是不兼容的。 

4、--slave_preserve_commit_order      

  1. For multi-threaded slaves, enabling this variable ensures that  
  2.  
  3.      transactions are externalized on theslave in the same order as they appear 
  4.  
  5.      in the slave's relay log.  

slave_preserve_commit_order=1時,relay-log中事務的提交順序會嚴格按照在relay-log中出現的順序提交。 

所以,事務的執行和flush tables with read lock語句獲得兩個鎖都不是原子的,并行復制時模式下按以下的順序就會出現死鎖。 

  1. 事務A、B可以并行復制,relay-log中A在前,slave_preserve_commit_order=1
  2. 從庫回放時B事務執行較快,先執行到commit,獲得commit鎖,并進入waiting for   preceding transaction to commit的狀態
  3. 執行flush tables with read lock,進入waiting  for commit的狀態
  4. 事務A執行。事務A如果在FTWRL語句獲得global read lock鎖之后執行,那么事務A就進入waiting for global  read lock的狀態,即第一種死鎖;如果事務A在FTWRL獲得global read lock之前執行,同時FTWRL獲得global commit鎖之后應用Xid_event提交事務,則進入 waiting for the commit lock的狀態,即第二種死鎖。  

復現 

理解了死鎖出現的原因后,重現就簡單多了。重現這個死鎖步驟主要是2步: 

1、在主庫構造并行復制的事務,利用debug_sync          

  1. session 1 
  2.  
  3. SET DEBUG_SYNC='waiting_in_the_middle_of_flush_stage SIGNAL s1 WAIT_FOR f'
  4.  
  5. insert into test.test values(13);//事務A 
  6.  
  7.   
  8.  
  9. //session 2 
  10.  
  11. SET DEBUG_SYNC= 'now WAIT_FOR s1';  
  12.  
  13. SET DEBUG_SYNC= 'bgc_after_enrolling_for_flush_stage SIGNAL f';    
  14.  
  15. insert into test.test values(16);//事務B  

2、從庫執行,修改源代碼,在關鍵地方sleep若干時間,控制并行復制的worker的執行并留出足夠時間執行flush tables with read lock 

修改點如下:       

  1. //Xid_apply_log_event::do_apply_event_worker 
  2.  
  3.          if(w->id==0) 
  4.  
  5.          { 
  6.  
  7.              std::cout<<"before commit"<<std::endl; 
  8.  
  9.              sleep(20); 
  10.  
  11.          } 
  12.  
  13.          //pop_jobs_item 
  14.  
  15.          if(worker->id==0)     
  16.  
  17.              sleep(20);   

開啟slave以后,觀察show full processlist和輸出日志,在其中一個worker出現wait for  preceding transaction to commit以后,執行 ftwrl,出現圖1的死鎖;wait for  preceding transaction to commit以后,出現日志before commit之后,執行 ftwrl,出現圖2的死鎖。 

如何解決? 

出現死鎖以后如果不人工干預,IO線程正常,但是SQL線程一直卡住,一般需要等待lock-wait-timeout時間,這個值我們線上設置1800秒,所以這個死鎖會產生很大影響。 

那么如何解決呢?kill !kill哪個線程呢? 

  • 對圖1的死鎖,146處于wait for  preceding transaction狀態的worker線程實際處于mysql_cond_wait的狀態,kill不起作用,所以只能kill 145線程或者備份線程,如果kill145worker線程,整個并行復制就報錯結束,show slave status顯示SQL異常退出,之后需要手動重新開啟sql線程,所以最好的辦法就是kill執行flush tables with read lock的線程,代價最小。
  • 至于圖2的死鎖,則只能kill掉執行flush tables with read lock的線程。所以出現上述死鎖時,kill執行flush tables with read lock的備份線程就恢復正常,之后擇機重新執行備份即可。 

如何避免? 

設置xtrabackup的kill-long-queries-timeout參數可以避免第一種死鎖的出現,其實不算避免,只是出現以后xtrabackup會殺掉阻塞的執行語句的線程;但是這個參數對第二種死鎖狀態則無能為力了,因為xtrabackup選擇殺掉的線程時,會過濾Info!=NULL。 

另外還有個參數safe-slave-backup,執行備份的時候加上這個參數會停掉SQL線程,這樣也肯定不會出現這個死鎖,只是停掉SQL未免太暴力了,個人不提倡這樣做。 

可以設置slave_preserve_commit_order=0關閉從庫binlog的順序提交,關閉這個參數只是影響并行復制的事務在從庫的提交順序,對最終的數據一致性并無影響,所以如果無特別要求從庫的binlog順序必須與主庫保持一致,可以設置slave_preserve_commit_order=0避免這個死鎖的出現。 

關于xtrabackup  kill-long-query-type參數 

首先說下```kill-long-queries-timeout,kill-long-query-type```參數,文檔介紹如下  

  1. --KILL-LONG-QUERY-TYPE=ALL|SELECT 
  2.  
  3.      This option specifies which types of queries should be killed to  
  4.  
  5.      unblock the global lock. Default is “all”. 
  6.  
  7. --KILL-LONG-QUERIES-TIMEOUT=SECONDS** 
  8.  
  9.      This option specifies the number of seconds innobackupex waits  
  10.  
  11.      between starting FLUSH TABLES WITH READ LOCK and killing those queries  
  12.  
  13.      that block it. Default is 0 seconds, which means innobackupex will not  
  14.  
  15.      attempt to kill any queries. In order to use this option xtrabackup  
  16.  
  17.      user should have PROCESS and SUPER privileges.Where supported (Percona  
  18.  
  19.      Server 5.6+) xtrabackup will automatically use Backup Locks as a  
  20.  
  21.      lightweight alternative to FLUSH TABLES WITH READ LOCK to copy non- 
  22.  
  23.      InnoDB data to avoid blocking DML queries that modify InnoDB tables.  

參數的作用的就是在Xtrabackup執行FLUSH TABLES WITH READ LOCK以后,獲得全局讀鎖時,如果有正在執行的事務會阻塞等待,kill-long-queries-timeout參數不為0時,xtrabackup內部創建一個線程,連接到數據庫執行show full processlist,如果TIME超過kill-long-queries-timeout,會kill掉線程,kill-long-query-type設置可以kill掉的SQL類型。 

官方文檔介紹kill-long-query-type默認值時all,也就是所有語句都會kill掉。但在使用中發現,只設置kill-long-queries-timeout,未設置kill-long-query-type時,參數沒起作用!最后查閱xtrabackup代碼,如下:   

  1. {"kill-long-query-type", OPT_KILL_LONG_QUERY_TYPE, 
  2.  
  3.    "This option specifies which types of queries should be killed to " 
  4.  
  5.    "unblock the global lock. Default is \"all\"."
  6.  
  7.    (uchar*) &opt_ibx_kill_long_query_type, 
  8.  
  9.    (uchar*) &opt_ibx_kill_long_query_type, &query_type_typelib, 
  10.  
  11.    GET_ENUM, REQUIRED_ARG, QUERY_TYPE_SELECT, 0, 0, 0, 0, 0}  

心中一萬頭草泥馬,也許只是筆誤,但也太坑爹了!所以使用kill-long-query-type時一定要自己指定好類型! 

總結 

回顧這次執行備份的從庫復制卡死故障,根本原因在于flush tables with read lock語句和事務執行的過程都涉及到連個鎖,而且不是原子的,再加上并行復制以及設置了從庫binlog的順序提交,最終導致三個線程形成死鎖。在尋找問題的解決方案中,意外發現了Xtrabackup kill-long-query-type的“秘密”,告誡我們在使用中盡量顯示指定參數,一方面更準確,另一方面也便于查看。 

另外,我們知道set global read_only=1語句執行中涉及到的鎖和flush tables with read lock涉及的鎖時一樣的,也是兩個MDL鎖,所以理論上在并行復制的從庫執行set global read_only=1語句也可能會出現上述的兩個死鎖,有興趣的可以驗證下。 

責任編輯:龐桂玉 來源: DBAplus社群
相關推薦

2017-06-07 16:10:24

Mysql死鎖死鎖日志

2011-08-24 17:41:16

MySQL死鎖

2024-08-27 22:04:37

2017-06-14 22:11:57

數據庫MySQL死鎖

2021-07-04 22:29:12

MySQL死鎖云日志

2023-12-30 09:44:27

MySQL算法數據庫

2016-03-07 09:09:35

blockios開發實踐

2020-07-16 21:20:08

數據庫MySQL死鎖

2021-03-26 10:40:16

MySQL鎖等待死鎖

2024-04-01 00:01:05

MySQL死鎖DDL

2020-04-14 10:20:12

MySQL數據庫死鎖

2024-10-16 11:40:47

2024-03-25 12:38:00

MySQL內存參數

2018-05-29 11:44:22

數據庫MySQL死鎖

2023-09-13 14:52:11

MySQL數據庫

2023-07-18 09:24:04

MySQL線程

2023-11-09 11:56:28

MySQL死鎖

2023-11-09 08:00:00

NoSQL數據庫

2011-08-18 11:31:06

MySQL性能分析explain

2023-10-11 22:24:00

DubboRedis服務器
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 操操操av| 国产日韩欧美精品 | 亚洲高清三级 | 97视频在线观看网站 | 国产小视频精品 | 青青草免费在线视频 | 久久精品久久久 | 国产精品a久久久久 | 国产清纯白嫩初高生视频在线观看 | 国产高清视频在线观看播放 | 久久精品久久久 | 成人伊人| 亚洲精选一区 | 久久久久久成人网 | 久久亚洲一区 | 亚洲成人av | av黄色在线观看 | 九九伦理电影 | 狠狠综合网 | 欧美天堂 | 成人在线视频一区 | 国产精品综合久久 | 一区二区三区在线 | 国产精品一区二区三区在线 | 怡红院成人在线视频 | 综合国产 | 久草网在线视频 | 乳色吐息在线观看 | 罗宾被扒开腿做同人网站 | 国产精品v| 一本大道久久a久久精二百 国产成人免费在线 | 国产japanhdxxxx麻豆 | 日韩在线国产精品 | 日韩午夜在线播放 | 亚洲中午字幕 | 亚洲精品一区二区三区四区高清 | 国产高清在线精品一区二区三区 | 亚洲成人免费视频 | 欧美日韩中文字幕在线 | 自拍偷拍亚洲一区 | 91精品国产综合久久久久 |