📖

re:Invent 2024: AWSが新データベースAurora DSQLを発表

2024/01/01に公開

はじめに

海外の様々な講演を日本語記事に書き起こすことで、隠れた良質な情報をもっと身近なものに。そんなコンセプトで進める本企画で今回取り上げるプレゼンテーションはこちら!

📖 AWS re:Invent 2024 - Get started with Amazon Aurora DSQL (DAT424)

この動画では、AWSの新しいデータベース製品であるAurora DSQLについて、その特徴と設計思想が詳しく解説されています。DSQLはトランザクショナルワークロード向けに最適化され、PostgreSQLと互換性を持つServerlessデータベースで、Active-activeのマルチリージョン構成を実現します。Strong Snapshot Isolationという分離レベルを採用し、リージョン間でも強い一貫性を保ちながら、読み取り操作はローカルリージョンで高速に処理できる特徴があります。スケーラビリティを確保するためにはHot write keysを避けることが重要で、トランザクションを活用することでレイテンシーとスループットを向上できます。シンプルなアーキテクチャでありながら、高い可用性と耐久性を実現できる点が強調されています。
https://www.youtube.com/watch?v=9wx5qNUJdCE
※ 動画から自動生成した記事になります。誤字脱字や誤った内容が記載される可能性がありますので、正確な情報は動画本編をご覧ください。
※ 画像をクリックすると、動画中の該当シーンに遷移します。

re:Invent 2024関連の書き起こし記事については、こちらのSpreadsheet に情報をまとめています。合わせてご確認ください!

本編

Amazon Aurora DSQLの紹介:背景と開発経緯

Thumbnail 0

タイトルスライドが表示されていますね。とても明るいスライドです。本日はご参加いただき、ありがとうございます。このトークのタイトルは数時間前に変更されたばかりで、私自身とチームにとってもワクワクする出来事でした。カタログの中からこのセッションを見つけ、Amazon Aurora DSQLについて私と一緒に話し合うためにお集まりいただき、嬉しく思います。声が1時間持つことを願っています。そして、なぜこの講演を普通の湿度の都市で開催できないのかと思います。皆さんもそうだと思いますが、私は喉が非常に渇いています。

Thumbnail 50

今朝、Mattが私たちの最新のデータベース製品であるAmazon Aurora DSQLを発表しました。このトークでは、Aurora DSQLを使い始めるためのアーキテクチャ、私たちが何を作り、なぜ作ったのかについてお話しします。 そして、これは400レベルのトークですので、私たちの分離レベルと一貫性モデルについても少し深く掘り下げていきます。明日、私は別のセッションでAurora DSQLの内部アーキテクチャや、私たちが行ったアーキテクチャの選択について詳しく説明する予定です。しかし、このセッションではDSQLの上に構築するアーキテクチャについて焦点を当てます。

Thumbnail 80

まず最初に、私がここに至るまでの個人的な話をさせていただきたいと思います。2020年、私はLambdaチームで働いており、Serverlessコンピューティングの分野でAWSのコンピュート事業全体を支援する、とてもクールな仕事をしていました。仕事の中で最も好きな顧客との対話を通じて、私は同じような話を何度も耳にしました。顧客はリレーショナルデータベースを使って構築したい、SQLのパワーを活用したい、既存のPostgreSQLコードを活用したいと考えていました。しかし、AWSの既存のデータベース製品はServerlessとの相性があまり良くなく、そこにはある種のミスマッチが存在していました。

私はAWSのデータベース部門に異動し、データベースとデータストレージについて以前の考え方に少し立ち返ることになりました。そこで多くのデータベースの顧客と話をする中で、彼らが本当に望んでいたのは、AWSの豊富なデータベースポートフォリオにまだなかったMulti-RegionのActive-Activeデータベースだということがわかりました。私たちは素晴らしいチームを見つけ、talented な人材を集めてこの製品を構築しました。この4年間、彼らと一緒に仕事ができたことを光栄に思います。最初のPR FAQを書いたのは2021年1月で、ここまで長い道のりでした。今日、皆さんとこれを共有し、DSQLの上に何を構築されるのかを見られることをとても楽しみにしています。

Aurora DSQLの特徴と設計思想

Thumbnail 190

では、Aurora DSQLとは何でしょうか?基本的に、これはトランザクショナルワークロード向けに最適化されたリレーショナルSQLデータベースです。トランザクショナルワークロードとは、サービスアーキテクチャ、Microserviceアーキテクチャ、モバイルバックエンドなどを実行するような種類のものを指します。これは分析やデータウェアハウジング向けに最適化されたデータベースではありません。そのような用途には、AWSポートフォリオの中に他の優れたオプションがあります。これはトランザクショナルワークロード向けに最適化されており、小規模な読み書き、一般的に1トランザクションあたり5-10程度のステートメント、比較的シンプルなSQL、数個のJoinといった処理を想定しています。

Thumbnail 240

Aurora DSQLはスケールアップとスケールダウンの両方に対応しています。AWSでスケーラビリティについて語る時、私たちはよくスケールアップについて話します。これは、数千、数百万のトランザクションを毎秒処理する巨大なアプリケーションに最適です。しかし、実際にはこの会場にいる皆さんの中で、そのような規模のアプリケーションを持っている方は比較的少ないでしょう。もしそうでないなら、むしろラッキーだと思ってください - 想像するほど楽しいものではありませんから。Aurora DSQLに私たちが当初から組み込んだ機能の1つが、スケールダウンする能力、つまり1日数件から毎秒数百万件以上まで、あらゆる規模のアプリケーションに適したサイズのデータベースとなる能力です。

Thumbnail 280

そして、これはServerlessです。確かに、AWSではこの「Serverless」という言葉を少々乱用してきた面があることは認めます。しかし、ここで私が言いたいのは、Aurora DSQLデータベースがDynamoDBデータベースやS3バケット、あるいはLambda関数のようなものだということです。目に見えるインフラストラクチャーは一切なく、心配したり、監視したりする必要はありません。インフラストラクチャーは完全にカバーされ、内部に組み込まれています。

Thumbnail 340

