Amazon Web Services ブログ

Amazon Aurora MySQLのストレージ使用量を理解する

本稿は、“Understanding Amazon Aurora MySQL storage space utilization” を翻訳したものです。

Amazon Auroraは、高性能な商用データベースが持つパフォーマンス、スケーラビリティ、可用性を提供しながらオープンソースデータベースの持つシンプルさとコスト効率の良さを実現する、フルマネージド型のリレーショナルデータベースサービスです。Amazon Aurora MySQL互換エディションは、MySQLとの互換性を持っており、すでにMySQLテクノロジーを使用している企業にとって魅力的な選択肢となっています。

Amazon Aurora MySQLのストレージは、従来のMySQLデータベースとは異なる方法で管理されています。このポストでは、Amazon Aurora MySQLで利用可能な様々なタイプのストレージ、Auroraがそれらのストレージタイプをどのように使用しているか、そしてストレージの消費状況をどのように監視するかについて説明します。また、Auroraのストレージ料金を見積もるために使用できるデータベースクエリや Amazon CloudWatchメトリクスについても説明します。

ストレージの種類

Auroraには2種類のストレージがあります:

  • クラスターボリュームストレージ – Amazon Aurora MySQLは、耐久性、障害耐性、データの冗長性、高可用性を提供するため、AWS リージョン内の3つのアベイラビリティーゾーンにまたがって分散された共有ストレージレイヤーを使用します。このストレージには、InnoDBテーブルとインデックス、データベースのメタデータ、ファンクションやプロシージャなどのストアドオブジェクト、そしてバイナリログやリレーログなどのその他の永続的なデータが保存されます。
  • ローカルストレージ – クラスター内の各Aurora MySQLインスタンスには、Amazon Elastic Block Store(Amazon EBS)を基盤とするローカルストレージボリュームが割り当てられています。これらのローカルボリュームは、非永続的な一時ファイルやInnoDB以外の一時テーブルの保存、大規模なデータセットの並べ替え、エラー、監査、一般ログなどの各種エンジンログの保存に使用されます。詳細については、 Temporary storage limits for Aurora MySQLを参照してください。

次のセクションでは、Aurora MySQLクラスターにおけるストレージ使用量の一般的な要因と、データベースメトリクスやメタデータを使用してストレージ消費量を確認する方法について説明します。

ユーザーテーブル、インデックス、およびテーブルスペース

ユーザーテーブルとインデックスは、リレーショナルデータベースシステムの永続的なストレージ領域の大部分を占めています。MySQLでは、ストレージエンジンは異なるテーブルタイプのSQL操作を処理するコンポーネントです。InnoDBは、MySQLのデフォルトの汎用ストレージエンジンです。Amazon Aurora MySQLでは、永続的なデータベーステーブルに対してInnoDBストレージエンジンのみがサポートされています。そのため、ここではInnoDBストレージエンジンのコンテキストでのみストレージ使用量について説明します。

従来のMySQLでは、InnoDBストレージエンジンを使用するテーブルは、「.ibd」という拡張子で示されるテーブルスペースと呼ばれるデータファイルに保存されます。詳細については、InnoDB: Tablespace Space Managementを参照してください。

Amazon Auroraは、InnoDBデータストレージに従来のファイルやブロックベースのファイルシステムを使用していませんが、高レベルの概念は同じままです。Auroraはテーブルスペースの概念に従っていますが、これらのテーブルスペースはブロックストレージデバイス上のファイルとしてではなく、Auroraのカスタム設計されたストレージボリューム内のオブジェクトとして存在します。

InnoDBストレージエンジンは、デフォルトでテーブルごとに個別のテーブルスペースを作成して保存します。この動作は、innodb_file_per_tableパラメータによって制御されます。

innodb_file_per_table=ONの場合、エンジンは次のように動作します:

  • 各テーブルは独自のテーブルスペースを持ちます(従来のMySQLにおける.ibdファイルに相当)。
  • テーブルスペースが削除される(Dropされる)と、解放されたデータベースページはストレージボリュームに返却され、新しいデータ用に再利用できるようになります。
  • Auroraは時間の経過とともにこれらの空きページを動的に回収し、ストレージボリュームを縮小することで、ボリューム内の利用可能な容量が増加し、ストレージコストを削減できます。

