Amazon Web Services ブログ
Amazon Aurora Under the Hood: Fast DDL
Anurag Gupta 氏は、氏自身が設計に協力した Amazon Aurora を含めて、いくつかの AWS データベースサービスを運営しています。この「詳細」シリーズでは、Aurora の設計考慮事項や基盤となるテクノロジーについて説明しています。
Amazon Aurora は、MySQL と互換性のあるデータベースであり、ハイエンドな商用データベースのスピードと可用性、オープンソースデータベースのシンプルさとコスト効率性を兼ね備えています。ここでは、MySQL で処理に数時間もかかるような一般的な DDL (データ定義言語) ステートメントが、Amazon Aurora の機能でほぼ即座に処理される仕組みについて説明します。この機能は、現在 Aurora version 1.12 以降のラボモードで使用できます。
高速 DDL とは? 注目する理由は?
アプリケーションが変わると、それに伴って基盤となるデータベーススキーマの変更が必要になります。クエリのワークロードが変わると、インデックスの追加や削除が必要になります。データの形式が変わると、既存の列のデータ型を変更する必要があります。このような変更は頻繁に起こります。Ruby on Rails アプリケーションをサポートするデータベース管理者 (DBA) の中には、週に数十回もスキーマを変更する人がいます。
MySQL の DBA には周知のことですが、このようなスキーマの変更に伴って本番稼働用システムが中断する場合があります。スキーマの変更は時間がかかります。完了まで数時間から数日かかることがあり、システムのリソースが奪われ、実際のアプリケーションのスループットが低下します。実行時間が長いオペレーションはクラッシュ回復が長引く場合があります。DDL オペレーションの一部では書き込みロックが必要なため、アプリケーションの一部が使用できなくなります。大量の一時ディスク容量が必要であり、小規模のインスタンスでは容量不足になる可能性があります。
以上のような諸問題に対処するために、まず、最も一般的な DDL オペレーションである「null が許容される列を表の末尾に追加する」例を取り上げます。
現在のアプローチが不便である理由は?
null が許容される列を表の末尾に追加するオペレーションを MySQL で実装する方法を確認しましょう。
MySQL での処理の流れは以下のとおりです。
データベースは、トランザクションの準備フェーズで、元のテーブルを排他的にロックします。
必要なスキーマで新しい空のテーブルを作成します。
一度に 1 行ずつコピーし、同時にインデックスを更新します。同時実行の DML (データ操作言語) ステートメントは、一時ファイルに記録されます。
再度、排他的なロックを行い、一時ファイルの DML オペレーションを新しく作成したテーブルに適用します。適用するオペレーションが多いと、処理に時間がかかります。
次に、オリジナルテーブルを削除し、新しいテーブルの名前をオリジナルテーブルと同じ名前に変更します。
以上の処理には、多くのロック、データのコピーやインデックスの作成に伴う多くのオーバーヘッド、多くの I/O、さらにアクティブなテーブルの場合は大量の一時容量が必要になります。
もっと良い方法はないのか?
対策はない、と思われるかもしれません。結局、各行のデータ形式は変更することになるのですから。しかし、この変更をテーブルで実行される他の DML (および関連する I/O) オペレーションに重ねることで、多くのことができます。ここでは複雑すぎて詳しく紹介できませんが、以下に概略を示します。
Aurora では、ユーザーが DDL ステートメントを発行すると、以下の処理が行われます。
データベースが INFORMATION_SCHEMA のシステムテーブルを新しいスキーマで更新します。さらに、オペレーションにタイムスタンプを付けて、古いスキーマを新しいシステムテーブル (Schema Version Table) に記録し、この変更をリードレプリカに伝達します。
オペレーションの同期部分は、これだけで完了です。
次に、以降の DML オペレーションで、該当するデータページに保留中のスキーマオペレーションがあるかどうかを確認します。これは、ページのログシーケンス番号 (LSN) タイムスタンプとスキーマ変更の LSN タイムスタンプを比べれば、簡単に確認できます。必要に応じて、DML ステートメントを適用する前に、ページを新しいスキーマに更新します。このオペレーションのプロセスは、やり直す/元に戻すレコードページのアップグレードプロセスと同じです。この場合も、すべての I/O はユーザーのアクティビティに重ねて実行されます
DML オペレーションでは、アップグレードでページが分割される場合があるため、注意してページのみをアップグレードする必要があります。Aurora レプリカでもアップグレードに対応する必要があります。この場合、データの変更は許可されません。SELECT ステートメントで、MySQL に戻すバッファのメモリイメージを変更します。これにより、基盤となるストレージに新旧のスキーマ形式が混在していたとしても、常に最新のスキーマが表示されます。
Aurora でストレージからの読み取りに対して REDO ログを適用する方法に詳しい方は、アプローチが似ていると感じることでしょう。しかし、このアプローチでは、REDO ログのセグメントではなく、実行する変更を記録するためにテーブルを使用します。
パフォーマンス比較は以下のとおりです。Aurora の場合、Schema Version Table の更新所要時間は変動が少ないことを確認できます。一方、MySQL ではテーブルのサイズにほぼ比例して線形に時間が増加しています。
確かに他にも改善すべき DDL オペレーションは多いのですが、ほとんどは同じ方法で対処できます。重要な点は、データベースが通常の定義の可用性で稼働していても、時間がかかるオペレーションではアプリケーションが適切に稼働しなくなるということです。これらのオペレーションは、並列実行、バックグラウンド実行、および非同期実行に移行することで改善できます。
フォローアップの質問またはフィードバックがあれば、aurora-pm@amazon.com に連絡するか、こちらにコメントを残してください。皆さんからのご意見やご感想をお待ちしています。