そのため、監視やパッチ適用、アップデート、コンプライアンスについて心配する必要はありません。コンソールやAPI、CLIを使ってAurora DSQLデータベースのエンドポイントを作成し、アプリケーションをそのエンドポイントに接続するだけで、あとはIAMポリシーの変更や請求を最適化するためのトランザクション確認以外に、インフラストラクチャーについて気にする必要は一切ありません。

Thumbnail 380

オプションとして、Active-activeとマルチリージョンのサポートを提供します。この講演を通じて、シングルリージョンとマルチリージョンの両方のアプリケーションについて説明しますが、これは大規模で重要なアプリケーションにとって最も重要な機能の1つです。Aurora DSQLの最も重要な特徴の1つは、分離性、一貫性、アトミック性、永続性、その他の重要なACIDプロパティを損なうことなく、複数のリージョンで同時にアクティブに実行できるアーキテクチャーを可能にすることです。

また、PostgreSQLと互換性があり、PostgreSQLクライアントで接続してPostgreSQLのCLIを使用できます。PostgreSQL用に書かれたSQLコードのほとんどがDSQLで動作します。ここで、いくつかの制限について説明したいと思います。一部の制限は、本日プレビューを発表したばかりでGAに向けて作業中であることが理由です。しかし、時間とともに私たちが目指すのは、広く使用されているPostgreSQLの機能のほぼすべてをカバーすることです。これは、私がLambdaビジネスを長年運営してきた中で得た重要な教訓でした。Lambdaの立ち上げ当初から、新しいアプリケーションを構築するお客様に大変興奮していましたが、実際には多くのお客様にとって、新しいアプリケーションの構築は頻繁に行うことではありませんでした。皆さんのビジネスの crown jewelとなるコードがあり、場合によってはそれが唯一のビジネスロジックやビジネスルールのエンコーディングとなっています。そのコードを単にControl-NやCommand-Nを押して書き直すことはできません。なぜなら、そうする余裕が単にないからです。だからこそ、既存のデータベースエンジンとの互換性や既存のSQL機能との互換性が私たちにとってとても重要だったのです。

Thumbnail 460

Thumbnail 510

DSQLは私たちの経験に基づいて構築されています。2014年のre:Inventで、私たちはAuroraを発表しました。同じre:Inventで、Lambdaも発表し、それ以来ずっとAuroraを運用してきました。DynamoDBやRDSはさらに長く運用しており、大規模なServerlessサービスもクラウドの初期から運用してきました。実際、AWSはServerlessから始まりました - 最初の2つのAWSサービスであるSQSとS3は、どちらもServerlessでした。 私たちは今、Auroraイノベーションの10周年を祝っています。つまり、これは新しい取り組みではなく、重要なお客様のために10年以上にわたってAuroraを本番環境で運用してきた経験から得られた教訓に基づいて構築されているのです。

シンプルなアーキテクチャから複雑なマルチリージョン構成まで

Thumbnail 530

Thumbnail 540

アーキテクチャについて詳しく見ていき、アプリケーションの構築について説明しましょう。 ここでは、シンプルな単一リージョンのアプリケーションを構築していきます。話が進むにつれて、少し複雑になっていきます。 これが、Aurora DSQLの上に構築できる非常にシンプルなアーキテクチャです:お客様がサービスを見つけられるようにするためのDNS、TLS終端などを行うのに便利なALB、そしてデータベースと通信するアプリケーションを実行する単一のマシンです。DSQLコンソール、CloudFormation、またはCLIを使用してDSQLデータベースを作成し、アプリケーションがそのデータベースに接続します。これは非常にシンプルで、ある意味ではナイーブなアーキテクチャですが、これによって何が得られるのでしょうか?

Thumbnail 590

アプリケーションの効率性や各リクエストが消費するCPUの量に応じて、1秒あたり数百、数千、場合によっては数万のリクエストを処理することができます。

そのインスタンスにAuto Scaling Groupを設定して障害を検知し、置き換えることができれば、99.9%以上の可用性を実現できます。障害時のデータ損失もありません。このアーキテクチャには、単一のマシンの障害によってデータを失ったり、そのアプリケーションボックスが故障した場合でも数秒から数分以上の可用性を失ったりするような箇所はありません。そして、SQLの強力なセマンティクス、同時実行制御、トランザクションのおかげで、トラフィックが増加した際にこのアーキテクチャを簡単にスケールアウトできます。要するに、これは非常にシンプルでナイーブなアーキテクチャですが、素晴らしい特性を持つアーキテクチャなのです。15年前には、これほどシンプルで優れた特性を持つものを構築することは夢のまた夢でした。

Thumbnail 700

これは、私たちがAWSデータベースポートフォリオを考える上での目標でした。アーキテクチャから複雑さを取り除き、システムのビルダー、アーキテクト、設計者としての皆さんの仕事を簡素化したいと考えています。データの耐久性、低レイテンシー、高可用性を確保するといったシステム運用の難しい部分を私たちのサービスに任せることで、より少ない構成要素でよりシンプルなアーキテクチャを構築できるようにしたいのです。

Lambda関数とLambda Function URLsを使ってみてはどうでしょうか?LambdaとDSQLの組み合わせは非常に相性が良いのです。この構成では、1秒間に数千、あるいはそれ以上のリクエストを処理することができます。先日、Lambdaコンソールで実際にコードを書いて、1秒間に数万リクエストまでテストしてみました。これは恐らく、1秒間に数千リクエストを処理できる最もシンプルなアーキテクチャと言えるでしょう。インフラストラクチャの心配は一切不要で、回復力があり、スケーラブルで、監視も簡単、セキュリティの考え方も明確で、アーキテクチャの中の動く部分も最小限です。このように、AWSはLambdaやFargate、EKSといったサービスを通じて、スケーラブルなアプリケーションの開発における複雑さを引き受け、さらにDSQLで困難なトランザクショナルなリレーショナルデータベースの課題にも対応しているのです。

Thumbnail 780

Thumbnail 800