テーブルスペースがDropされ、その結果としてAuroraが回収できる空きページが生成されるデータベース操作がいくつかあります。各パーティションが個別のテーブルスペースを使用するため、これはテーブルパーティションにも適用されます:

  • テーブルやスキーマのDropにより、基盤となるテーブルスペースが削除されます。
  • テーブルのTruncateは、既存のテーブルスペースを空のものに置き換えます。これは技術的には、Dropして再作成するのと同じです。
  • テーブルの最適化(OPTIMIZEまたはALTERを通じて)は、新しいテーブルスペースを作成し、古いものを削除します。

このような操作を実行した後でも、ボリュームサイズはすぐには減少しません。Auroraは、バックグラウンドで1日最大10 TBのペースで空き領域を徐々に回収します。動的なサイズ変更の詳細については、 Storage scalingを参照してください。

innodb_file_per_table=OFFの場合、動作は次のようになります:

  • テーブルは個別のテーブルスペースを持たず、テーブルデータはシステムテーブルスペース内に格納されます。
  • テーブルのDrop、Truncate、またはOptimizeを行った場合、関連するページはシステムテーブルスペース内で解放されますが、システムテーブルスペースのサイズは減少しません。その結果、Auroraの動的ボリュームサイズ変更機能では、これらのページが占有していた領域を回収することができません。

テーブルスペースが使用している容量を計算するには、INFORMATION_SCHEMA.FILESテーブルを使用できます。INFORMATION_SCHEMA.FILESテーブルは、テーブルごとのテーブルスペース、システムテーブルスペース、グローバル一時テーブルスペース、およびundoテーブルスペースを含む、InnoDBテーブルスペースタイプのメタデータが記録されます。InnoDBテーブルスペースの詳細については、Tablespacesを参照してください。

以下のクエリを使用して、テーブルスペース名とそのサイズを一覧表示できます:

SELECT FILE_NAME,
      TABLESPACE_NAME,
      ROUND((TOTAL_EXTENTS * EXTENT_SIZE) / 1024 / 1024 / 1024, 4) AS SIZE_GB
FROM INFORMATION_SCHEMA.FILES
order by size_gb desc limit 10;

このクエリは、Amazon Aurora MySQL バージョン2(MySQL 5.7互換)とAmazon Aurora MySQL バージョン3(MySQL 8.0互換)の両方で動作します。

なお、テーブルスペースは空の状態でも一定の最小サイズを持ちます。innodb_file_per_tableがONに設定されている場合、空のテーブルやパーティション(行が存在しない状態)でも、数メガバイト程度の少量のストレージを占有します。これは、1つのAuroraクラスターに数千万のテーブルを保存する予定がない限り、通常は問題になりません。可能な限り、innodb_file_per_tableはデフォルトのON設定を使用することを推奨します。

テーブル、インデックス、およびスキーマが使用するストレージ容量を計算する際は、INFORMATION_SCHEMA.TABLESの代わりに(もしくは併用して)INFORMATION_SCHEMA.FILESテーブルの使用を検討すべきです。これは、INFORMATION_SCHEMA.TABLESテーブルにはキャッシュされた統計情報が含まれており、メタデータを読み取る前にテーブルを分析していない場合、その情報が古くなっている可能性があるためです。information_schema_stats_expiryシステム変数(Aurora MySQL バージョン3に適用)は、キャッシュされた統計情報が自動的に期限切れになるまでの期間を定義します。デフォルトは86,400秒(24時間)です。特定のテーブルのキャッシュ値を強制的に更新するには、ANALYZE TABLEコマンドを使用し、その後でINFORMATION_SCHEMA.TABLESの統計情報を確認してください。なお、analyze tableの精度は、innodb_stats_persistentinnodb_stats_transient_sample_pagesパラメータの設定に依存することにご注意ください。

一時テーブルと一時テーブルスペース

