mysql 裏的 ibdata1 文件不斷的增加

咱們在 Percona 支持欄目常常收到關於 MySQL 的 ibdata1 文件的這個問題。當監控服務器發送一個關於 MySQL 服務器存儲的報警時,恐慌就開始了 —— 就是說磁盤快要滿了。一番調查後你意識到大多數地盤空間被 InnoDB 的共享表空間 ibdata1 使用。而你已經啓用了 innodb_file_per_table,因此問題是:php

ibdata1存了什麼?

當你啓用了 innodb_file_per_table,表被存儲在他們本身的表空間裏,可是共享表空間仍然在存儲其它的 InnoDB 內部數據:html

  • 數據字典,也就是 InnoDB 表的元數據
  • 變動緩衝區
  • 雙寫緩衝區
  • 撤銷日誌

其中的一些在 Percona 服務器上能夠被配置來避免增加過大的。例如你能夠經過 innodb_ibuf_max_size 設置最大變動緩衝區,或設置 innodb_doublewrite_file 來將雙寫緩衝區存儲到一個分離的文件。mysql

MySQL 5.6 版中你也能夠建立外部的撤銷表空間,因此它們能夠放到本身的文件來替代存儲到 ibdata1。能夠看看這個文檔ios

什麼引發 ibdata1 增加迅速?

當 MySQL 出現問題一般咱們須要執行的第一個命令是:git

這將展現給咱們一些頗有價值的信息。咱們從** TRANSACTION(事務)**部分開始檢查,而後咱們會發現這個github

這是一個最多見的緣由,一個14天前建立的至關老的事務。這個狀態是活動的,這意味着 InnoDB 已經建立了一個數據的快照,因此須要在撤銷日誌中維護舊頁面,以保障數據庫的一致性視圖,直到事務開始。若是你的數據庫有大量的寫入任務,那就意味着存儲了大量的撤銷頁。sql

若是你找不到任何長時間運行的事務,你也能夠監控INNODB STATUS 中的其餘的變量,「History list length(歷史記錄列表長度)」展現了一些等待清除操做。這種狀況下問題常常發生,由於清除線程(或者老版本的主線程)不能像這些記錄進來的速度同樣快地處理撤銷。數據庫

我怎麼檢查什麼被存儲到了 ibdata1 裏了?

很不幸,MySQL 不提供查看什麼被存儲到 ibdata1 共享表空間的信息,可是有兩個工具將會頗有幫助。第一個是馬克·卡拉漢製做的一個修改版 innochecksum ,它發佈在這個漏洞報告裏。ruby

它至關易於使用:服務器

所有的 20608 中有 19272 個撤銷日誌頁。這佔用了表空間的 93%

第二個檢查表空間內容的方式是傑里米·科爾製做的 InnoDB Ruby 工具。它是個檢查 InnoDB 的內部結構的更先進的工具。例如咱們可使用 space-summary 參數來獲得每一個頁面及其數據類型的列表。咱們可使用標準的 Unix 工具來統計撤銷日誌頁的數量:

儘管這種特殊的狀況下,innochedcksum 更快更容易使用,可是我推薦你使用傑里米的工具去了解更多的 InnoDB 內部的數據分佈及其內部結構。

好,如今咱們知道問題所在了。下一個問題:

我該怎麼解決問題?

這個問題的答案很簡單。若是你還能提交語句,就作吧。若是不能的話,你必需要殺掉線程開始回滾過程。那將中止 ibdata1 的增加,可是很顯然,你的軟件會出現漏洞,有些人會遇到錯誤。如今你知道如何去鑑定問題所在,你須要使用你本身的調試工具或普通的查詢日誌來找出誰或者什 麼引發的問題。

若是問題發生在清除線程,解決方法一般是升級到新版本,新版中使用一個獨立的清除線程替代主線程。更多信息查看該文檔

有什麼方法回收已使用的空間麼?

沒有,目前尚未一個容易而且快速的方法。InnoDB 表空間從不收縮...參見10 年之久的漏洞報告,最新更新自詹姆斯·戴(謝謝):

當你刪除一些行,這個頁被標爲已刪除稍後重用,可是這個空間從不會被回收。惟一的方法是使用新的 ibdata1 啓動數據庫。要作這個你應該須要使用 mysqldump 作一個邏輯全備份,而後中止 MySQL 並刪除全部數據庫、ib_logfile*、ibdata1* 文件。當你再啓動 MySQL 的時候將會建立一個新的共享表空間。而後恢復邏輯備份。

總結

當 ibdata1 文件增加太快,一般是 MySQL 里長時間運行的被遺忘的事務引發的。嘗試去解決問題越快越好(提交或者殺死事務),由於不通過痛苦緩慢的 mysqldump 過程,你就不能回收浪費的磁盤空間。

也是很是推薦監控數據庫以免這些問題。咱們的 MySQL 監控插件包括一個 Nagios 腳本,若是發現了一個太老的運行事務它能夠提醒你。

相關文章
相關標籤/搜索