【MySQL經典案例分析】 Waiting for table metadata lock

来源:https://www.cnblogs.com/qcloud1001/archive/2018/12/12/10107439.html
-Advertisement-
Play Games

本文由雲+社區發表 一、 問題是這樣來的 ​ 2018年某個周末,接到連續資料庫的告警,告警信息如下: 二、 苦逼的探索過程 1、總體的思路 看到too many connection的報錯信息,基本上可以把問題定位在: (1)機器負載飆升,導致SQL執行效率下降,導致連接推積 (2)業務訪問量突增 ...


本文由雲+社區發表

一、 問題是這樣來的

​ 2018年某個周末,接到連續資料庫的告警,告警信息如下:

img

二、 苦逼的探索過程

1、總體的思路

看到too many connection的報錯信息,基本上可以把問題定位在:

(1)機器負載飆升,導致SQL執行效率下降,導致連接推積

(2)業務訪問量突增(或者有SQL註入現象),導致連接數打滿

(3)出現“死鎖”或者鎖競爭嚴重,導致大量SQL堆積

2、排查過程

(1)機器的各項性能指標都顯示正常, 沒有出現高負載現象,暫時先排除了這種原因

(2)查看監控信息,發現在連接數打滿的時間點前並沒有訪問量突增的趨勢,同時通過檢查告警信息並沒有發現有註入工單

img

(3)最後上到伺服器上查看下SQL的執行情況

①查看show full processlist;

img

​ 大量的請求都是在“Waiting for table metadata lock”,可以分成三類請求:

  • Select請求
  • Rename請求
  • Sleep請求

②分析Waiting for table metadata lock

​ 一般來說常見的“Waiting for table metadata lock”會出現在DDL操作或者是有未提交的事務上,從information_schema.processlist表中,沒有發現有DDL操作,而能夠產生MDL鎖的操作也只剩下rename,但是根據SQL執行的狀態,rename操作也是在等待MDL鎖,所以rename操作應該是被阻塞的操作,而不是產生MDL鎖的操作。

​ 接著我們來查看下死鎖和事務的相關指標:

  • show engine innodb status;中沒有任何死鎖的信息
  • information_schema.innodb_trx 、information_schema.innodb_locks 、 information_schema.innodb_lock_waits 的也沒有任何形式的鎖信息。

​ 現在基本又排除了顯示的死鎖問題,那是從show full processlist中也抓不出任何請求,這裡就比較疑惑了,當看了下表的結構式,發現這個表是myisam引擎的,所以上面的兩種統計信息裡面沒有任何值就可以解釋了。

img

​ 那麼其實問題就集中在有未結束的事務上了,這裡其實有一個誤區,當時跟開發溝通存在未關閉的事務時,開發一直認為不可能,因為myisam表是不支持事務的,只有innodb支持事務。但是對於MDL鎖來說,5.5之後引入MDL事務級別的鎖不論對myisam還是innodb都是生效的。

③查看未提交的事務

​ 之後查看了下系統的事務自動提交的變數,autocommit的值是ON,那說明如果是事務未提交的話只可能是業務主動的開啟一個事務,而沒有commit。

img

​ 為了驗證這個猜想,打開了general log,在log中果然發現,業務在開啟事務後,把autocommit的值設為0了,導致必須要顯示的commit才能提交事務。

img

img

​ 這時候我們反過頭來看一下host為10.49.84.70的連接請求,由於select的執行速度很快,而且訪問並不頻繁,所以在抽樣的show processlist中,狀態值大部分時間是“Sleep”,給問題的定位帶來了一些迷惑性的干擾。接著我們kill掉了這個進程,果然推積的請求瞬間就執行完成了,也之間印證了剛剛上述推論。

2、問題解決

​ 在與開發同學溝通過程中,開發同學說庫中是myisam表所以不會主動開啟事務,在代碼里也沒有設置autocommit=0的代碼,那麼根本原因在哪?

​ 當我們定位到這台伺服器上的請求都是來自python的定時腳本,使用python 操作mysql的時候,使用了其pymysql模塊,但是在進行插入操作的時候,必須使用受到提交事務。Python的pymysql模塊預設是會設置autocommit=0的。

img

​ 讓我們來對比一下其他同樣使用python訪問的正常連接請求,再斷開前都會手動的commit。

img

​ 找到原因後有思考了下,是不是可以在建連後就設置autocommit=1呢?這樣對於之後新變更的SQL就不要再考慮到手動commit的事情了,可以通過在初始化連接池的時候,對每一個連接進行設置,即

img

三、 延伸的一些思考

1、metadata lock

(1)MDL簡述

​ 為了在併發環境下維護表元數據的數據一致性,在表上有活動事務(顯式或隱式)的時候,不可以對元數據進行寫入操作。因此從MySQL5.5版本開始引入了MDL鎖(metadata lock),來保護表的元數據信息,用於解決或者保證DDL操作與DML操作之間的一致性。

​ 對於引入MDL,其主要解決了2個問題,一個是事務隔離問題,比如在可重覆隔離級別下,會話A在2次查詢期間,會話B對錶結構做了修改,兩次查詢結果就會不一致,無法滿足可重覆讀的要求;另外一個是數據複製的問題,比如會話A執行了多條更新語句期間,另外一個會話B做了表結構變更並且先提交,就會導致slave在重做時,先重做alter,再重做update時就會出現複製錯誤的現象。所以在對錶進行上述操作時,如果表上有活動事務(未提交或回滾),請求寫入的會話會等待在Metadata lock wait 。