一時テーブルスペースについて説明する前に、まず一時テーブルとは何か、いつ使用されるのか、そしてAmazon Aurora MySQL バージョン2とバージョン3での一時テーブルの扱いの違いについて理解する必要があります。

Aurora MySQLには2種類の一時テーブルがあります:

  • 内部(または暗黙的な)一時テーブル – これらのテーブルは、ソート、集約、派生テーブル、共通テーブル式(CTE)などの操作を処理するために、データベースエンジン自体によって作成されます。データベースユーザーはこれらのテーブルを直接制御することはできません。MySQL 5.7での内部一時テーブルの詳細についてはInternal Temporary Table Use in MySQLを、MySQL 8.0についてはInternal Temporary Table Use in MySQLを参照してください。
  • ユーザーが作成した(または明示的な)一時テーブル – これらのテーブルは、CREATE TEMPORARY TABLE文を使用してデータベースクライアントによって作成されます。明示的な一時テーブルは、それを作成したデータベースセッション(接続)内でのみ表示され、セッションが終了すると自動的に削除されます。これらのテーブルは、複雑なSQL処理の実行中に中間データを保存する際に便利で、永続的に保存する必要のないデータに適しています。MySQL 5.7でのこれらのテーブルの詳細についてはCREATE TEMPORARY TABLEを、MySQL 8.0についてはCREATE TEMPORARY TABLEを参照してください。

Amazon Aurora MySQL 2とAurora MySQL 3では、一時テーブルの格納方法に違いがあります。これらの違いの一部はパフォーマンスに影響を与え、他の一部はストレージの消費に影響を与えます。次のセクションでは、ストレージに関連する違いについて簡単に説明します。詳細については、 Use the TempTable storage engine on Amazon RDS for MySQL and Amazon Aurora MySQLを参照してください。

Aurora バージョン2(MySQL 5.7互換)

Aurora バージョン2では、内部一時テーブルはメモリ内に保持され、MEMORYストレージエンジンによって処理されます。メモリ内に作成された内部一時テーブルが大きくなりすぎると、MySQLは自動的にそれをディスクベースのテーブルに変換します。場合によっては、クエリがMEMORYエンジンでサポートされていないデータ型(BLOBやTEXTなど)を含む場合など、データベースは最初からディスクベースのテーブルを使用することがあります。ディスク上の内部一時テーブルのストレージエンジンは、 internal_tmp_disk_storage_engine 設定に応じて、InnoDB(デフォルト)またはMyISAMのいずれかになります。

MySQL 5.7のInnoDBの一時テーブルでは、エンジンは単一の一時テーブルスペースを使用します。これはibtmp1と呼ばれる、サイズが自動拡張する共有一時テーブルスペースです。詳細については、 The Temporary Tablespaceを参照してください。

一時テーブルスペースのサイズを確認するには、以下のクエリを使用してInformation_Schema.Filesテーブルに問い合わせることができます:

SELECT FILE_NAME, 
    TABLESPACE_NAME, 
    ENGINE, 
    INITIAL_SIZE, 
    TOTAL_EXTENTS*EXTENT_SIZE AS TotalSizeBytes, 
    DATA_FREE, 
    MAXIMUM_SIZE 
FROM INFORMATION_SCHEMA.FILES
WHERE TABLESPACE_NAME = 'innodb_temporary'

デフォルトでは、一時テーブルスペースのデータファイルは自動拡張され、ディスク上の一時テーブルに対応するために必要に応じてサイズが増加します。

一時テーブルスペースが占有するディスク容量を回収するには、Auroraクラスターのライターインスタンスを再起動します。ライターインスタンスを再起動すると、一時テーブルスペースのデータファイルが削除され、再作成されます。

Aurora バージョン2では、デフォルトで、InnoDB形式のディスク上の内部一時テーブル(一時テーブルスペース内)はAuroraクラスターボリュームに配置されます。InnoDB以外の一時テーブルは、Amazon Aurora MySQLインスタンスによって提供されるローカルストレージに配置されます。

Aurora バージョン3(MySQL 8.0互換)

