Amazon Aurora Limitless Database 内部アーキテクチャ詳解 〜スケーラビリティと可用性の秘密〜

Amazon Aurora Limitless Database 内部アーキテクチャ詳解 〜スケーラビリティと可用性の秘密〜

本記事では、Amazon Aurora Limitless Database の内部アーキテクチャについて解説します。特に、スケーラビリティと可用性を実現するための仕組みについて詳しく見ていきます。

Aurora Limitless Database を理解する上で、前提知識として、従来のデータベース運用における課題と、AWS が提供するマネージドデータベースサービスの利点を押さえておくと理解が深まります。

従来のデータベース運用では、以下のような課題がありました。

  • データベースの運用管理には、モニタリング、クエリチューニング、スキーマ設計、アップデート、バックアップとリストア、セキュリティ対策など、様々なタスクが必要となる。
  • データベースの規模が大きくなると、これらのタスクは複雑化し、専門的な知識と経験を持つデータベースエンジニアや管理者が不可欠となる。
  • ハードウェアの制約により、データベースのスケールアップやスケールダウンにはダウンタイムが発生し、サービスの可用性に影響を与える可能性がある。

これらの課題を解決するために、AWS ではマネージドデータベースサービスを提供しています。マネージドデータベースサービスでは、AWS がデータベースの運用管理タスクを代行するため、ユーザーはデータベースの設計、開発、アプリケーションの構築といったコア業務に集中することができます。

Amazon Aurora も、このようなマネージドデータベースサービスの一つであり、高いパフォーマンス、スケーラビリティ、可用性、セキュリティ、そして運用管理の容易さを兼ね備えています。

なぜマネージドデータベースなのか?

データベース運用には、様々なタスクが存在します。特に、データベースの専門家が少ない環境や、システムやデータベースの数が多く管理対象が多い場合には、負担が大きくなってしまいます。

自社の責任範囲AWSの責任範囲
クエリ作成High availability
クエリ最適化コンフォーマンス
スキーマ設計セキュリティ
アプリケーションとの連携モニタリング
パッチ適用
バックアップ & リカバリー
パフォーマンスとスケーラビリティ可用性と耐久性
セキュリティ
オペレーショナル・アナリティクス生成AI
規模に応じた管理能力
移行の容易性

マネージドデータベースは、これらのタスクの大部分を AWS 側に移譲することで、ユーザーは本来の業務に集中できるというコンセプトで開発されています。

Aurora のコアバリュー

Amazon Aurora は、以下の7つのコアバリューを基に開発が進められています。

  • パフォーマンスとスケーラビリティ
  • 可用性と耐久性
  • セキュリティ
  • 大規模な管理性
  • 運用分析
  • 生成系 AI
  • 移行の容易さ

特に、マネージャビリティという観点で運用管理の容易性を追求し、様々な機能のリリース、改善に取り組んでいます。近年では、生成系 AI の潮流も取り入れ、AI とのシームレスなインテグレーションも強化されています。また、既存環境から Aurora クラスターへの移行を容易にする仕組みや機能も提供されています。

マネージャビリティ向上のための機能

Amazon Aurora は、マネージャビリティという観点で、様々な機能をリリースしています。データベースサービスではパフォーマンスやデータ容量に注目が集まりがちですが、RDS や Aurora は管理運用性の向上にも注力しています。

例えば、以下のような機能が挙げられます。

  • セキュリティ上の問題を自動的に検知する仕組み
  • パフォーマンスの問題や異常を検知する機能
  • サーバーレスデータベースを実現するための技術
  • データベースの高速なスケールアップ、スケールダウンを実現する仕組み

グローバーストレージ

Amazon Aurora は、独自開発のストレージである「グローバー」を採用しています。「The log is the Database」という設計思想に基づき、データベースサーバーから送られてくる更新のログをすべて集め、データベースページとして再生成する仕組みです。これにより、従来のデータベースサーバーと比較して80%の Disk I/O の削減を実現しています。

グローバーストレージは、3つの Availability Zone (データセンターのクラスター) に2つずつ、計6つのデータのコピーを置くことで、1つの Availability Zone が消失した場合でも動作し続ける可用性の高い設計となっています。

また、グローバーストレージは単なるストレージではなく、コンピューティングの役割も担っています。そのため、Amazon Aurora とは、クエリを処理するエンジンだけでなく、グローバーとクエリを処理するノードを合わせて Aurora というサービスとして提供しています。

カスピアン