さて、これまでシンプルなアーキテクチャについて見てきましたが、先ほど申し上げたように、実際のアプリケーションはもっと複雑です。Lambda関数だけで収まるようなアプリケーションを運用している方は少ないでしょう。ビジネスもニーズも、それ以上に複雑なものです。そこで、もう少し複雑な構成を見ていきましょう。ここでは、アプリケーション(単一のボックスかもしれませんし、アプリケーションスタック全体、あるいはマイクロサービスのグラフ全体かもしれません)を3つのアベイラビリティーゾーンにそれぞれデプロイしています。その前にALBやNLBなどのロードバランサーを配置して、ヘルスチェックやロードバランシングを行い、適切な負荷を適切な場所に振り分けます。さらにその前にDNSを置いてカスタマーからの接続を受け付け、そしてリージョナルなDSQLエンドポイントがあります。

Thumbnail 840

このアーキテクチャではどのような特性が得られるでしょうか?まず、1秒間に数千、あるいはそれ以上のリクエストを処理できます。99.95%の可用性があり、1つのアベイラビリティーゾーン全体が故障したり切断されたりしても、ほとんどカスタマーへの影響なく運用を継続できます。インフラストラクチャのニーズと管理の手間は、アプリケーションスタックとその構築方法によって異なります。LambdaやFargateなどの高レベルサービスを使用した場合は非常にシンプルですが、アプリケーションのニーズによってはより洗練された構成が必要になることもあります。ここでもAWSは、可用性、スケーラビリティ、レイテンシー(これについては後ほど詳しく説明します)といった優れたエンドユーザー特性を、比較的シンプルなアーキテクチャで実現しようとしています。アベイラビリティーゾーンの障害耐性や障害検知、データベース内部のスケーラビリティといった困難な課題は、DSQLが担当してくれるので心配する必要はありません。

DSQLのスケーラビリティ:Hot write keysを避ける重要性

Thumbnail 920

では、トレードオフは何でしょうか?すべてのものがそうであるように、メリットとデメリットがあり、特にスケーラビリティについては考慮すべき点があります。アプリケーションをスケールさせるためには、いくつかのパターンについて考える必要があります。ここでは、DSQLでスケーラビリティを確保する上で最も重要なヒントを1つお伝えします:Hot write keysを避けることです。

Thumbnail 990

SQLステートメントの例を見てみましょう。これは単独でAutoコミットとして実行することも、より大きなトランザクションの一部として実行することもできます。このコードでは、プードルを見かけるたびにカウントを増やしてその数を返すという、非常にシンプルなSQLを実行しています。ここでデータベースから選択して更新しているキー、つまり行は、このプードルのタイプに基づいています。たくさんのプードルを見かける場合、ここでスケーラビリティの問題が発生する可能性があります。例えばプードルショーに行って1秒間に何千匹ものプードルを見かけるような場合、スケーラビリティの懸念が出てくるわけです。

2つの並行トランザクションが同時に実行される場合、1つ目が開始し、2つ目が開始し、SQLを実行し、ある程度の時間実行された後にコミットされると、最初のトランザクションは正常に動作してコミットされます。最初のトランザクションがそのRowを変更しようとした最初のケースで、読み取り時点からRowが変更されていないため、競合は発生しません。2つの並行トランザクションのうち2番目がコミットしようとすると、拒否されます。データベースは「他の並行トランザクションによって既に書き込まれたRowを書き込もうとしました」と通知し、Optimistic Concurrency Controlエラーでコミットが失敗します。そうなると、アプリケーションはトランザクションの開始時点に戻り、トランザクション内で実行されたビジネスロジックを再実行し、2回目のコミットが成功することを期待することになります。

Thumbnail 1070

アプリケーションをスケールする際に最も重要な考慮点は、このような競合を示すコミットに注意を払うことです。ただし、これは実際に書き込みが競合する場合にのみ当てはまります。ここでは、2つのトランザクションが同じテーブルを更新していますが、テーブルの異なるRowを更新しています。ここでTypeが異なる(一方はプードルをカウントし、もう一方はゴールデンレトリバーをカウントしている)ため、問題ありません。これらのトランザクションは両方とも正常にコミットされます。

Thumbnail 1130

ここでの教訓は、更新と書き込みを複数のKeyに分散させるようにスキーマを設計する必要があるということです。適切なKey数はアプリケーションの目標スケールによって異なります。1時間に数リクエストしか発生しないアプリケーションであれば、心配する必要はなく、すべてを1つのRowに入れても構いません。しかし、1秒間に数百万のリクエストを処理しようとする場合は、並行して更新されるRowを避けるようにスキーマを慎重に設計する必要があります。これは正確性の観点からではありません。データベースは正確性の観点から常に正しい動作を保証しますが、スケーラビリティの観点から重要なのです。

Thumbnail 1170

その解決策の1つは、更新クエリでより細かい粒度のKeyを選択することです。世界中にはたくさんのプードルがいますが、Snufflesという名前の犬はそれほど多くありません。犬の名前やUUID(私の犬にはUUIDがありますし、皆さんの犬にもUUIDを付けるべきです。便利ですよ)のようなものを使用すれば、このような問題は発生しません。これはスキーマ設計の問題ですが、書き込みに特有の問題です。テーブルから選択する場合、2つの並行トランザクションで同じRowを選択しても、DSQLではこれらのトランザクションが競合することは決してありません - 常に両方ともコミットされます。さらに重要なのは、一方が他方を遅くすることはないということです。リソースの競合も、同時実行制御の競合も発生しません。常にコミットされ、読み取るKeyの数は問題になりません。これがスケールに関するヒントの結論です - スケールアップする場合は、Hot Write Keyを避けてください。

マルチリージョンActive-activeアーキテクチャの利点

Thumbnail 1210

スケールアップを目指せば目指すほど、Hot Write Keyを避ける必要があります。読み取りは決して競合せず、これは読み取り専用トランザクションの読み取りだけでなく、読み書きトランザクションの読み取りにも当てはまります。更新の背後にある読み取りについても同様です。異なるKeyへの書き込みは決して競合しません。同じKeyへの並行トランザクションからの書き込みは競合する可能性があります。最後の特性として、SQLの読み取り専用トランザクションは常にコミットされます。読み取りは競合しないため、OCCの失敗は発生しません。読み取り専用トランザクションであれば、そのような事態は起こり得ないのです。