Aurora バージョン3では、内部一時テーブルはメモリ内に保持され、TempTableストレージエンジン(デフォルト)またはMEMORYエンジンによって処理されます。TempTableストレージエンジンの制限とストレージ割り当ての動作は、tmp_table_sizetemptable_max_ramtemptable_use_mmaptemptable_max_mmapなどの設定パラメータによって制御されます。これらのパラメータによって規定される大きさにメモリ内で作成された内部一時テーブルが達すると、MySQLはそのテーブルをディスク上の一時テーブルに変換します。Aurora MySQL 3.x以前のバージョンでは、ディスク上の内部一時テーブルに使用するストレージエンジンをInnoDBまたはMyISAMとして定義できました。Aurora MySQL バージョン3.x以降では、ディスク上の内部一時テーブルにはInnoDBストレージエンジンのみを使用します。

MySQL 8.0、そしてAurora MySQL バージョン3では、InnoDBは2種類の一時テーブルスペースを使用します:

  • セッション一時テーブルスペース – これらのテーブルスペースは、ユーザーが作成した一時テーブルと、InnoDBがディスク上の内部一時テーブル用のストレージエンジンとして構成されている場合のディスク上の内部一時テーブルを保存します。セッション一時テーブルスペースは、一時テーブルスペースのプールからセッションに割り当てられます。セッションが切断されると、そのセッションの一時テーブルスペースは切り捨てられ、プールに返却されます。以前のリリースでは、一時テーブルはグローバル一時テーブルスペース(ibtmp1)に作成され、一時テーブルが切り捨てられたり削除されたりしても、オペレーティングシステムにディスク容量が返却されませんでした。
  • グローバル一時テーブルスペース – グローバル一時テーブルスペース(ibtmp1)は現在、ユーザーが作成した一時テーブルへの変更に対するロールバックセグメントを保存します。この一時テーブルスペースのデータファイルは自動拡張され、必要に応じてサイズが増加します。このグローバル一時テーブルスペースのサイズを確認するには、上記(Aurora バージョン2の場合)と同じクエリを使用できます。

グローバル一時テーブルスペースのデータファイルが占有するディスク容量を回収するには、Auroraクラスターのライターインスタンスを再起動する必要があります。ライターインスタンスを再起動すると、グローバル一時テーブルスペースのデータファイルが削除され、再作成されます。

Aurora バージョン3では、デフォルトで、InnoDB形式のディスク上の内部一時テーブルと一時テーブルスペースファイルはAuroraクラスターボリュームに配置され、InnoDB以外の一時テーブルとファイルはAmazon Aurora MySQLインスタンスによって提供されるローカルストレージに配置されます。

バイナリログ

バイナリログ(または binlog)には、テーブルの作成操作やテーブルデータの変更などのデータベースの変更を記述するイベントが含まれています。

Aurora MySQLでは、バイナリログは以下の用途に役立ちます:

  • Aurora MySQLから他のMySQL互換データベースへのレプリケーション
  • AWS Database Migration Service(AWS DMS)などのチェンジ・データ・キャプチャ(CDC)ツールを使用して、Aurora MySQLから非MySQLデータベースへのレプリケーション
  • Auroraとダウンストリームのメッセージ/イベントベースシステムとの統合を確立するなど、様々な目的でAurora MySQLからCDCレコードを抽出

Amazon Aurora MySQLでは、デフォルトでバイナリログは無効になっています(log_bin = OFF)。クラスターレベルのパラメータグループでbinlog_formatをMixed、Statement、またはRowに設定することで、バイナリログを有効にできます。

クラスターでバイナリログが有効になっている場合、クラスターボリュームで消費される容量は以下のような要因に依存します:

  • 設定されたバイナリログの保持期間
  • テーブルの作成操作やテーブルデータの変更などによって生成される変更の量
  • 場合によっては、接続されたバイナリログレプリカに問題が発生すると、クラスターボリュームでバイナリログの容量が増加することがあります。例えば、バイナリログベースのクロスリージョンリードレプリカを使用している場合に、何らかの理由でリードレプリカがバイナリログの適用に遅れが生じると、Auroraは通常必要とする以上のバイナリログをソース側に一時的に保存する必要が生じることがあります。