コンピューティングの面では、データベースをクラウド上でシームレスに動作させるために「カスピアン」と呼ばれる仕組みを開発しました。これは、Aurora Serverless v2 の裏側で動作している仕組みであり、ハイパーバイザーとヒートマネジメントを行うコントロールプレーンの総称です。

カスピアンの主な機能は以下の通りです。

  • オーバーサブスクリプションで、物理ハードウェアの上にインスタンスを起動し、実際にメモリや vCPU、ネットワーク帯域が必要になった時にダウンタイムを与えずに自動的にリソースを増やす、もしくは負荷が下がったらリソースを減らすという動作をオンデマンドで行う。
  • 処理時間はミリ秒単位で増減を行い、リソースを増減している時のデータベースのワークロードへの影響は発生しない。
  • キャパシティがスケールアップしていく時に、物理状態、その稼働している物理状態のキャパシティを超えるといった時はライブマイグレーションが実施される。

ライブマイグレーションは、ダウンタイムやワークロードへの影響なく、どのインスタンスを移動させれば物理ハードウェアに空きが出るのか、どうすれば早くライブマイグレーションが完了してスペックアップができるのかを判断してコントロールプレーンが指示を出します。そのため、スケールアップのリクエストを出しているインスタンスをライブマイグレーションするという単純なロジックではなく、どれを移動させればすぐにスケールアップできるのかを考慮しています。

ライブマイグレーションの前後でバッファプールやコネクションのステートはすべてコピーされるため、アプリケーションは意識する必要がありません。

このキャパシティのコントロールは、リージョン単位で行われています。東京リージョンやノースバージニアといった単位でキャパシティのコントロールを行っており、この横軸がカスピアンインスタンスが稼働している物理ハードウェアで、青い点1個1個がカスピアンインスタンスを表しています。それぞれスケールアップ、スケールダウンの要求が来た時にリージョン全体として各ハードウェアのキャパシティが一定に保たれるように、稼働率が一定に保たれるようにライブマイグレーションを実施しています。

このように、マイグレーションを行うことでスケールアップのスロットリングがかからないよう、かつマイグレーションを高速に行えるように、常にインスタンスのキャパシティ管理を行っています。

Amazon Aurora Limitless Database

これらのグローバーやカスピアンといった技術を用いて現在開発を進めているのが、新しい Aurora のシリーズである「Amazon Aurora Limitless Database」です。現在 Limited Preview 中で提供されています。

マネージドシャーディング

Aurora Limitless Database の開発を始めたきっかけは、Amazon Aurora でスケーラビリティは提供されているものの、やはり事業が続く中でデータサイズが増えていった場合や、アプリケーションの機能追加やイベント時にクエリがスパイクした場合などに、従来の1台のライターでは足りなくなるという状況が発生する可能性があることにあります。

このような時に、通常であればシャーディングと呼ばれる方法で、物理的に Aurora のクラスターを分割し、アプリケーション側でデータのアクセス先を振り分けます。しかし、シャーディングにはいくつかの問題点があります。

  • 物理的に異なる Aurora のクラスターが存在するということは、どのデータがどのシャードに入っているのかをアプリケーションが判断する必要がある。
  • 複数のシャードに渡って結合 (JOIN) しなければならない、トランザクションを実行しなければならないといった時に、整合性をどうとるのか。
  • バックアップやリストアを全シャードで同じポイントで取って同じポイントに戻さなければならない時に、どう整合性を保つのか。
  • 複数のクラスターが立つということは、それぞれでメンテナンスが必要になる。

これらの問題点を解決するために、手作業でスクリプトを組んだり管理ツールを作成するケースも多いですが、それらのフィードバックをもとに、マネージドでシャーディングを実施するマネージドシャーディング機能を提供する、というコンセプトで開発されたのが Amazon Aurora Limitless Database です。

現在 PostgreSQL 互換のエンジンを提供しています。

このコンセプトは、1つのエンドポイントに対してクエリを投げるだけで、裏側で透過的にシャードの分割などを行い、アプリケーション側にカスタムロジックなどを組む必要がなくなり、メンテナンスも Aurora のプラットフォーム上で稼働するためマネージドで提供されます。そして何よりもパフォーマンス面では、この1つのエンドポイントだけで数100万トランザクション、そしてストレージに関してはペタバイトクラスのストレージを提供します。また、分散トランザクションや分散クエリといった複数のシャードにまたがったクエリもサポートします。

リミットレスデータベースのテーブル構造

Limitless Database 内では、以下の3種類のテーブルが作成可能です。

  • シャードテーブル
  • リファレンステーブル
  • スタンダードテーブル