Thumbnail 1260

同時実行トランザクション間において、read-readコンフリクト、つまり2つのトランザクションが同じデータを読み取る場合は、コンフリクトとはなりません。これは問題ありません。write-readコンフリクト、つまり1つのトランザクションが書き込んだデータを別のトランザクションが読み取る場合も、決してコンフリクトは発生せず、問題ありません。read-writeコンフリクト、つまりその逆のケースも、コンフリクトは発生せず、問題ありません。これら最初の3つのケースでは、トランザクションがアボートされることはありません。最後のケースであるwrite-writeコンフリクト、これは2つの同時実行トランザクションが同じ行に書き込みを行う場合ですが、この場合は少なくとも同時実行セットの2番目のトランザクションがロールバックされることになります。

Thumbnail 1300

スケールアウトを考える上での2つ目のヒントは、Hot keyの範囲を避けることです。これは、Aurora PostgreSQLやRDS PostgreSQL、あるいは自前でデータベースインスタンスを運用するような従来型のリレーショナルデータベース設計に精通している方々にとっては、少し異質に感じるかもしれません。従来型のデータベースエンジンは、パフォーマンスの観点からデータの局所性を重視します。頻繁にアクセスされる行が少数に集中していることを好みます。なぜなら、それらの行をキャッシュに保持でき、ストレージからの読み取りが不要となり、キャッシュミスを回避して優れたパフォーマンスを提供できるからです。そのため、シングルマシンデータベースのパフォーマンスチューニングの多くは、データの局所性を最適化することに重点を置いています。コンピュータサイエンスの観点からも、シングルシステムにおけるデータの局所性は、パフォーマンス面で非常に重要なのです。

一方、DSQLはパフォーマンスの観点から分散を重視します。特に書き込みワークロードを、できるだけキースペース全体に分散させることを望みます。最適なスケールの観点からは、キースペースの各部分にほぼ均等に負荷がかかるようにすることができます。これがどの程度重要かは、アプリケーションの目標とするスケールに大きく依存します。1秒あたり数十、数百、あるいは数千程度のリクエストであれば、この点を気にする必要はありません。最も自然な方法で実装すれば良いのです。しかし、1秒あたり数百万のリクエストを目指す場合は、ワークロードがキースペース全体にどのように分散されているかに細心の注意を払う必要があります。その非常に自然な方法の1つは、Version 7 UUIDをプライマリーキーとして選択することです。これによって、ワークロードがキースペース全体に自然に分散されることが多いのです。これは必ずしも難しいことや人工的な対応を必要とするわけではありません。

Thumbnail 1440

アーキテクチャの話に戻って、マルチリージョンのActive-activeアプリケーションについて説明しましょう。Active-activeが私たちにとってなぜそれほど重要なのかについては、後ほど詳しく説明します。基本的に、ここでのマルチリージョンは2つの目的があります。1つは、特にローカルクライアントの読み取りレイテンシーと、クライアントのエクスペリエンスを最適化することです。例えば、East Coastのクライアントにはローカルな読み取りレイテンシーを提供し、West Coastのクライアントにも同様にデータへのローカルな読み取りレイテンシーを提供したい場合、データベースを大陸全体に分散させる必要があるかもしれません。もう1つの理由は、可用性、耐障害性、またはコンプライアンスに関して重要な要件を持つアプリケーションのためです。少なくとも一部の方々は、マルチリージョンを要求し、アプリケーションを複数のAWSリージョンに分散させることを求めるコンプライアンス体制の下にあると思います。これがマルチリージョンのActive-activeアプリケーションです。

Thumbnail 1520

このアーキテクチャは非常に複雑で、多くの要素が絡み合っているはずだと思われるかもしれません。しかし、そうではありません。マルチAZのシングルリージョンアーキテクチャを単に2回複製しただけです。Region AとRegion Bにそれぞれ1つずつ配置し、それらは互いに通信する必要も、互いのことを考える必要も、さらには互いの存在を知る必要すらありません。

DSQLコンソールにアクセスしてDSQLリンククラスター(マルチリージョンDSQLクラスターとも呼ばれます)を作成したことで、Region AとRegion Bの2つのエンドポイントが提供されます。Region Aのアプリケーションは Region Aのエンドポイントに、Region BのアプリケーションはRegion Bのエンドポイントに向けて設定します。それ以外は、アプリケーションと管理アーキテクチャを複数回デプロイすること以外、特に気にする必要はありません。

Thumbnail 1580

このアーキテクチャの特性について、障害時の動作を見ていきましょう。Availability Zoneが使用できなくなった場合、つまり接続が切断されたり、停電が発生したり、自然災害が起きたりした場合、どうなるでしょうか。実際には、ソフトウェアのデプロイメントに失敗したり、オペレーターが誤って間違ったインスタンスを終了させたりするケースの方が、自然災害よりもはるかに多いものです。十分な注意を払わない限り、そういったことは起こり得ます。Load Balancerは問題のあるアプリケーションへのトラフィック送信を停止する必要がありますが、これには数秒かかる可能性があります。一方、DSQLは数ミリ秒以内に適切な対応を行い、同一リージョン内の残り2つのAvailability Zoneで可用性を維持します。

一貫して、データの損失や永続性の喪失は一切発生せず、コミット済みのトランザクションが消失することもありません。また、一貫性も失われることはなく、時間が逆行するような奇妙な現象も発生しません。アプリケーションのヘルスチェックとLoad Balancingの設計が優れていれば、一部のユーザーへの影響は数ミリ秒程度で済む可能性があります。このような比較的シンプルなアプリケーションアーキテクチャでも、大規模なインフラ障害や重大な運用ミスが発生した場合でも、ダウンタイムを数ミリ秒に抑えることができます。これは非常に大きなメリットです。

Thumbnail 1690