バイナリログの保持設定は、mysql.rds_show_configurationストアドプロシージャを実行することで確認できます:

CALL mysql.rds_show_configuration;

保持期間は時間単位で表されます。必要に応じて、mysql.rds_set_configurationストアドプロシージャを使用してバイナリログの保持期間を変更できます。以下の例では、バイナリログの保持期間を24時間に設定しています:

CALL mysql.rds_set_configuration('binlog retention hours', 24);

プライマリインスタンスで SHOW BINARY LOGS コマンドを実行すると、存在するバイナリログとそれぞれのサイズを確認できます:

SHOW BINARY LOGS

Amazon Aurora MySQLでは、クラスターレベルの以下のCloudWatchメトリクスを使用して、バイナリログの数とサイズを監視できます:

  • SumBinaryLogSize – バイナリログの総サイズ(バイト単位)
  • NumBinaryLogFiles – クラスターに保存されているバイナリログの数

リレーログ

MySQLのバイナリログレプリケーションでは、レプリカサーバー上のI/Oレシーバースレッドがプライマリサーバーに接続し、プライマリからバイナリログイベントを読み取り、それらをリレーログと呼ばれるローカルログにコピーします。SQLアプライヤースレッドはリレーログからイベントを読み取り、可能な限り速やかに適用します。つまり、リレーログは、レプリカに適用待ちのバイナリログのコピーです。

SQLスレッドが特定のリレーログファイルからイベントを処理すると、そのファイルは不要になるため自動的に削除されます。

特定の場合において、Auroraクラスターが実際にレプリケーションを行っていないにもかかわらず、リレーログがストレージ容量を占有していることがあります。例えば、過去にAuroraクラスターを別のMySQLサーバーのレプリカとして構成したものの、完全にリセットせずにレプリケーションを停止した場合などです。このような場合、Aurora MySQLクラスターボリュームには、ストレージ容量を占有しているリレーログが依然として存在している可能性があります。

これを確認するには、SHOW REPLICA STATUS コマンド(5.7互換バージョンではSHOW SLAVE STATUS)を実行して、実際にレプリケーションが動作していなくても、レプリケーションが設定されているかどうかを確認できます。このコマンドが空の出力を返す場合、レプリケーションが設定されていないことを意味し、したがってクラスターにリレーログは存在しないはずです。

以下の例のように、レプリケーション設定と他のレプリケーションステータスカウンターを示す出力が表示される場合、レプリケーションは停止されているものの、レプリケーションのメタデータが残っており、Auroraクラスターボリュームの容量を消費しているリレーログがまだ存在している可能性があります。

*************************** 1. row ***************************

Slave_IO_State:
Master_Host: 10.136.6.91
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysqld@sam_prd2-bin.000712
Read_Master_Log_Pos: 418325560
Relay_Log_File: relaylog.066015
Relay_Log_Pos: 4
Relay_Master_Log_File: mysqld@sam_prd2-bin.000712
Slave_IO_Running: No
Slave_SQL_Running: No
....
**********************************************************

残念ながら、MySQLはリレーログファイルに関する詳細なメタデータを提供していないため、クラスター内に保存されているリレーログの正確な数やサイズを確認することはできません。

レプリケーションのメタデータをクリアし、リレーログファイルを削除するには、Auroraクラスターのライターインスタンスで以下のストアドプロシージャを呼び出すことができます:

Aurora クローン

Auroraクローンは、Auroraクラスターボリュームのデータをクローンする、迅速でコスト効率の良い方法です。

