Mysql

什麼會導致 RDS MySQL 數據庫可用儲存空間快速下降?

  • July 21, 2019

我在 Amazon RDS 上的 MySQL 數據庫最近如何在大約 1.5 小時內從 10.5 GB 免費變為“儲存已滿”狀態?

這是一個執行在 db.t2.micro 實例上的 15GB MySQL 5.6.27 數據庫。通常每天只添加幾百 KB。

大約一天前,免費儲存空間在大約 1.5 小時內從 10.5 GB 變為基本上 0 GB。寫入 IOPS 圖表僅顯示了我在該時間段內的正常低流量流量,因此顯然數據必須是在伺服器端生成的。

一個可能相關的註釋是我的數據庫有大約 7,000 個表,並且 innodb_file_per_table 設置為 1。

類似的事件顯然發生在 8 天前,但沒有那麼嚴重,我什至沒有註意到它,因為它沒有填滿儲存空間。

螢幕截圖顯示 8 天前的事件以及一天前的儲存填充事件 在此處輸入圖像描述

顯示儲存填充事件詳細視圖的螢幕截圖 在此處輸入圖像描述

我不是數據庫專家,這是我的一個愛好項目,所以我正在努力弄清楚如何開始解決這個問題!

編輯 1

我開始查看@RolandoMySQLDBA 提供的答案,我意識到我遺漏了一些非常有用的細節。

寫入數據庫的唯一系統是兩個 EC2 實例,它們每 30 分鐘寫入一次,這對應於圖中的儲存減少量。

這兩個系統都從網路上收集相同的數據,然後它們都嘗試在半小時內同時將收集到的數據寫入我的數據庫。我使用兩個數據收集系統只是為了冗餘,並且我對我的寫入常式進行了編碼,以便每個系統都將嘗試使用 INSERT IGNORE INTO 寫入其所有數據,因此無論哪個系統首先寫入該特定數據都會獲勝,而第二個系統的插入嘗試是簡單地忽略了。

在每 30 分鐘發生一次的寫入期間,除了一個表之外,數據庫中的數千個表中的每一個中都會插入一行。該表中沒有插入任何內容,但其(大約)2000 行中的每一行都會更新,一次更新。

編輯 2

在添加了大約 2.5GB 的數據後,我從某個點恢復了一個數據庫實例(如第一個螢幕截圖所示,8/16 上的事件),這樣我就可以執行命令而不會遇到“儲存已滿”錯誤。

在@RolandoMySQLDBA 的幫助下,我能夠看到有多少 InnoDB 和 MyISAM 數據正在使用中(如何監控 MySQL 空間?)。這是輸出:

rudy InnoDB 761.72 MB   0.00 B  761.72 MB 
rudy Total  761.72 MB   0.00 B  761.72 MB 
sys InnoDB  16.00 KB    0.00 B  16.00 KB 
sys Total   16.00 KB    0.00 B  16.00 KB 
Database Total  761.73 MB   0.00 B  761.73 MB

我還執行了以下命令來檢查數據庫中所有表的“Data_Length”:

show table status from rudy;

我將該命令的輸出導出到 CSV 文件,將其作為電子表格導入,然後將所有數據長度相加,總數為 798,720,00。

所以在這一點上我很困惑。如果根據您的命令輸出,表中有大約 798MB,整個數據庫中有大約 761MB,那麼還有什麼可能佔用大約 4.5GB(15GB 實例,約 10.5GB 的免費儲存空間)?

有沒有其他方法可以查看我的 RDS 實例上還有什麼可能佔用空間?

編輯 3

我通過僅使用一個系統寫入數據庫並刪除所有更新語句來簡化我的測試場景,所以現在我在數據庫上所做的所有程式碼基本上都是這樣的(使用 python 3 和 pymysql):

query = "INSERT IGNORE INTO {tn} (Timestamp, Price, Flags, Sales, Total) VALUES(%s,%s,%s,%s,%s)".format(tn=table_name)
self.cursor.execute(query, (timestamp, price, flags, sales, total))

這是我要插入的表的 DDL:

query = "CREATE TABLE IF NOT EXISTS {tn} (Timestamp INT PRIMARY KEY, Price BIGINT, Flags INT, Sales INT, Total INT)".format(tn=table_name)
self.cursor.execute(query)

在我的簡化程式碼中,我只插入了大約 2000 個這種類型的表,每個表有 1,000 到 11,000 行。

我可以通過上述測試設置一致地重現該問題。

極光工作正常!

我還嘗試將快照遷移到 Aurora 並執行測試場景,但沒有出現問題!我想堅持使用 MySQL 伺服器,因為它更便宜,但如果沒有人可以幫助我解決這個問題,那麼我可能會永久轉向 Aurora。

這是您在 MySQL RDS 伺服器中寫入的文件夾

mysql> select * from information_schema.global_variables where variable_name in
   -> ('innodb_log_group_home_dir','innodb_data_home_dir','innodb_data_file_path');
+---------------------------+------------------------+
| VARIABLE_NAME             | VARIABLE_VALUE         |
+---------------------------+------------------------+
| INNODB_LOG_GROUP_HOME_DIR | /rdsdbdata/log/innodb  |
| INNODB_DATA_FILE_PATH     | ibdata1:12M:autoextend |
| INNODB_DATA_HOME_DIR      | /rdsdbdata/db/innodb   |
+---------------------------+------------------------+
3 rows in set (0.00 sec)

您的 ibdata1 文件位於/rdsdbdata/db/innodb其中,您的重做日誌位於/rdsdbdata/log/innodb.

我擔心的是你的ibdata1文件。由於在假設您沒有 MyISAM 表的情況下啟用了 innodb_file_per_table,因此唯一可能導致增長的是 MVCC。大量的選擇和寫入會導致 InnoDB 創建大量的回滾資訊。該資訊可以拉伸ibdata1文件。這些年來我一直在討論這個問題:

您可以OPTIMIZE TABLE針對所有 InnoDB 表執行以提供一些收縮。請參閱我 5 年前的文章為什麼 InnoDB 將所有數據庫儲存在一個文件中?有關如何縮小表格的想法。

不幸的是,在你現在的狀態下你不能這樣做。請參閱此 YouTube 影片。至於您無法列出您的數據庫,請注意:

mysql>  show global variables like 'tmpdir';
+---------------+----------------+
| Variable_name | Value          |
+---------------+----------------+
| tmpdir        | /rdsdbdata/tmp |
+---------------+----------------+
1 row in set (0.00 sec)

SHOW創建臨時表這樣的元命令。整個磁碟已滿。

壞消息

創建只讀副本不會縮小任何內容。RDS 只會拍攝快照並設置複製。

這樣做ALTER TABLE會縮小表格,而不是ibdata1.

啟動一個新的 RDS 實例並從頭開始載入將從一個新的 ibdata1 開始。

更新 2017-08-25 12:21 EDT

回顧您的圖表,我可以看到您每 30 分鐘發送的數據過多。嘗試一次更新 500 行而不是 2000 行。請記住,就 ibdata1 增長而言,大量更新與大量插入一樣糟糕。

研究您的查詢。也許您有一個“交叉連接”(JOIN沒有說明這些表是如何相關的),這會生成一個巨大的中間表。你能發現 的大小ibdata1嗎?變大了嗎?如果沒有,還有什麼文件?

引用自:https://dba.stackexchange.com/questions/184299