次のスライドは考えたくもないほど怖い内容ですが、考えざるを得ません。リージョン全体が失われた場合、どうなるでしょうか。運用ミスや認証情報の期限切れ、不具合のあるソフトウェアのデプロイメントによって、このリージョン全体が失われるケースを考えてみましょう。もちろん、自然災害やバックボーンの接続性喪失などが原因となることもありますが、そういったケースは稀です。ただし、最も高い回復性を必要とするアプリケーションでは、これらに対する計画も必要です。

DSQLの高速な読み取りと書き込み:リージョン内処理の仕組み

DSQLやアクティブ-アクティブアーキテクチャが登場する前は、このような状況にどう対処していたのでしょうか。プライマリリージョンを失った場合、セカンダリリージョンへのフェイルオーバー方法を考える必要がありました。何週間も何ヶ月も実トラフィックを受けていないアプリケーションのほこりを払い、適切なメンテナンスが行われていなかった可能性があるにもかかわらず、それが正常に動作することを祈るしかありませんでした。データベースの切り替えも、障害の性質によっては非常に簡単な場合もあれば困難な場合もあり、数分から数時間のダウンタイムが発生する可能性がありました。

Active-ActiveアーキテクチャとDSQLを採用することで、このような災害シナリオでもダウンタイムはミリ秒単位に抑えることができます。DSQLはこのようなケースを検知し、その詳しい仕組みについては明日説明させていただきます。Region Bでは継続的にサービスが利用可能で、強い整合性も維持され、データの損失も発生しません。つまり、コミット済みのトランザクションが消失することはありません。このような実際の災害シナリオでも、極めて短いダウンタイムで済むのです。私がActive-Activeについて繰り返し強調する理由がここにあります。

Thumbnail 1810

なぜActive-Activeが望ましいのでしょうか?Amazon Web Servicesや大規模アプリケーションを10年以上運用してきた経験から、いくつかの説得力のある理由があります。その経験から学んだのは、Activeフェイルオーバーアーキテクチャは正しく実装するのが難しいということです。これは常に間違った選択だというわけではありませんが、アーキテクチャ的に困難を伴うということです。

私がActive-Activeアーキテクチャを推奨する理由は、両方のサイドが常に稼働している点にあります。アプリケーションの両サイドがトラフィックを処理しているため、正常に動作していることが分かり、毎秒その状態を監視できます。キャッシュは常にフルの状態を保ち、JITも最適化された状態を維持します - これは数日や数ヶ月間休止状態だったアプリケーションとは異なります。両方のアーキテクチャの両リージョンで継続的に運用経験を積めるため、キャパシティプランニングや予測も容易になります。また、お客様を最寄りのリージョンにルーティングし、読み取りと書き込みの両方で低いレイテンシーを提供することも可能です。

Thumbnail 1930

これは特に重要な利点です。なぜならDSQLは対称的なレイテンシーを提供し、つまりエンドポイントAとエンドポイントBで同じレイテンシー体験が得られるからです。これは、プライマリリージョンが高速で、セカンダリリージョンが時として任意に遅くなる他の分散SQLプロダクトとは大きく異なります。マルチリージョンアプリケーションを構築する際、私は大半のケースでActive-Activeを選択します。一見すると複雑に見えるかもしれませんが、並行性制御と整合性という困難な課題をデータベースに任せることができるため、アプリケーションの両サイドが確実に動作することが分かり、実際にはアプリケーションの他の部分がシンプルになります。

Thumbnail 2050

この対称的なレイテンシーと、お客様を最寄りのリージョンにルーティングできることの重要性について説明しましょう。DSQLでマルチリージョンアプリケーションを構築する場合、読み取りは常にリージョン内で行われ、両サイドとも常に高速でリージョン内で処理されます。Region AのアプリケーションがRegion Aのエンドポイントと通信する場合、SQLはRegion Aで実行され、同じAvailability Zone内のストレージノードからデータを取得します。読み取りデータのために大陸を越えたり、場合によっては世界を横断したりする必要は一切ありません。これらのSELECT文は高速で、ローカルで、リージョン内で実行され、コミットも同様に高速で、ローカルで、リージョン内で処理され、データベースの他端との調整は不要です。

多くのトランザクションアプリケーションは読み取りが中心で、読み取り専用のトランザクションが大半を占めているため、これは非常に優れた最適化の機会となります。例えばAmazon.comを例に取ると、顧客がアプリケーションにアクセスした際、カタログを閲覧するのは読み取り専用です。商品詳細ページを見るのも読み取り専用です。カートに商品を入れるという購入の意思決定をする時になって初めて、より頻度の低い書き込み操作が必要になります。多くのWebアプリケーション、モバイルアプリケーション、そしてサービスアーキテクチャも非常によく似たパターンを持っているため、この高速な読み取りを活用することは非常に有用です。

Thumbnail 2090

驚くべきことに、書き込みもリージョン内で行われ、高速でローカルであり、決してリージョンを跨いで行われることはありません。トランザクションを開始し、更新を行い、さらに別の更新を行うという場合、これらはRegion AのアプリケーションからRegion Aのエンドポイントに対して実行されます。SQLはRegion Aで実行され、これらの更新に使用される読み取りは、Region Aからの読み取り-修正-書き込みとして、素早く行われます。 書き換えトランザクションでさえも、SELECTは依然として高速でローカルです。この優れたローカリティ特性を失うことなく、読み取りと書き込みの両方を行う混合モードのトランザクションを実行できます。

Thumbnail 2110

これが可能なのは、これらの操作がすべて そのリージョン内で強い整合性を保ちながら実行できるからです。このリージョンで強い整合性を保ちながら実行できる理由は、Mattが今朝お話ししたマルチリージョンのクロックアーキテクチャの構築と、世界中のすべてのEC2インスタンスに非常に高精度のクロック信号を配信するEC2タイムサービスの構築に投資したからです。これはAuroraのためだけに構築したものではありません - 現在でもEC2で皆様のアプリケーションでこれを活用することができます。

Thumbnail 2170