シャードテーブル

シャーディングが行われるテーブルです。設定いただいたシャーディングキーを元に各シャードにデータが自動的に分散されます。
例えば、customer_id をキーとしたシャーディングの場合、customer_id が同じユーザーは、どのテーブルでも同じシャードに格納されます。これをコロケーションと呼びます。

リファレンステーブル

更新量が少なく、テーブルのデータサイズが小さいものや、シャーディングキーの設定が難しいテーブルは、リファレンステーブルとして設定します。リファレンステーブルは、すべてのシャードに同じデータがコピーされます。

スタンダードテーブル

Limitless Database ではなく、通常の Aurora クラスターの中に作成される通常のテーブルです。

リミットレスデータベースの仕組み

Limitless Database では、これらのテーブルをどのように作成していくかというと、まずセッション変数を定義します。

SET aurora_limitless.table_mode = 'shard';

上記のように、aurora_limitless.create_table_mode を用いて、今回はシャードテーブルを作成するため shard と指定します。

次に、どのカラムをシャーディングキーにするのかを指定してあげます。

CREATE TABLE users (
 user_id INT PRIMARY KEY,
 username VARCHAR(255),
 email VARCHAR(255)
) PARTITION BY HASH(user_id);

今回は user_id をキーにシャーディングを行います。 複合キー、複数のカラムをシャーディングキーに設定することも可能です。

そして最後に、CREATE TABLE を実行します。この CREATE TABLE は PostgreSQL のものと全く同じ構文が使え、Limitless Database 用に構文の拡張は行われていません。そのため、特定のテーブルを Limitless Database として使いたい場合は、この2つのセッション変数を指定してあげるだけで、高速なテーブルが作成されます。

アプリケーション側にカスタムロジックなどを組む必要がなくなり、メンテナンスも、この後ご説明しますが、Aurora のプラットフォーム上で稼働するためマネージドで提供されます。

内部アーキテクチャ

Limitless Database はサーバーレスアーキテクチャを採用しており、ユーザー側でインスタンスをプロビジョニングする必要はありません。最大キャパシティだけを設定すれば、その範囲内で自動的にシャードのスプリットやスケールアップ/ダウンが行われます。分散クエリや分散トランザクションといった複数のシャードにまたがった処理にも対応しています。

Limitless Database の内部アーキテクチャは、以下の2つのレイヤーで構成されています。

  • 分散トランザクションを司るルーターのレイヤー
  • データアクセスシャーディングのコンピューターレイヤー

まず、分散トランザクションルーターは、単なるプロキシではなく、ユーザーに対して前述のエンドポイントを提供する役割と、どのシャードにどのデータが入っているかというメタデータを管理する役割を担います。
Limitless Database は時間ベースのトランザクションマネジメントを実行しており、そのための時刻の払い出しも行っています。

クエリの実行計画の解析もここでまず最初に行われ、マルチシャードクエリ、マルチシャードトランザクションになる場合は、トランザクションやクエリのコーディネーションをしたり、各シャードから返ってくるデータをアグリゲーションしたり DISTINCT として最終的にアプリケーションに返すといった処理を行います。

ユーザーから見ると、通常の Aurora のクラスターの下に Limitless Database のエンドポイントが追加され、クラスターエンドポイント、リーダーエンドポイント、カスタムエンドポイント、インスタンスエンドポイントに続く5つ目のエンドポイントとして、Limitless Database のシャードグループのエンドポイントが提供されます。アプリケーションからはこのエンドポイントに接続するだけで Limitless Database が使え、Aurora がサポートする機能の恩恵も受けられる仕組みです。

次に、データアクセスシャーディングのコンピューターレイヤーについて説明します。

このレイヤーはユーザーからは完全に隠蔽されており、直接見たりアクセスしたりすることはできません。ここもメタデータだけを保持しており、データ本体はグローバーストレージに格納されています。これは後で詳しくご紹介します。データにアクセスするためのシャードということで、データアクセスシャードと名前を呼んでいます。

さらに、このテーブルフラグメントは、サブレインジと呼ばれる単位に分割されます。このサブレインジに関してはユーザーから確認することができず、完全に内部的に分散処理を行うものになっています。これによって、シャード内での並列性の向上や、シャードスプリットが起こった時の高速なスプリット処理が可能になります。

整合性の実現方法

コミット処理

Limitless Database では、ハッシュパーティショニングを採用しています。与えられたシャーディングキーの値をハッシュ関数にかけ、さらにハッシュのレンジに分割することで、単調増加する ID が発行されても特定のシャードに偏りにくい設計になっています。

