最近、Amazon RDS上のMySQLデータベースは、約1.5時間以内に10.5 GBの空き容量から「ストレージフル」ステータスになりましたか?
これは、db.t2.microインスタンスで実行される15GBのMySQL 5.6.27データベースです。通常、1日あたり数百キロバイトしか追加されません。
約1日前に、約1.5時間で空きストレージ容量が10.5 GBから基本的に0 GBになりました。書き込みIOPSチャートには、その期間の私の通常の少量トラフィックのみが表示されているため、データはサーバー側で生成されたはずです。
関連する可能性のあるメモの1つは、私のデータベースには約7,000のテーブルがあり、innodb_file_per_tableが1に設定されていることです。
同様のインシデントが8日前に起こったようですが、それほど深刻ではなく、ストレージスペースがいっぱいにならなかったので気づきませんでした。
8日前のインシデントと1日前のストレージ容量不足のインシデントを示すスクリーンショット
ストレージがいっぱいになるインシデントの詳細ビューを示すスクリーンショット
私はデータベースの専門家ではありません。これは私の趣味のプロジェクトのためです。そのため、これのトラブルシューティングを開始する方法さえ理解するのに少し苦労しています!
@RolandoMySQLDBAが提供する回答を検討し始めたところ、いくつかの非常に役立つ詳細が省略されていることに気付きました。
データベースに書き込む唯一のシステムは、30分ごとにデータベースに書き込む2つのEC2インスタンスです。これは、グラフに示されているストレージ削減に対応しています。
これらのシステムはどちらもWebから同じデータを収集しており、収集したデータを30分後にデータベースに同時に書き込みます。私は冗長性のために2つのデータ収集システムを使用しており、各システムがINSERT IGNORE INTOを使用してすべてのデータを書き込もうとするようにコーディングルーチンをコーディングしています。単に無視されます。
30分ごとに発生する書き込み中に、1つのテーブルを除いて、データベース内の数千のテーブルのそれぞれに1つの行が挿入されます。そのテーブルには何も挿入されませんが、その(おおよそ)2000行は、一度に1つずつ更新されます。
約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インスタンスのスペースを占有している可能性があるものを確認する方法はありますか?
1つのシステムのみを使用してデータベースに書き込み、すべての更新ステートメントを削除することで、テストシナリオを簡略化しました。これで、データベースで実行しているすべてのコードは基本的にこれです(python 3 with 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
にあり、REDOログは/rdsdbdata/log/innodb
にあります。
心配なのはあなたのibdata1
ファイルです。 innodb_file_per_table が有効になっているAMDはMyISAMテーブルがないと想定しているため、成長を引き起こす可能性があるのはMVCCのみです。大量の選択と書き込みにより、InnoDBが大量のロールバック情報を作成する可能性があります。その情報はibdata1
ファイルを拡張できます。私はこれを長年にわたって議論してきました:
Apr 23, 2013
: innodb_file_per_tableが設定されている場合でも、Innodb ibdata1ファイルを5倍に拡大するにはどうすればよいですか?Mar 31, 2014
: テーブルがいっぱいであるために失敗した1つのクエリの後で、mysqlディレクトリが246Gに増加しますJun 04, 2014
: ndoログを既存のサーバーのMySQL 5.6のibdata1の外に移動できますか?Jun 16, 2014
: テーブルでのMySQLインデックス作成の失敗がいっぱいですAug 21, 2015
: MySQLのトランザクションDDLワークフローすべてのInnoDBテーブルに対してOPTIMIZE TABLE
を実行して、ある程度の縮小を提供できます。テーブルを縮小する方法については、5年前の投稿 InnoDBがすべてのデータベースを1つのファイルに保存するのはなぜですか? のアイデアを参照してください。
残念ながら、現在の状態ではそれを行うことはできません。 この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が開始されます。
グラフを振り返ると、30分ごとに大量のデータを送信していることがわかります。 2000行ではなく500行を一度に更新してみてください。大量の更新は、ibdata1の増加という点で、大量の挿入と同じくらい悪いことに注意してください。
クエリを調べます。おそらく「クロスジョイン」(JOIN
はテーブルがどのように関連しているかは言うまでもありません)があり、これにより巨大な中間テーブルが生成されました。 ibdata1
のサイズはわかりますか?巨大になりましたか?そうでない場合、他のどのファイルですか?
同様のことが私たちにも起こり、SELECTクエリがマージソート用の大規模な中間テーブルを生成するファンキーな実行プランであることがわかりました。これはディスクに書き込まれ、サーバーが再起動するまでクリーンアップされません。
それがあなたに起こったのであれば、それがおそらくAuroraレプリカが問題なかった理由です-開始時に一時テーブルを削除したので、どのレプリカも問題なかったでしょう:)
1分のダウンタイムが気にならない場合は、オフにしてから再度オンにすることをお勧めします。