ここで分かるように、読み取りと書き込みはリージョン内でローカルに行われ、読み取りはローカルストレージに対して行われ、大陸や世界を横断するような長いレイテンシーの溝を越える必要はありません。コミット時には時間がかかります。なぜなら、コミットはリージョンを跨ぐ必要があるからです 。これは物理法則に起因する制約です。リージョンを失った場合にデータを失わないようにするためには、コミットがクライアントに応答を返す前に、同期的にそのデータを複数のリージョンで利用可能にする必要があります。これより良い方法は存在しません。

遅いと言っても、リージョン構成によって、コミット時に15〜100ミリ秒程度です。現在US East 1でお試しいただけるプレビューでは、US East 2にWitnessリージョンとしてUS West 2を使用しており、マルチリージョンモードでのコミットレイテンシーは約20ミリ秒となっています。通常、単一の更新には3〜5ミリ秒、簡単なSELECTには2〜3ミリ秒程度かかり、そしてコミットには、マルチリージョナルクラスターの設定方法によって、15〜20ミリ秒、場合によっては100ミリ秒かかることがあります。

Thumbnail 2270

これは、データベースやDistributed Systemsの専門家を驚かせる別の興味深い点につながります。 DSQLでは、トランザクションが実はレイテンシーを改善するのです。多くの人は、Distributed Systemsについて考える中で、トランザクションは処理を遅くする概念だと思い込んでいます。しかしDSQLでは、リージョン間の調整コストをトランザクション内の全ステートメントで分散できるため、複数のステートメントを含むトランザクションを書くことで、レイテンシーとスループットが向上します。アプリケーションの制約の範囲内で、複数の処理を行うトランザクションを書くことをお勧めします。複数の作業単位をコミットにまとめるようにしましょう。Auto Commitやそれに相当する方法を使用している場合、DSQLから最高のレイテンシーパフォーマンスを得られていない可能性が高いでしょう。

Thumbnail 2350

覚えておいていただきたいのは、読み取り専用トランザクションは常に高速で、コミット時でも常にローカルで処理され、リージョン間の調整のペナルティを支払う必要がないということです。ただし、大きなトランザクションを作る際の重要な注意点として、コンフリクトの問題に戻ります。トランザクションに含まれるキーが多ければ多いほど、単純により多くのキーが存在することで、他の同時実行トランザクションとコンフリクトする可能性が高くなります。ここでご覧いただけるシミュレーション結果では、2つのキーヒート分布を比較しています:分布の先頭が非常にホットなZipf分布と、キー空間全体に負荷が分散された一様分布です。データベース内のキーの何パーセントにアクセスするかに応じて、2つの同時実行トランザクションの2番目がコンフリクトする確率を調べました。ここでは1%、つまりデータベース内の100個に1個のキーにアクセスする場合、ホットキーが多いZipf分布では、コンフリクトの確率がかなり高くなっています。

一様分布の場合、データベースのキーの1%にアクセスする際のコンフリクトの確率は50%に向かって上昇しています。これは深刻に見えますよね?しかし、実際のところ、トランザクショナルなアプリケーションで、データベース内のキーの1%にアクセスしたり書き込んだりするトランザクションをどれくらい書くでしょうか?おそらく数千の顧客がいて、運が良ければ数万や数百万、数十億の顧客がいるでしょう。データサイズは非常に大きく、スキーマやアプリケーションをキー空間で極端に偏るように設計していない限り、このような問題に遭遇する可能性は低いでしょう。ただし、認識しておく価値はあります。

Strong Snapshot Isolationの選択理由と他の分離レベルとの比較

Thumbnail 2470

残りの15分で、IsolationとConsistencyについて深く掘り下げたいと思います。このトーク中でConsistencyとIsolationについて多く話してきましたが、ここでIsolationとはACIDのIを指します。これは、データベースの専門家がよく知るIsolationレベルです。Consistencyについては、ACIDのCではなく、Distributed Systemsでの定義を指します。つまり、自分の書き込みを読み取れるか?他のトランザクションの効果を適切なタイミングで見られるか?トランザクションが正しく順序付けられているように見えるか?などです。これらについて掘り下げていきましょう。

Thumbnail 2500

Thumbnail 2540

DSQLは、プレビューモードでSnapshot Isolationと呼ばれる単一のIsolationレベルを提供します。これはかなり強力なIsolationレベルです。実際、ある有名なデータベースプロバイダーはこのレベルをSerializableと呼んでおり、これはデータベースの学者たちを本当に怒らせていますが、他の人々はそれほど気にしていないようです。これが、プレビューでサポートする選択されたIsolationレベルです。各DSQLトランザクションは時刻Tにアトミックにコミットされます。つまり、すべてが実行されるか、まったく実行されないかのどちらかです。すべてが単一の時点で実行されたように見えます。時刻T以降に開始されるすべてのトランザクションに対してその効果がすべて見えるようになり、時刻T以前に開始されたトランザクションにはその効果がまったく見えません。

Thumbnail 2580

このシステムでは、アボートまたはロールバックされたトランザクションは、他のトランザクションからは一切見えません。また、プリコミット中のトランザクション、つまりまだCommitを呼び出していない変更中のトランザクションも、DSQLでは他のトランザクションからは見えません。これらは他のトランザクションから完全に分離されています。ここまでの説明は、Serializableのように聞こえますよね?トランザクションはアトミックで、一時点で発生し、新しいトランザクションは見えず、古いトランザクションはすべて見える、という具合です。

Thumbnail 2610

時刻Tで開始されるトランザクション(ここで重要なのは、コミット時ではなく開始時という点です)は、その時刻Tにおけるデータベースの完全に一貫性のあるスナップショットを参照します。T以前にコミットされたすべてのトランザクションは見え、T以降にコミットされたトランザクションは見えず、実行中やアボートされたトランザクションも見えません。ここでは2つの概念があります:トランザクションのコミット時刻(データベースに書き込まれる時刻)と、トランザクションの開始時刻(一般的にBeginやStart Transactionを呼び出す時刻)です。この2つの間には、他のトランザクションが書き込んでコミットしたキーを読み取れる競合期間が存在します。これが、Snapshot Isolationが本質的にSerializableではない理由です。分離レベルの説明は非常に難しいので、多くの例は挙げませんが、オンラインには素晴らしい資料がたくさんあります。