データ本体をテーブルフラグメント、そしてメタデータをテーブルフラグメントリファレンスと呼び、実際にシャーディングされるのはテーブルフラグメントです。

ルーターのレイヤーも、データアクセスシャードのレイヤーも、データの実体は持っていません。データ本体はグローバーストレージにあり、その理由はこの後ご紹介します。

では、データアクセスシャードはなぜ「シャード」と呼ばずに、わざわざ「データアクセスシャード」と呼ぶのでしょうか。
それは、このレイヤーではメタデータだけを保持しており、実際のデータはグローバーにあるためです。データにアクセスするためのシャードであるという点を強調して、データアクセスシャードと命名しています。

シャードスプリット

シャードスプリット、つまり水平スケールはどのように行われるのでしょうか。基本的にはユーザー側で手動でスプリットすることもできますし、AWS のコントロールプレーンに任せることも可能です。

コロケーション設定されたテーブルに関しては、ちゃんと同じデータは同じシャードに分割されていきます。

テーブルスライスに関しては、ユーザー側で一切考慮する必要はなく、完全に内部的に分散処理を行うものになっています。これによって、シャード内での並列性の向上や、シャードスプリットが起こった時の高速なスプリット処理が可能になります。

トランザクション

Read Committed アイソレーションレベル

Limitless Database は、Read Committed と Repeatable Read のトランザクションレベルに対応しています。
Read Committed アイソレーションレベルの場合、まずトランザクション1が SELECT 文を発行します。ルーターは T100 (便宜上 T100 という時間情報) を付与して各シャードにばら撒きます。必要なシャードは時刻情報 T100 の時点のリードビューを参照してクエリを返します。

次に別のトランザクションが実行され、今回は2つの UPDATE 文で、口座の中で金銭を動かすようなトランザクションを実行します。今回、シャード 619 を格納しているシャードが T118 の時点でプリペアが完了し、次に T112 の時点で 801 のシャードがプリペアが完了したという情報がルーターに返され、ルーターが T120 でコミットを打って良いという指示を出します。各シャードは T120 以上の時間に自分が含まれているか、かつグローバーにデータが完全に Durability な状態になっていると判断してコミットを実行します。

別のトランザクションは T116 という時間でクエリを発行していますが、T116 は T120 よりも前なので、このコミットされたデータは見せてはいけません。そのため、T116 の時点のリードビューを返します。

このように、マイクロ秒単位で処理が行われているため、多少時間がずれても数マイクロ秒のウェイトタイムで済みます。

Repeatable Read アイソレーションレベル

Repeatable Read の場合も同様ですが、こちらは T100 の時刻情報がキープされています。そのため、SELECT 文を発行しても、T100 時点のリードビューを返します。

データベースの分散における課題と解決策

ここまで、内部の仕組みとどういったコンセプトで作ってきたのかをご紹介しました。
Limitless Database はまだ Limited Preview 中ではありますが、基本的にはライトスケーラビリティ、ストレージの性能やサイズが欲しい、もしくは MySQL や PostgreSQL のインターフェースが欲しい、リレーショナルデータベースが持つ複雑なトランザクション制御を使わないとダメ、そのトランザクション制御をデータベースのレイヤーに責務として持たせたい、もしくは JOIN で複数のテーブルをまとめなきゃいけない、各エンジンの組み込み関数やエクステンションを使いたい、という場合には Limitless Database が1つの選択肢になるかと思います。

今回限られた時間の中でお話しできなかったところ、Bounded Clock のトランザクション、ちょっと分かりにくかったというところがあればぜひお越しいただければ詳細解説したいと思います。

まとめ

Amazon Aurora Limitless Database は、従来の Aurora の機能を継承しつつ、シャーディングを AWS によってマネージドで提供することで、スケーラビリティと可用性をさらに向上させたデータベースサービスです。

  • ライトスケーラビリティを提供し、ペタバイトクラスのストレージまで拡張可能。
  • 1つのエンドポイントでアクセスでき、アプリケーション側でシャーディングを意識する必要がない。
  • 分散トランザクション、分散クエリをサポート。
  • 通常の PostgreSQL と互換性があり、ドライバーやツールをそのまま使用できる。

Aurora Limitless Database は、大規模なデータと高トラフィックを扱うアプリケーションに最適なデータベースサービスです。

AWSモダナイズ・スモールスタート開発支援基幹業務システムのUI.UX刷新はお気軽にお問い合わせください。