咱們在 Percona 支持欄目常常收到關於 MySQL 的 ibdata1 文件的這個問題。當監控服務器發送一個關於 MySQL 服務器存儲的報警時,恐慌就開始了 —— 就是說磁盤快要滿了。一番調查後你意識到大多數地盤空間被 InnoDB 的共享表空間 ibdata1 使用。而你已經啓用了 innodb_file_per_table,因此問題是:php
當你啓用了 innodb_file_per_table
,表被存儲在他們本身的表空間裏,可是共享表空間仍然在存儲其它的 InnoDB 內部數據:html
其中的一些在 Percona 服務器上能夠被配置來避免增加過大的。例如你能夠經過 innodb_ibuf_max_size 設置最大變動緩衝區,或設置 innodb_doublewrite_file 來將雙寫緩衝區存儲到一個分離的文件。mysql
MySQL 5.6 版中你也能夠建立外部的撤銷表空間,因此它們能夠放到本身的文件來替代存儲到 ibdata1。能夠看看這個文檔。ios
當 MySQL 出現問題一般咱們須要執行的第一個命令是:git
1
|
SHOW ENGINE INNODB STATUS/G
|
這將展現給咱們一些頗有價值的信息。咱們從** TRANSACTION(事務)**部分開始檢查,而後咱們會發現這個github
1
2
3
4
|
---TRANSACTION 36E, ACTIVE 1256288 sec
MySQL thread id 42, OS thread handle 0x7f8baaccc700, query id 7900290 localhost root
show engine innodb status
Trx read view will not see trx with id >= 36F, sees < 36F
|
這是一個最多見的緣由,一個14天前建立的至關老的事務。這個狀態是活動的,這意味着 InnoDB 已經建立了一個數據的快照,因此須要在撤銷日誌中維護舊頁面,以保障數據庫的一致性視圖,直到事務開始。若是你的數據庫有大量的寫入任務,那就意味着存儲了大量的撤銷頁。sql
若是你找不到任何長時間運行的事務,你也能夠監控INNODB STATUS 中的其餘的變量,「History list length(歷史記錄列表長度)」展現了一些等待清除操做。這種狀況下問題常常發生,由於清除線程(或者老版本的主線程)不能像這些記錄進來的速度同樣快地處理撤銷。數據庫
很不幸,MySQL 不提供查看什麼被存儲到 ibdata1 共享表空間的信息,可是有兩個工具將會頗有幫助。第一個是馬克·卡拉漢製做的一個修改版 innochecksum ,它發佈在這個漏洞報告裏。ruby
它至關易於使用:服務器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# ./innochecksum /var/lib/mysql/ibdata1
0 bad checksum
13 FIL_PAGE_INDEX
19272 FIL_PAGE_UNDO_LOG
230 FIL_PAGE_INODE
1 FIL_PAGE_IBUF_FREE_LIST
892 FIL_PAGE_TYPE_ALLOCATED
2 FIL_PAGE_IBUF_BITMAP
195 FIL_PAGE_TYPE_SYS
1 FIL_PAGE_TYPE_TRX_SYS
1 FIL_PAGE_TYPE_FSP_HDR
1 FIL_PAGE_TYPE_XDES
0 FIL_PAGE_TYPE_BLOB
0 FIL_PAGE_TYPE_ZBLOB
0 other
3 max index_id
|
所有的 20608 中有 19272 個撤銷日誌頁。這佔用了表空間的 93%。
第二個檢查表空間內容的方式是傑里米·科爾製做的 InnoDB Ruby 工具。它是個檢查 InnoDB 的內部結構的更先進的工具。例如咱們可使用 space-summary 參數來獲得每一個頁面及其數據類型的列表。咱們可使用標準的 Unix 工具來統計撤銷日誌頁的數量:
1
2
|
# innodb_space -f /var/lib/mysql/ibdata1 space-summary | grep UNDO_LOG | wc -l
19272
|
儘管這種特殊的狀況下,innochedcksum 更快更容易使用,可是我推薦你使用傑里米的工具去了解更多的 InnoDB 內部的數據分佈及其內部結構。
好,如今咱們知道問題所在了。下一個問題:
這個問題的答案很簡單。若是你還能提交語句,就作吧。若是不能的話,你必需要殺掉線程開始回滾過程。那將中止 ibdata1 的增加,可是很顯然,你的軟件會出現漏洞,有些人會遇到錯誤。如今你知道如何去鑑定問題所在,你須要使用你本身的調試工具或普通的查詢日誌來找出誰或者什 麼引發的問題。
若是問題發生在清除線程,解決方法一般是升級到新版本,新版中使用一個獨立的清除線程替代主線程。更多信息查看該文檔
沒有,目前尚未一個容易而且快速的方法。InnoDB 表空間從不收縮...參見10 年之久的漏洞報告,最新更新自詹姆斯·戴(謝謝):
當你刪除一些行,這個頁被標爲已刪除稍後重用,可是這個空間從不會被回收。惟一的方法是使用新的 ibdata1 啓動數據庫。要作這個你應該須要使用 mysqldump 作一個邏輯全備份,而後中止 MySQL 並刪除全部數據庫、ib_logfile*、ibdata1* 文件。當你再啓動 MySQL 的時候將會建立一個新的共享表空間。而後恢復邏輯備份。
當 ibdata1 文件增加太快,一般是 MySQL 里長時間運行的被遺忘的事務引發的。嘗試去解決問題越快越好(提交或者殺死事務),由於不通過痛苦緩慢的 mysqldump 過程,你就不能回收浪費的磁盤空間。
也是很是推薦監控數據庫以免這些問題。咱們的 MySQL 監控插件包括一個 Nagios 腳本,若是發現了一個太老的運行事務它能夠提醒你。