Thumbnail 2700

もう1つ重要な点は、DSQLはマルチリージョンモードでも強い一貫性を持っているということです。 分散システムの専門家向けに具体的に言うと、これはLinearizableであるということです。すべてのトランザクションは、ある特定の時点でアトミックに発生したように見えます。トランザクションがアトミックに発生する時刻(つまりコミット時刻)は、必ずCommitを開始した実際の壁時計時刻よりも後で、かつCommitへのレスポンスを受け取った実際の壁時計時刻よりも前になります。分散システムでは、これらは瞬時には発生せず、その間にある程度の時間がかかりますが、そのアトミックなコミットの瞬間は、必ずCommitの開始と終了の間に現れます。

これはLinearizabilityと呼ばれる非常に強力な一貫性特性です。この結果として、データベースに書き込みを行い、その後他の人にコミットしたことを伝えた場合、その人は必ずその書き込みの影響を見ることができます。また、データベースに書き込みを行い、その直後に読み取りを行った場合、異なるリージョンで書き込みを行った場合でも、必ずその書き込みの影響をすぐに確認できます。これは非常に強力な一貫性特性なのです。

Thumbnail 2790

これらの要素を組み合わせることで、DSQLは文献で言うところのStrong Snapshot Isolationを実現しています。これはSnapshot IsolationとStrong Consistency(または Linearizability)を組み合わせたものです。ほとんどのアプリケーションにとって、これは非常にシンプルなプログラミングモデルを提供し、開発者はシステムの分散性について心配する必要がありません。これはAWSサービスを何十年も運用してきた経験から得た教訓です。私たちは、開発者がEventual Consistencyに直面した際に、正しいアプリケーションコードを書くことが非常に困難だと感じることを発見しました。

これは、AWSとAmazonにとって、ある意味転換点となりました。私たちは当初、Eventual Consistencyの大きな提唱者の一つでした。15〜20年前、私たちはEventual Consistencyのスケールメリットについて盛んに語っていました。しかし、世界最大規模のアプリケーションや複雑なビジネスロジックを持つアプリケーションを構築していく中で、アプリケーション開発者にとって、Eventual Consistencyの環境下で正しいコードを書くことが極めて困難、時には不可能であることが分かりました。このような重要な教訓があったからこそ、私たちはDSQLではデフォルトで、そして現時点では唯一のモードとしてStrong Consistencyを選択しています。

Thumbnail 2880

他のデータベースに詳しい方は、私たちのStrong Snapshot Isolationと呼ぶこの分離レベルが、さまざまなデータベースが提供する分離レベルのスペクトラムの中でどこに位置するのか気になるかもしれません。MySQLのREAD COMMITTED、PostgreSQLのREAD COMMITTED、そしてMySQLのREPEATABLE READは、いずれもDSQLが提供する分離レベルよりも厳密に弱い分離レベルです。PostgreSQLのSerialモードは完全にSerialであり、DSQLが提供するレベルよりも強い分離レベルです。私たちの分離レベルは、PostgreSQLのREPEATABLE READモードと同等です。

データベースコミュニティでは少し議論の的となっている点もあります。PostgreSQLのREPEATABLE READは、ANSIが定めているようなスナップショットを使用した実装方法ではありません。実際には厳密なREPEATABLE READではないのです。PostgreSQLは正しいことをしました。ただし、それはSQLの仕様が定めていた正しいことではありませんでした。これはPostgreSQLでよくあることです。PostgreSQLは多くの場合、正しいことをします。賢い人々によって設計されたからだと私は考えています。

Thumbnail 2950

では、なぜStrong Snapshot Isolationが適切なのでしょうか?なぜSerializableや、より弱いレベルではないのでしょうか?私たちは、分散型の大規模アプリケーションや、あらゆる規模のアプリケーションにとって、Strong Snapshot Isolationがトレードオフの中での最適なポイントだと考えています。Strong Consistencyの利点についてお話ししましたが、それらはすべて、アプリケーション開発者が正しいコードを構築し、アプリケーションが実際に機能し、意図した通りに動作することを容易にすることに関係しています。そしてそれは非常に価値のあることなのです。

では、なぜSnapshotを選び、Serializableを選ばなかったのでしょうか?確かにSerializableは、一見するとより良い選択肢に思えます。トランザクションの異常を心配する必要がなく、すべてのトランザクションが時系列で整然と並び、とても純粋で素晴らしい世界が実現できそうです。

しかし、データベース業界で長年の経験がある人々は、Serializable分離レベルには大きなパフォーマンス上の欠点があることを知っています。このパフォーマンスの問題により、アプリケーションプログラマーは複雑な対応を迫られることになります。なぜなら、Serializableのパフォーマンスの問題を回避するために、クエリやアプリケーションの書き方に細心の注意を払う必要があるからです。具体的には、Serializableではトランザクションが実行する読み取り操作のセットを、他のトランザクションの書き込みと比較する必要があるため、良好なパフォーマンスとスケーラビリティを実現するには、トランザクション内で読み取る行数を慎重に制御するコードを書く必要があります。

Serializable分離は素晴らしいアイデアに聞こえますが、実際にはアプリケーションプログラマーの負担を増やすことになります。では、READ COMMITTEDやRead Uncommittedのような、Snapshot分離よりも弱い分離レベルはどうでしょうか?私たちのアーキテクチャでは、明日詳しく説明する予定のストレージの仕組みから得られる利点により、ハードウェアクロックと組み合わせたMultiversion Concurrency Controlという技術を使用しています。実は、私たちのアーキテクチャでは、より弱い分離レベルを採用してもパフォーマンス上の利点は得られないのです。

スケールアウト可能なSQLレイヤーを構築する際、コンピュートレイヤーをスケールアウトしても性能を維持するには、個々のコンポーネントが互いに通信を避ける必要があります。分散システムの基本として、スケーラビリティを実現するには調整を避けることが重要です。水平方向にスケーラブルなフリートで複数のSQLインスタンスを実行する場合、トランザクション中の通信は調整のオーバーヘッドを生むため避けたいところです。トランザクション中の通信がない場合、コミットされていない変更は完全に独立した空間で発生するため、他のトランザクションから見えることはありません。