​ 支持事務的InnoDB引擎表和不支持事務的MyISAM引擎表,都會出現Metadata Lock Wait等待現象。一旦出現Metadata Lock Wait等待現象,後續所有對該表的訪問都會阻塞在該等待上,導致連接堆積,業務受影響。

(2)常見MDL鎖場景

①當前有執行DML操作時執行DDL操作

② 當前有對錶的長時間查詢或使用mysqldump/mysqlpump時,使用alter會被堵住

③ 顯示或者隱式開啟事務後未提交或回滾,比如查詢完成後未提交或者回滾,DDL會被堵住

④ 表上有失敗的查詢事務,比如查詢不存在的列,語句失敗返回,但是事務沒有提交,此時DDL仍然會被堵住

2、myisam、innodb對事務的支持

​ Myisam是不支持事務的,innodb是支持事務的,這個概念其實沒有任何問題,但是這裡只的都是對於數據的事務性操作的支持,通過如下簡單的實驗可以很清楚的理解(關於事務的相關概念和解釋就不再贅述了,只是想區別一下mysiam不支持事務,但是主動開始事務中對Myisam的操作仍然會產生MDL鎖):

​ 在隔離級別為RC的情況下:

(1)myisam表

① CREATE TABLE tb2 (a int(11) DEFAULT NULL ) ENGINE=MyISAM;

② Session 1:

​ mysql> begin ;

​ mysql> insert into tb2(a) value(1);

​ (在session2的update之後)

​ mysql> select * from tb2;

​ +--------+

​ | a |

​ +--------+

​ | 3 |

​ +--------+

Session 2:

​ mysql> select * from tb2;

​ +---------+

​ | a |

​ +---------+

​ | 1 |

​ +---------+

​ mysql> update tb2 set a=3 where a=1;

​ mysql> select * from tb2;

​ +--------+

​ | a |

​ +--------+

​ | 3 |

​ +--------+

​ mysql> alter table tb2 add b int(11);

... hangs ...

(2)innodb表

①CREATE TABLE tb3 (a int(11) DEFAULT NULL ) ENGINE=INNODB;

② Session 1:

​ mysql> begin ;

​ mysql> insert into tb3(a) value(1);

​ Session 2:

​ mysql> select * from tb3;

​ Empty set (0.00 sec)

3、myisam表的另一個BUG

(1)場景

① CREATE TABLE tb2 (a int(11) DEFAULT NULL ) ENGINE=MyISAM;

② Session 1:

​ mysql> begin ;

​ mysql> select * from tb2;

​ Session 2:

​ mysql> create table if not exists tb2(a int);

​ ... hangs ...

③查看show processlist

​ Session 1:Sleep

​ Session 2:Waiting for table metadata lock

(2)解決方式

①session 1上commit或者rollback

②另外再開一個session3 ,kill掉可疑連接

此文已由作者授權騰訊雲+社區發佈

搜索關註公眾號「雲加社區」,第一時間獲取技術乾貨,關註後回覆1024 送你一份技術課程大禮包!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • redis資料庫 redis有以下三個特點 redis支持數據的持久化,可以將記憶體中的數據保存在磁碟中,重啟的時候可以再次載入進行使用 redis不僅僅支持簡單的key-value類型的數據,同時還提供list,set,zset,hash等數據結構的存儲 redis支持數據的備份,即master-s ...
  • 嚴謹轉載--否則追究法律責任 作者 王加鴻 bug 1 解決方案 將這兩個路徑下的文件清空即可 ↑ 解決方案: 暫無(如無法連接,會自動創建連接,但可能長久後會造成連接過多) bug 3 解決方案:初步分析,是埋點數據產生的json格式解析出問題了 後來查看源代碼在org.apache.flume. ...
  • 樹 樹,大家都見過,以這種形式的數據關係,就是樹。下麵看一張圖,瞭解什麼是根節點(樹幹)、節點或分叉、葉(葉節點) connect by 級聯查詢 connect by可以用於級聯查詢,常用於對具有樹狀結構的記錄查詢某一節點的所有子孫節點或所有祖輩節點。 來看一個示例,現假設我們擁有一個菜單表t_m ...
  • 一. Redis的介紹 Redis 是一個Key-Value存儲的系統;它支持存儲的value類型有string(字元串),list(列表),set(集合),zset(有序集合);為了保證效率;數據都緩存在記憶體中;它也周期性將記憶體數據寫入磁碟或者把讀寫操作寫入記錄文件。Redis使用單線程模型;還有 ...
  • update B b set b.value=(select max(a.value) from A a where b.key=a.key) where exists(select 1 from A c where b.key=c.key) UPDATE A a,(select a.`key`,b... ...
  • 1 MYSQL常用命令 2 1.導出整個資料庫 3 mysqldump -u 用戶名 -p –default-character-set=latin1 資料庫名 > 導出的文件名(資料庫預設編碼是latin1) 4 mysqldump -u wcnc -p smgp_apps_wcnc > wcnc ...
  • redis資料庫的基本類型分析: 1、string 最基本的數據類型。只存貯一個值,key-value,最大值存儲512M. 創建命令:hmset 讀取命令:hget 2、hash 集合,存儲為一個集合。適合一個對象的存儲。創建命令:hmset ,field1 field2...,其中field1這 ...
  • 因為很多存儲過程都會共用一段sql語句,所以我把共用的sql封裝成一個自定義函數 AddCapital(); 然後通過存儲過程調用,創建存儲過程會報錯1415,Not allowed to return a result set from a function(不允許從函數返回結果集);因為存儲過程 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...