揪出MySQL磁盤消耗迅猛的真兇

揪出MySQL磁盤消耗迅猛的真兇
背景


  • Part1:寫在最前
    當一張單表10億數據量的表放在你面前,你將面臨着什麼?

  • Part2:背景介紹

爲了提升數據庫資源利用率,一個實例中,在不互相影響,保證業務高效的前提下,我們會將同一個大業務下的不同小業務放在一個實例中,我們的磁盤空間是2T,告警閾值爲當磁盤剩餘空間10%時發出短信告警。筆者接到某業務主庫磁盤剩餘空間告警的短信後,經過一番查探,發現從幾天前開始,有一張表的數據量增長非常快,而在之前,磁盤空間下降率還是較爲平緩的,該表存在大字段text,其大批量寫入更新,導致磁盤消耗迅猛。

  • 我們首先來看下該表的表結構:
    揪出MySQL磁盤消耗迅猛的真兇
    與業務瞭解得知,該表幾乎沒有刪除操作,由於數據量過大,我們模糊使用auto_increment來作爲表數量預估值,避免count()操作對線上造成的影響。

Part3:案例分析
與業務溝通了解後得知,該表可以清理4個月以前的老舊數據,因此可以使用delete的方式清除,而我們通過表結構可以看出,該表在設計之初,並沒有對updateTime列創建索引,因此以時間爲範圍去進行delete操作,這顯然是不合理的。

經過與業務協商,我們確定了可以將id作爲刪除條件,刪除id<2577754125之前的數據

也就是說,此時的delete語句變爲了:
揪出MySQL磁盤消耗迅猛的真兇
且不說delete操作有多慢,直接執行這樣的SQL也會有諸如長事務告警,從庫大量延遲等併發症產生,因此絕不能在生產庫上進行這種大批量的危險操作。

實戰


Part1:監控
從監控圖我們能看出磁盤下降的趨勢:
揪出MySQL磁盤消耗迅猛的真兇
監控顯示,從6月14日-6月18日期間,磁盤消耗最爲嚴重,與業務溝通得知,618期間大促引發該表存儲量激增導致。

Part2:實戰操作
我們通過查看binlog發現,集羣中binlog的刷新量雖不說像筆者上個案例那樣多麼迅猛,但也絕不是老實本分

揪出MySQL磁盤消耗迅猛的真兇
我們可以看出,在高峯期間,binlog的刷新間隔最短達到了2分鐘寫滿1.1GB的binlog。因此筆者與業務溝通後,首先清理binlog日誌,將 expire_logs_days從7天調整至3天。

同時,清理一些能夠清理的無用日誌、廢舊文件等等。

我們也能在上面的監控圖看到在做完這些清理操作後,磁盤空間剩餘從4%提升至12%,但隨後依舊保持原有速率下降。
Part3:pt-archiver

真兇找到了,我們怎麼辦,別急,使用pt-archiver。pt-archiver工具是percona工具集的一員,是歸檔MySQL大表數據的最佳輕量級工具之一。他可以實現分chunk分批次歸檔和刪除數據,能避免一次性操作大量數據帶來的各種問題。

閒話不多說,一向本着實戰的原則,我們直接上命令:
揪出MySQL磁盤消耗迅猛的真兇
簡單說下常用的參數:
揪出MySQL磁盤消耗迅猛的真兇

Warning:警告這裏就又有個小坑了,的確,我們使用bulk-delete參數能夠增加刪除速率,相比不使用bulk-delete速度能夠提升10倍左右,但問題也就顯現出來,在使用上述命令期間,發現binlog每秒寫入量激增,這又回到了我們說的,哪些情況會導致binlog轉爲row格式。

首先我們需要瞭解到使用bulk-delete時,sql是如下執行的:
揪出MySQL磁盤消耗迅猛的真兇
如果您之前關注過筆者的文章,應該知道,當使用了delete from xxx where xxx limit 語法時,會將binlog_format從mixed轉爲row,這樣的話,刪除的同時,binlog由於轉爲了row格式也在激增,這與我們的預期是不符的。

因此最終的命令爲:
揪出MySQL磁盤消耗迅猛的真兇
去掉了bulk-delete,這樣的話就能夠保證正常的delete,而不加limit,binlog不會轉爲row格式導致磁盤消耗繼續激增。

對於Innodb引擎來說,delete操作並不會立即釋放磁盤空間,新的數據會優先填滿delete操作後的“空洞”,因此從監控來看就是磁盤不會進一步消耗了,說明我們的pt-archiver工具刪除是有效的。

Part4:困惑

首先我們要知道,當你面對一張數據量龐大的表的時候,有些東西就會受限制,例如:

不能alter操作,因爲這會阻塞dml操作。

對於本案例,空間本就不足,也不能使用pt-online工具來完成。

對於不能alter其實是比較要命的,比如開發要求在某個時間段儘快上線新業務,而新業務需要新增列,此時面對這麼龐大的量級,alter操作會異常緩慢。

因此,筆者與研發溝通,儘快採用物理分表的方式解決這個問題,使用物理分表,清理表的操作就會很容易,無需delete,直接drop 老表就可以了。其次,物理分表讓alter語句不會卡住太久,使用pt-online工具也不會一次性佔據過多的磁盤空間誘發磁盤空間不足的告警。

再有就是遷移TiDB,TiDB相較MySQL更適合存儲這類業務。

Part5:再談binlog_format

我們選取其中高峯期的binlog發現其update操作轉爲了row格式,記錄了所有列變更前後的所有信息,而binlog中並未出現update xxx limit這種操作,那又會是什麼引發的row格式記錄呢?

這裏這篇文章又拋出一個新的案例,在官網那篇何時mixed轉row格式中又一個沒有記錄的情況

官方文檔:
揪出MySQL磁盤消耗迅猛的真兇
我們這個案例中又出現了一個新的因素就是:

當表結構中存在多個唯一索引(包括主鍵id),本案例中存在主鍵和UNIQUE KEY uk_mailNo這個唯一索引,且使用了
揪出MySQL磁盤消耗迅猛的真兇
這時,mysql binlog_format就會被轉爲row格式,這個內容也是記錄在官網的其他章節:

https://dev.mysql.com/doc/refman/5.5/en/insert-on-duplicate.html

也就是說,只要業務解決了使用這種語法插入的話,磁盤空間下降迅猛的原因也能夠緩解不少。我們統計發現,qps更高的其他業務中,binlog保留7天的磁盤消耗量在60GB

而該業務我們僅僅保留3天binlog,卻依舊消耗了430GB的磁盤空間,這已經超過了我們整個2T磁盤空間的5分之一了。
——總結——

通過這個案例,我們能夠瞭解到什麼情況下binlog_format會由MIXED格式轉爲ROW格式,以及觸發的一系列併發症和解決辦法,還有pt工具pt-archiver的使用。由於筆者的水平有限,編寫時間也很倉促,文中難免會出現一些錯誤或者不準確的地方,不妥之處懇請讀者批評指正。喜歡筆者的文章,右上角點一波關注,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章