Auroraは、クラスターのクローンを作成するためにコピーオンライトプロトコルを使用します。クローンが作成されると、Auroraは新しいスタンドアロンのクラスターストレージボリュームを作成しますが、元のデータページをすべて新しいボリュームにコピーすることはありません。代わりに、ページが変更されていない限り、クローンされたページは単に元のページへのポインタとなります。どちらかの側でページが変更されると、Auroraはそのページのコピーをクローン上に作成します。これが「コピーオンライト」という用語の由来です。このため、クローンの作成は迅速で、スナップショットの復元、ポイントインタイムリストア(PITR)、論理的なダンプと復元などの他の手法を使用してデータを物理的にコピーするよりも、容量効率が高くなります。また、クローンのチェーン(クローンのクローン)を作成したり、異なるAWSアカウント間でクラスターをクローンしたりすることも可能です。

クローンはボリュームの作成に少量の追加容量を使用します。この小さなオーバーヘッド以外の追加ストレージは、ソースまたはクローンされたクラスターに変更が加えられた場合にのみ割り当てられます。クローンは、データレプリケーションとパフォーマンスの面で、元のクラスターおよび他のクローンから独立しています。Auroraはこれらのエンティティ間で自動的にデータをレプリケートすることはなく、クローン(または元のクラスター)上のワークロードは互いに影響を与えません。

クローンされたクラスターストレージボリュームは、当初そのページの大部分をソースボリュームと共有しているため、それらのページはソースボリュームのVolumeBytesUsedメトリクスにのみ含まれます。クローンされたクラスターでは、VolumeBytesUsedメトリクスは最初はほぼゼロです。メトリクスについては、このポストの後半で説明します。クローンボリュームのVolumeBytesUsedメトリクスには、クローン作成後のデータ変更によって割り当てられた追加ストレージのみが含まれます。

ソースクラスターが削除された場合、まだ共有されていたページは残りのアクティブな(稼働中の)クローンに課金されます。つまり、クローンされたクラスターに実質的な書き込みがなくても、VolumeBytesUsedが大幅に増加する可能性があります。

そのチェーン内でさらにクローンが削除または作成されると、残りのクローンへのページの再分配が発生します。詳細については、How Aurora cloning worksを参照してください。

したがって、クラスターのVolumeBytesUsedと実際のテーブルスペースサイズの間に大きな差異が見られる場合は、そのクラスターがクローンチェーンの一部であるかどうかを確認する価値があります。

CloudWatch メトリクス

以下は、ローカルストレージとクラスターボリュームの使用状況を観察するための有用なCloudWatchメトリクスです:

  • FreeLocalStorage – このメトリクスでは、各Auroraインスタンスに関連付けられたローカルストレージ量を監視できます。ローカルストレージの容量はインスタンスクラスに紐付いているため、より多くのローカルストレージが必要な場合は、より大きなインスタンスを使用する必要があります。
  • VolumeBytesUsed – このメトリクスは、Aurora DBクラスターで使用される課金対象のストレージ量を示します。前述の通り、クラスターボリュームの使用量にはInnoDBテーブルスペース、バイナリログ、リレーログが含まれます。これは課金用のメトリクスであり、コピーオンライトクローンを使用している場合など、クラスター内に実際に存在するデータ量を必ずしも反映していない場合があることに注意してください。
  • AuroraVolumeBytesLeftTotal – このメトリクスは、128TiB(Aurora MySQL 3.10以降では256TiB)の最大容量のうち、クラスターボリュームの残りの使用可能な容量を示します。クラスターボリュームが成長するにつれて、この値は減少します。ゼロに達すると、クラスターは容量不足エラーを報告します。このメトリクスには、内部のハウスキーピングやその他のストレージ課金に影響しない割り当ても含まれることに注意してください。その結果、このメトリクスの値は「128 TiB から VolumeBytesUsed を引いた値」と正確には一致しません。

これらのメトリクスの詳細については、Amazon CloudWatch metrics for Amazon Auroraを参照してください。

まとめ

この記事では、Aurora MySQLクラスターボリュームの容量使用の一般的な理由と、容量使用の根本原因を突き止め、Auroraのストレージ課金コストを理解するために使用できるクエリと設定について説明しました。

AWS Aurora MySQLの詳細については、 Working with Amazon Aurora MySQLを参照してください。また、Auroraストレージボリュームについての詳細は、 Introducing the Aurora Storage Engineを参照してください。