私たちは、そのレイヤーでスケーラビリティを実現するために、調整を減らしトランザクション中のシステムメッセージを最小限に抑えるよう設計したことで、強力な分離性をほぼ無償で手に入れることができました。これにより、スケーラビリティ、可用性、レイテンシーの面で大きな利点が得られます。分散システムにおいて、強力なSnapshot分離は最適なトレードオフを実現する理想的な分離レベルと言えます。将来的には他の分離レベルもサポートするかもしれません。特に、データベースをSerializableレベルで運用しているユーザーからの要望があれば、Serializableの実装も検討するかもしれませんが、そのような運用をしているユーザーは比較的少数です。これが永遠に唯一のオプションだと言っているわけではありませんが、Aurora DSQLで私たちのお客様が構築すると予想されるアプリケーションのタイプに対して、非常に適切なデフォルト設定として選択しました。

まとめと今後の展望:DSQLの活用と関連セッションの紹介

Thumbnail 3220

このトークを通して何を学んだのでしょうか? シンプルなアーキテクチャでもスケーラビリティを確保できます。Aurora DSQLやDynamoDBのような、障害耐性やマルチAZの耐久性を自動的に処理してくれるデータベースを活用すれば、高い可用性や耐久性、その他の有益な特性を実現できるのです。これはクラウドデータベースを利用する大きな利点で、シンプルなアーキテクチャでも優れた特性を実現できます。また、Active-activeの構成が有効だということも学びました。マルチリージョンやマルチAZのアプリケーションを設計する唯一の方法ではありませんが、デフォルトの選択肢として優れていると考えています。興味深いことに、複数のAvailability Zoneやデータセンターにまたがるシステムを構築する場合、ほとんど誰もActiveフェイルオーバーのアプローチを選択しません。代わりに、Active-activeを選択し、アプリケーションを複数のAZに分散配置し、それらすべてがデータベースと通信するようにします。このアプローチは物事をシンプルにし、作業の分散を可能にし、レジリエンスを向上させ、フェイルオーバーの心配をなくします。フェイルオーバーを心配する必要がないため、より高い回復力を実現できます。マルチAZアーキテクチャでこのアプローチを選択する理由は、そのままマルチリージョンアーキテクチャにも当てはまります。

データベースがリージョン間でActive-activeとして構築されている場合(Aurora DSQLはそのように設計されています)、スケーラビリティにとって重要なのはHot write keysを避けることです。これはAurora DSQLでスケーラビリティを確保する上で、おそらく最も重要な単一の要素です。

Thumbnail 3390

先ほど申し上げたように、アプリケーションが1日10リクエストしか処理しないのであれば、これについて心配する必要はありません。大したことではないので、好きなようにすればいいのです。しかし、1秒あたり数百万または数十万のリクエストを処理しようとする場合、優れたスループットと優れたスケーラビリティを得るためには、Hot write keysを避けるように慎重に設計する必要があります。また、トランザクションを使用すべきだということも学びました。トランザクションが処理を高速化し、スケーラビリティを向上させ、レイテンシーを低下させ、スループットを向上させる可能性があるというのは、少し意外に感じるかもしれません。トランザクションは、アプリケーション開発者にとって素晴らしいツールです。並行コードの作成をより簡単でクリーンにし、障害が発生した場合にロールバックできるため、フォールトトレラントなコードの作成もより簡単でクリーンになります。そしてDSQLでは、パフォーマンスを向上させることができます。

DSQLについてもっと詳しく知りたい方は、ほとんどのドキュメントがオンラインで公開されていますが、明日も素晴らしいトークがいくつか予定されています。DAT427では、DSQLの内部構造について、私たちが何をどのように設計し、どのように構築したのか、そして私たちが強力で興味深くユニークだと考えている部分について説明します。DAT421はDSQLのハンズオンワークショップで、実際にDSQLでアプリケーションを構築し、ゼロからスタートしてどのように動作するかを体験していただきます。私はこのようなハンズオンワークショップを学習の機会として大好きです。なぜなら、私が理論的に説明してきたことではなく、実際にものを作るために必要な現実を体験できるからです。

そしてDAT334では、このプロジェクト全体に携わってきたPEの一人であるJamesとプロダクトマネージャーが、チョークトークを行います。皆さんの質問に答え、ホワイトボードにアーキテクチャの選択肢を描き、スキーマの構造化の方法やDSQLの機能について説明します。このサービスについて深い知識を持つ人々と質疑応答の時間を持ちたい方にとって、これも素晴らしいトークになるはずです。

Thumbnail 3540

ありがとうございます。私はMarc Brookerです。私の職場のメールアドレスでご連絡いただけます。また、SNSでも発信していますので、LinkedInでもつながれます。ぜひDSQLを試してみてください。コンソールで利用可能です。PostgreSQLドライバーを使用できますし、お気に入りのPostgreSQLのCLIツールも使えます。ぜひ試していただいて、ご感想をお聞かせください。次にどんな機能を追加してほしいか、私たちが実装したこれらの機能のうち、どれが素晴らしいと思われたか、また何を変更すべきかについても教えてください。GAリリースの前にプレビュー版を提供している理由は、まさにお客様からのフィードバックをいただくためです。この400レベルのセッションに参加されているということは、かなり高度な知識をお持ちだと思います。皆様は専門家であり、まさに私たちがGAリリースを皆様にとって完璧な製品にするために、ぜひご意見を伺いたい方々です。モバイルアップでセッションのアンケートにご協力ください。次回のre:Inventをより良いものにするために役立てさせていただきます。ありがとうございました。


※ こちらの記事は Amazon Bedrock を利用することで全て自動で作成しています。
※ 生成AI記事によるインターネット汚染の懸念を踏まえ、本記事ではセッション動画を情報量をほぼ変化させずに文字と画像に変換することで、できるだけオリジナルコンテンツそのものの価値を維持しつつ、多言語でのAccessibilityやGooglabilityを高められればと考えています。

Discussion