📖

re:Invent 2024: IntuitのQuickBooksがAuroraでモノリスからマイクロサービスへ

2024/01/01に公開

はじめに

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

📖 AWS re:Invent 2024 - Scaling from monoliths to microservices with Amazon Aurora (DAT325)

この動画では、IntuitのPrincipal EngineerであるNarayanan Gopalakrishnanが、QuickBooksのモダナイゼーションの取り組みについて解説しています。Monolithデータベースが抱える小規模独立ワークロード、絡み合ったワークロード、時系列データ、非対称ワークロードなどの課題を整理した上で、AWS Database Migration Service、Amazon Aurora、Aurora Serverless、Aurora Limitless Databaseなどを活用した段階的な移行手法を具体的に説明しています。特に、1,000万人以上の顧客を抱えるQuickBooksの事例を通じて、データベースの分割方法、zero-ETL統合によるデータウェアハウスとの連携、Query Plan Managementによるパフォーマンス最適化など、実践的な知見が共有されています。
https://www.youtube.com/watch?v=2LDm-12rXvw
※ 動画から自動生成した記事になります。誤字脱字や誤った内容が記載される可能性がありますので、正確な情報は動画本編をご覧ください。
※ 画像をクリックすると、動画中の該当シーンに遷移します。

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

本編

モノリスデータベースの課題:Intuitの事例紹介

Thumbnail 0

本日は、IntuitのNarayanan Gopalakrishnanをお迎えして、この旅にご案内させていただきます。パーティーの直前の木曜日の遅い時間にお集まりいただき、誠にありがとうございます。皆さんお疲れのところ、本当に感謝いたします。

Thumbnail 30

Thumbnail 50

さて、皆さんはMonolithを抱えていらっしゃいますね。 Monolithについては様々な捉え方がありますが、データベースの観点から見ると、少しコントロールが効かなくなっているものと言えます。この例では、複数のアプリケーションが1つのデータベースと通信しており、そのデータベースには多種多様なデータが格納されています。 では、この例について詳しく見ていきましょう。

モノリスデータベースの3つの主要な問題点

Thumbnail 70

小規模な独立したワークロードが動いているかもしれません。私がAmazonに入社した当初、このようなケースが多くありました。これはデータベースに同居している、メインとは関係のないものです。 この例では、いくつかのテーブルを持つSupplierアプリケーションです。そこまで大きくなく、多くの処理も行っていませんが、存在しています。このような状況になる理由はいくつかあります。商用データベースのライセンスの問題があったかもしれませんし、利用可能なリソースやサーバーがあったからかもしれません。あるいは、管理が大変だったため、新しいデータベースを追加したくなかったのかもしれません。

Thumbnail 90

問題は、そのテーブルが制御不能になったり、メインアプリケーションとは関係のない不適切なクエリが発生したりする可能性があることです。通常はCPUをそれほど使用しないとしても、障害の原因となる可能性があります。また、メンテナンスウィンドウについて関係者と調整する必要がありますが、アプリケーションごとにメンテナンスのニーズが異なる場合、これが複雑になります。

Thumbnail 120

Thumbnail 140

次のケースはより難しい問題です。私が「絡み合ったワークロード」と呼ぶものです。これは、複数のアプリケーション(同じアプリ内の場合もあれば、異なるデプロイメントに分散している場合もある)が、一箇所にまとめられたデータセットと通信している状態です。この例では、顧客、注文、配送のデータが該当します。 先ほどと同じ理由に加えて、もう1つ理由があります。開発者にとって実装が非常に簡単だったのです。注文システムにいる場合、配送データがどこにあるのか考える必要がなかったからです。

Thumbnail 160

リーダーシップがよく見落としがちな問題は、共有状態が存在することです。例えば、出荷チームが他のチームと調整することなく出荷関連のテーブルに変更を加えて列を追加した場合、システム障害が発生する可能性があります。これは、共有QA、共有テスト、共有認証が必要になることを意味します。その結果、エラーが増加し、開発速度が低下することになります。このようなシステムに関わる開発者が増えるほど、状況は一層困難になっていきます。

時系列データと非対称ワークロードがもたらす課題

Thumbnail 190

Thumbnail 210

Thumbnail 230

もう一つ、一般的に見落とされがちな側面は時系列データです。時間の経過とともにデータベースが成長し、特に注文の世界では、注文データが増え続けていきます。 注文を保存する際、インデックスではなくヒープ領域のストレージだけを見ると、それはブロックに格納されます。そのブロックはその時点で他のデータで埋められ、その注文を見つけるのは非常に簡単です - そのブロックを取得するだけで済みます。 数週間後に別の注文が入ってきた場合、それは新しいブロックに格納されるため、やはり見つけるのは簡単です。

Thumbnail 240

Thumbnail 260

しかし、「去年の注文をすべて見つけてください」というようなクエリの場合、コストは10倍になります。これは単純な例ですが、私たちのシステムでは、1つの注文に対して3つのOrder Item、そしてOrder Itemごとに2つのItem Detailがあります。 つまり、このクエリでは約100のブロックを取得することになります。以前Amazonにいた頃、過去数年分の注文に関するクエリに対して、何万ものブロックを収集しなければならない顧客もいました。これらの大規模なクエリは、通常のアプリケーションクエリというよりも、レポーティングクエリのような様相を呈してきます。

Thumbnail 290

最後に説明したいタイプは、非対称ワークロードです。非対称とは、メインアプリケーションで行っている中核的な処理とは異なるものを指します。これには分析やSearch、その他の例として、データウェアハウジングの意思決定や、OLTPシステムに対するリアルタイムダッシュボードの実行などが含まれます。良さそうに聞こえますよね?

Thumbnail 310

Thumbnail 320

ETLを行う必要がなく、 データが常に最新の状態で遅延がないため、ビジネスリーダーは喜ぶかもしれません。しかし、重大な欠点があります。データベースに対してこのような大規模な操作を実行するクエリは、 大規模なスキャンやソートを伴うため、システムを不安定にする可能性があります。これが非対称と呼ばれる理由は、単純なポイントセレクトや小規模なJoinではないからです。私たちの多くが経験してきたように、このような問題のあるクエリを1つ実行するだけで、CPU、IO、メモリの使用率が完全に不安定になる可能性があります。

IntuitのQuickBooksモダナイゼーション:背景と目標

ここまでMonolithの基礎についてお話ししてきましたが、ここでIntuitの事例と、その取り組みについてお話しいただくためにNarayananをお招きしたいと思います。ありがとうございます、Grant。皆様、こんにちは。私はIntuitのPrincipal EngineerのNarayanan Gopalakrishnanと申します。本日は、QuickBooksのモダナイゼーションの取り組みと、その成功のレシピについてご紹介させていただきます。

Thumbnail 390

Thumbnail 400

まず、Intuitについて簡単にご紹介させていただきます。私たちはAIを活用したFintechプラットフォームで、TurboTax、Credit Karma、QuickBooks、そしてMailchimpを通じて、個人のお客様、小規模ビジネス、中堅企業のお客様にサービスを提供しています。QuickBooksと聞くと、簿記や会計を思い浮かべるかもしれませんが、今日のQuickBooksは会計以上のことができます。ご覧のように、会計は私たちのプラットフォームがビジネスを管理するための多くの機能の一つに過ぎず、その過程で会計処理が行われるのです。私たちは1,000万以上の中小企業のお客様にQuickBooksをご利用いただいており、最近ではエンタープライズ向けのサービスも開始しました。

Thumbnail 420

では、私たちのレガシーアーキテクチャについてお話しします。QuickBooksはKubernetes上で動作するJavaアプリケーションです。リレーショナルバックエンドには商用データベースを使用しており、Swim-laneアーキテクチャで展開しています。Swim-laneとは、データベースを含むアプリケーションの独立した単一のデプロイメント、つまり私たちバージョンのサイロアーキテクチャです。これには2つの理由があります:Swim-laneを追加することで水平方向にスケールできる拡張性と、異なる地域のお客様を異なるSwim-laneでホストし、場合によっては異なるベース地域にデプロイできるGeo-partitioningです。現在、1,000万人のお客様を管理するために、これらのフリートを運用しています。

Thumbnail 460

Thumbnail 470

私たちのデータベースは数百テラバイトのデータを管理し、100万以上のプロビジョンドIOPSを使用して、リレーショナルデータベース上でOLTPとOLAP検索のユースケースを処理しています。アプリケーションは数百万行のコードを持ち、数千のダイナミッククエリと複数の複雑なクエリを扱っています。また、独自のデータベーススキーマジェネレーターとデータアクセス・ダイナミックSQLジェネレーターを開発しました。これらはすべて、レガシーデータベースで動作するように設計され、様々なデータベース機能を使って最適化されています。

Thumbnail 500

Thumbnail 530

Thumbnail 540

モダナイゼーションの必要性について見ていきましょう。QuickBooksは進化し、時間とともに機能を追加し続けた結果、いくつかの課題を抱えたMonolithに成長しました。特に大規模なお客様や、現在の10倍のデータを扱おうとする次の成長フェーズに向けて、スケーリングが困難になってきていました。また、開発のスピードも低下し、管理コストも増加の一途をたどっていました。これらの課題に対処するため、私たちはクラウドネイティブなオープンソースデータベースを使用したサービスベースのアーキテクチャに移行することを決定しました。これにより、次のような目標アーキテクチャの設計図が出来上がりました。ご覧のように、このアーキテクチャでは、一つのデータベースですべてを解決するのではなく、ユースケースに応じて複数のデータベースを選択できるようになっています。

Thumbnail 560

Thumbnail 570

Thumbnail 580

要件を見ていきましょう。私たちの目標は、このMonolithシステムを、1,000万人のお客様に影響を与えることなく、この新しいアーキテクチャに移行することでした。その際、100%のデータの整合性と機能の同等性を確保し、フォールバックのサポートと、パフォーマンスの向上、そしてライセンスに基づいた期限までに完了させる必要がありました。さらに、この全てを、機能開発とお客様へのリリースを継続しながら実施しなければなりませんでした。言わば、飛行中の航空機のエンジンを交換するようなものでした。

Thumbnail 590

Thumbnail 600

ワクワクしてきましたか?どのようにアプローチしたのか見ていきましょう。私たちは段階的なアプローチを取り、まず製品をサポートするために必要な機能に基づいて技術評価を行うことから始めました。実現可能性に基づいて、変更の範囲を定義し、高レベルの技術設計を行い、計画フェーズを設けました。

Thumbnail 610

Thumbnail 620

その後、実際の実行フェーズに入り、スキーマ変換、データ移行、アプリケーション変換を行いました。広範なテストを実施し、慎重なロールアウト戦略を立てて完了させました。では、これらの各フェーズを詳しく見ていき、いくつかの決定事項と重要な学びについて説明していきましょう。

QuickBooksのマイグレーション戦略:評価からテストまで

Thumbnail 630

Thumbnail 640

Thumbnail 650

まず評価フェーズから始めましょう。SaaSアプリケーションとして、私たちの基本的な要件の1つはマルチテナンシーです。このトピックについて簡単に説明しましょう。データベースでマルチテナンシーを実装する基本的なモデルは3つあります。1つ目はSiloモデルで、顧客ごとに専用のデータベースを持つ方式です。これは最高レベルの分離を提供しますが、運用オーバーヘッドも高くなります。これは、テナント数が限られている場合に適したオプションです。2つ目はBridgeモデルで、1つのデータベースを複数のテナントで共有しますが、それぞれが専用のスキーマを持ちます。これはデータの分離と運用オーバーヘッドのバランスが取れたモデルです。実際、QuickBooksは初期にこのモデルを採用していましたが、何百万というテナントには対応できないことがすぐに分かり、このモデルから脱却する必要がありました。3つ目はPoolモデルで、1つのデータベーススキーマを複数のテナントで共有します。これは少ない運用オーバーヘッドで多数のテナントに対応できる優れたモデルですが、データの分離レベルは高くありません。

Thumbnail 730

Thumbnail 740

Thumbnail 750

BridgeモデルからPoolモデルに移行する際のこれらの懸念に対処するため、私たちはデータベースで特定のスキーマ設計原則に従い、データの分離を保証し、テナンシーモデルをアプリケーションから透過的にするレイヤーを実装しました。これらの原則は長期的に非常に有効に機能しています。では、私たちが求めていた他の機能についても見ていきましょう。何十億行もの行数を持つテーブルや時系列データを含むテーブルがあり、それらを管理するための商用グレードのパーティショニングが必要でした。機能開発を継続するためにダウンタイムなしで複雑なスキーマ変更を行える必要があり、そのためにはOnline Schema Evolutionが必要でした。システムにある複雑なクエリのユースケースを実装するためには、SQLの全機能が必要でした。それらの複雑なクエリを適切に実行できるよう調整するためのツールとテクニックも必要でした。さらに重要なのは、一度調整したら、時間が経過してもパフォーマンスが一貫していることを確保する必要があり、ここでQuery Plan Stabilityが重要になります。また、負荷に対応するために数千の接続をスケールできる能力も必要でした。

Thumbnail 760

Thumbnail 780

Thumbnail 800

これらの機能と慎重な評価に基づき、私たちはRow-level Securityやその他必要な機能のために Amazon Aurora PostgreSQL を、そしてスケーラビリティのために Auroraを選択しました。さらに重要なのは、私たちが求めていたQuery Plan の安定性を提供してくれる Aurora Query Plan Management を採用したことです。では、実際の実装についてご説明しましょう。私たちは独自のスキーマジェネレーターを持っていたので、 そのジェネレーターに PostgreSQL のサポートを追加し、PostgreSQL のベストプラクティスに基づいてデータ型のマッピングルールを実装しました。これは非常に重要なステップでした。その後、それほど数は多くありませんでしたが、トリガーとストアドプロシージャの変換を行い、データ移行の作業に着手しました。重要な機能については、 広範なプルーフオブコンセプトを実施し、それらの機能が私たちのユースケースで期待通りに動作するだけでなく、スケールしても問題なく機能することを確認しました。

Thumbnail 810

Thumbnail 840

アプリケーションは レガシーデータベース向けに書かれていたため、最初に行ったのは SQL 抽象化レイヤーの導入と、すべてのデータアクセスをその背後にリファクタリングすることでした。これにより、開発者はデータベースを意識することなくアプリケーションの開発を継続できるようになりました。動的 SQL 生成とコード生成ツールに PostgreSQL のサポートを追加し、同じ抽象化レイヤーの背後に配置しました。開発者はデータベースを気にすることなく作業を続けることができ、レガシースタックとターゲットスタックの両方で並行してビルドとデプロイを行うことができました。これにより、 プロダクトの機能開発を続けながら、リファクタリングを進めることができました。

Thumbnail 850

Thumbnail 860

Thumbnail 870

Thumbnail 880

データ移行について見ていきましょう。私たちは データ移行のために AWS Database Migration Service (DMS) を選択し、DMS プレイブックからいくつかのパターンを採用しました。最初に採用したのはフォールフォワードパターンです。これは次のように機能します: DMS を使用してソースから対象の Aurora へのレプリケーションを行い、さらにこの対象の Aurora からソースデータベースのクローンへの別のレプリケーションを設定します。 このアプローチの利点は、パイプライン全体を継続的にテストできることと、レプリケーション中にデータの問題が発生しても、ソースデータベースが intact な状態で残っていることです。 2番目に採用したのはフォールバックパターンです。これは DMS を使用してソースから対象への同一のレプリケーションから始まりますが、対象への切り替えを行った後、逆方向のレプリケーションをソースに向けて開始します。この方式の課題は、Aurora に依存している時にのみこの方向のパイプラインをテストすることになり、問題が発生してフォールバックが必要になった場合にデータ損失が発生する可能性があることです。

QuickBooks は複数の Swim Lane を使用しているため、最初の一連の Swim Lane には最初のパターンを使用しました。自信が持てるようになってからは、効率性を考慮して2番目のパターンに切り替えました。これらすべての変更により、全く新しいデータベースと完全に書き直されたデータアクセスコードを持つシステムの機能とパフォーマンスのテストは大きな課題となり、残された時間も多くありませんでした。そこで私たちは、Capture Replay テクニックを使用する革新的なアプローチを考案し、これが大きな転機となりました。

Thumbnail 940

Thumbnail 950

Thumbnail 960

この仕組みを見ていきましょう。本番環境で稼働しているアプリケーションに、 軽量な計装を追加して実行されるすべてのクエリとバインド変数を取得し、それらをキューに格納しました。これを動的クエリ再生成コンポーネントで処理して、 レガシークエリをそれぞれ対応する PostgreSQL クエリに変換し、リポジトリに保存しました。これにより、本番のワークロードから数百万のクエリを取得し、 レガシークエリを対応する PostgreSQL クエリに変換してこのリポジトリに保存することができました。

私たちはReplayの作業を、本番環境のクローンを構築することから始めました。本番データベースから、ソースエンジンとターゲットエンジンの両方に継続的なレプリケーションを設定しました。この環境で、キャプチャしたクエリをキューを通じて再生し、キューワーカーがLegacyとPostgreSQLのクエリをそれぞれのエンジンに対して実行しました。実行された各クエリに対して2つのタスクを行いました:機能的な違いを特定するために結果を行ごと、列ごとにチェックし、チューニングが必要な領域を特定するためにパフォーマンスメトリクスを収集しました。この処理を100回以上実行して、機能面とパフォーマンス面の問題を発見しました。また、本番環境に移行する前に、異なる設定でターゲットシステムをテストするためにもこの手法を活用し、次のフェーズであるロールアウトに進む自信を得ることができました。

段階的ロールアウトと成果:Intuitの成功事例

Thumbnail 1030

Thumbnail 1040

Thumbnail 1060

Thumbnail 1070

Thumbnail 1080

オフピーク時間帯に4時間のロールアウトから始める段階的なロールアウトフェーズを実施しました。 まずはオフピーク時間帯に新システムの動作を確認し、4時間以内に計画的に切り戻すという考えでした。 次に24時間のロールアウトを試み、ピーク時のトラフィックも処理しました。システムの健全性と安定性を24時間モニタリングし、24時間後に計画的に切り戻しを行いました。これらの学びを活かして、 1週間のロールアウトを実施しました。予期せぬ問題が発生しない限り、ターゲットシステムを継続して使用することが目標でした。これらの経験を基に、 最初のSwim Laneセットのロールアウトを開始しました。2週間のロールバック期間を設けており、完全に切り離す前に最大2週間のデータを逆方向にレプリケーションしていました。 その後、残りのSwim Laneについては、同じプロセスを繰り返して完了まで拡大していきました。

Thumbnail 1110

Thumbnail 1130

このプロジェクトで最も誇りに思っているのは、Capture Replayによる入念なテストとロールアウトプロセスが完璧だったため、計画外の切り戻しが一度もなかったことです。予定通りにすべてのSwim Laneの移行を完了しました。それでは、得られた利点と結果を見ていきましょう。 Amazon Auroraにより、QuickBooksのような読み取り負荷の高いシステムに対して、複数のリーダーを使用したより優れたスケーラビリティを実現しました。また、高可用性も確保され、Aurora Globalを使用することで災害対策機能が標準で提供され、ワンクリックで災害対策訓練を実施できるようになりました。

Thumbnail 1150

Thumbnail 1160

Thumbnail 1180

検索機能をリレーショナルデータベースからOpenSearchに切り替えたことで、単純なテキスト検索を超えて、セマンティック検索やハイブリッド検索が可能になりました。これにより、製品内のAIユースケースの実現を支援しています。監査機能をエコシステム内の再利用可能なサービスとして構築し、 これにより興味深い不正検知や異常検知の機能、そしてAIユースケースが実現可能になりました。 プランの安定性については嬉しい驚きがありました。PostgreSQLでより良いプラン安定性が得られ、プランフリップによる予期せぬスパイクが大幅に減少しました。Query Plan Managementチームの素晴らしいパートナーシップと、私たちのユースケースをサポートするためにQPMに追加された機能や発表に感謝したいと思います。

Thumbnail 1190

Thumbnail 1200

数百万のプロビジョニングに対する支払いから従量課金モデルに切り替えることで、ホスティングコストを削減できています。まとめると、より低コストで より良いスケールと開発速度を実現しました。では、次は何でしょうか?サービスベースのアーキテクチャにより、 データを統合する必要のあるデータベースが多数存在しています。

Thumbnail 1210

Thumbnail 1220

私たちは、管理している大規模なデータベース群のデータ統合にZero-ETLの活用を検討しています。 バージョンアップグレードには多大な労力がかかるため、それを簡素化するためにBlue/Green Deploymentの採用を検討しています。自社開発のShardingは私たちにとってうまく機能していますが、 まだまだ差別化につながらない重労働が多いのが現状です。そこで、マネージドShardingソリューションとしてAmazon Aurora Limitless Databaseの活用を検討しています。

Grantにバトンを渡す前に、この素晴らしい取り組みに参加したIntuitの全チームメンバーに感謝の意を表したいと思います。ご想像の通り、これは決して容易な道のりではありませんでした。数々の課題に直面しましたが、チームの情熱と献身的な取り組みのおかげで、すべての課題を乗り越えることができました。また、この journey全体を通じて素晴らしいパートナーシップを提供してくれたAWSにも感謝しています。皆様にとって有意義な内容であったことを願っています。

AWS Database Migration ServiceとAmazon Auroraの機能紹介

Thumbnail 1270

Thumbnail 1280

ここからは、Ryanが言及したサービスの中で、このマイグレーションパスで有用だと考えられるものについて詳しく見ていきましょう。最初はAWS Database Migration Service(DMS)です。 実はこれを Migration Serviceと呼ぶべきか、Replication Serviceと呼ぶべきか、多くの議論がありました。というのも、このサービスは両方の機能を持っているからです。 まず最初に、主にマイグレーションの側面についてお話しします。結果的にこの名前に落ち着いたのは、マイグレーションを支援する多くの機能があるからです。あるエンジンから新しいエンジンへ、または商用データベースからオープンソースへの移行を行う場合、優れたSchema Conversion Toolを使用して、スキーマを分析し、どのような違いがあるのか、どこに問題があるのかを特定し、新しいシステムへの移行をサポートします。

Thumbnail 1300

Thumbnail 1310

Thumbnail 1320

Thumbnail 1330

変換プロセス全体を見ると、ソースデータベースから始まって最終的なターゲットに至るまで、多くのステップがあります。DMSはこのプロセス全体をサポートできます。最初のステップは評価で、既存のすべてのデータベースを確認し、すべてのコードを分析して、実際の状況を把握します。その後、Schema Conversion Toolを使用して新しいスキーマを生成します。これには非常に複雑になり得るストアドプロシージャのコードも含まれます。現在では、以前は変換が困難だったより複雑なコードの処理を支援するGenerative AI統合機能も備えています。

Thumbnail 1340

Thumbnail 1350

Thumbnail 1370

最後のステップは、Narayananが示したように、ソースからターゲットへのレプリケーションツールとして使用する段階です。新しいスキーマとデータの両方を取り込んでレプリケーションを行います。しかし、これはまだ半分に過ぎません。データは移行できても、アプリケーションはまだ対応できていないかもしれません。ここでQ Developerが役立ちます。Schema Conversion Toolで生成したスキーマを使用して、新しいデータベースで動作するようにアプリケーションを更新する作業を支援します。同じエンジン間での移行の場合は、DMSをレプリケーション用途だけに使用することができます。

Thumbnail 1380

Thumbnail 1400

先ほど申し上げた通り、これはレプリケーションサービスとして機能します。左側にターゲット、右側にデスティネーション、そして真ん中にDMSがあります。まず、フルロードを実行してすべてのデータをダンプし、ロードした後、CDCロジカルレプリケーションを行ってキャッチアップします。追いついたら、切り替えが可能になります。しかし、DMSの活用はこれだけではありません。マイクロサービスアーキテクチャの一部としても使用できます。Amazon Auroraから実行している場合、DMSを通じてデータをファンアウトし、他のAuroraデータベースや様々なサービス、あるいはお客様独自のアプリケーションにレプリケートすることができます。

Thumbnail 1430

Amazon Auroraは、クラウドのために特別に設計されたデータベースです。MySQLとPostgreSQLの両方と完全な互換性があります。ただし、同時にではありません - それは奇妙ですよね。各エンジンにはそれぞれの利点があると考えているため、好みのエンジンモードを選択できます。共通している特徴は、パフォーマンス、スケーラビリティ、可用性、耐久性、セキュリティ、そしてフルマネージド型であることです。このフルマネージド型という特徴は、Amazon RDSから始まり、現在のAuroraに至るまでの重要な要素です。マイクロサービスへの移行において特に重要な点は、より多くのデータベースを扱うことになるということです。

Thumbnail 1470

Thumbnail 1490

Thumbnail 1500

アーキテクチャの詳細を見ていきましょう。Auroraの特徴と、皆様にとってより良いと思われる点について説明します。まず、ストレージから始めましょう。青い線は、データベース用の仮想ボリュームを表しており、3つのアベイラビリティーゾーンにまたがっています。これは耐久性のためです。黄色のボックスはストレージサーバーです。図では9つしか表示していませんが、実際には特定のリージョンで数千から数万存在する可能性があります。ストレージクラスターに対する最初のデータベースインスタンスがあり、これがほとんどのアプリケーションで使用するものです。最初の違いは、ブロックではなくログレコードを書き込むということです。これには多くの利点があります。チェックポインティングを行う必要がなく、ヘッドノードでの作業が大幅に減少し、6箇所に書き込みを行います。

Thumbnail 1540

チェックポインティングを実装するために、ヘッドノードでの作業を大幅に削減しています。この6箇所の書き込みは小さな輪で表されており、それぞれがストレージ内の10GBの組織単位です。コミットの確認を受けるには、これら6つの書き込みのうち4つが完了する必要があります。実際には、コミット前に先に進むことができるため、書き込みを待つ必要はありません。これにより、完全な耐久性を維持しながら、優れたパフォーマンスを実現しています。

Thumbnail 1550

Thumbnail 1570

Thumbnail 1580

シンプルさを保ち、優れたオープンソースシステムのコードへの変更を最小限に抑えるため、ブロックを読み戻します。ログから変更を適用し、読み取りが必要な場合にブロックを送り返します。これにより、データベースはシンプルで信頼性の高いものとなります。時には、その小さな赤い丸で示されているように、書き込みが失敗することもあります。バックグラウンドで広範なクリーニングとテストを行い、すべてのデータが揃っていることを確認します。書き込みが失われた場合、ピアの1つがピアツーピアレプリケーションを実行して修正します。ストレージユニットに障害が発生した場合、新しいストレージユニットに自動的に新しいコピーをレプリケートします。これらはすべてバックグラウンドで行われ、お客様の操作は一切必要ありません。

Thumbnail 1590

Thumbnail 1620

もう1つの大きな差別化要因は、Read-onlyノードです。これは読み取りのスケーラビリティを大幅に向上させることができ、しかも各ノードに追加のストレージを購入する必要がありません。 これにより大幅なコスト削減が可能で、リージョン内で最大15個まで、お好みの構成で設置できます。ご覧のように、私の環境では各ノードで異なるインスタンスタイプを使用しており、片方でGraviton、中央でIntel、そしてServerlessを使用しています。サイズや構成は自由に組み合わせることができます。これにより、例えばIntelからGravitonへの切り替えなど、プラットフォーム間の移行テストを、単純にフェイルオーバーを行うだけで実施できる優れた方法を提供しています。

Thumbnail 1640

管理性に優れたもう1つの特徴は、使用量に応じて拡大縮小するストレージシステムです。従来のファイルシステムとは異なり、容量不足を避けるために余分なストレージを確保しておく必要がありません。中央のAvailability Zoneで DBインスタンスに障害が発生した場合、1分以内にRead-onlyノードの1つにフェイルオーバーします。完全な耐久性を保ったまま運用を再開でき、ラッパードライバーを使用することで、その多くがDNS伝播時間であるこの切り替え時間をさらに短縮することができます。

Thumbnail 1660

Thumbnail 1670

Thumbnail 1690

Thumbnail 1700

このアーキテクチャにより、リージョン間の災害対策を提供するGlobal Databaseのような強力な機能を実装することができます。他のリージョンにボリュームを作成し、レプリケーションサーバーとエージェントを介して、ストレージベースのレプリケーションを開始します。反対側にインスタンスを用意する必要がないため、使用していないリソースに対する支払いは発生しません。書き込みを実行すると、Read-onlyノードが更新され、ローカルストレージに書き込まれ、その後レプリケーションサーバーがエージェントに転送し、最終的に反対側のストレージに書き込まれます。この時点で災害対策の観点からカバーされており、システムコストを2倍にすることなく、経営陣のDR要件を満たすことができます。

Thumbnail 1740

Thumbnail 1750

Thumbnail 1760

クエリのチューニングとパフォーマンス最適化については、AuroraにはPerformance Insightsがあります。これはRDSとAuroraで利用可能な機能で、データベースとクエリのパフォーマンスを可視化できます。緑色のボックスはCPU使用率を表しており、ご覧のように、ある時点でCPU使用率が100%まで急上昇しています。これはアプリケーションのパフォーマンスとしては理想的ではありません。これを詳しく調べることで、具体的にどのクエリに問題があるのかを特定できます。何が変化したのかを理解するために、問題が発生する数分前の期間を確認すると、CPU使用率がはるかに低かったことがわかります。

Thumbnail 1780

Thumbnail 1790

クエリプランを見ると、以前はビットマップとネステッドループを使用していましたが、現在はハッシュ結合やシーケンシャルスキャンといった、はるかにコストの高い非効率な方法を使用していることがわかります。このようなプランの変更は、統計情報の変更、分析の不足、設定の変更、またはインデックスの変更によって発生する可能性があります。私の場合は、2つのプランナー機能を無効にしたことが原因でしたが、これは実運用では推奨されません。このような場合に役立つのが、先ほどNarayananが説明したQuery Plan Management(QPM)で、これによってプランの安定性を確保することができます。

Thumbnail 1810

Thumbnail 1820

Thumbnail 1830

Thumbnail 1840

QPMはプランの安定性を重視して設計されています。ステートメントをキャプチャする際、2つの異なるクエリ(Query AとQuery B)とそれぞれのプランを観察します。これらのプランが良好だと判断して承認すると、それがベースラインとして確立されます。つまり、これらのプランが今後使用されることになります。プランナーが別のプランを生成しても、そのプランは使用されませんが、保持はされます。もしそのプランの3番目のバージョンが登場し、データ量の変化などにより、より優れていることが証明された場合、それらのプランを比較して、そのプランをアクティブなプランに昇格させるようにシステムを進化させることができます。これは一度きりの静的なプロセスではありません。システムを進化させることもできますし、必要がなければ既存のプランを維持することもできます。

Thumbnail 1850

Thumbnail 1860

この機能は特に、多数のシステムを持っていて、プランの変更について心配したくない場合に重要です。私がQPMを有効にしたとき、安定したプランは一貫性を保ち続けました。インスタンスレベルでプランナーの設定が無効になっていても、すべてが効果的に動作し続けます。Intuitからのリクエストの一環として実装した改良の1つは、この機能をRead-Onlyノードにも拡張したことです。当初はRead-Writeノードに限定されていましたが、Read-Onlyノードでも機能するのは当然のことでした。

Thumbnail 1880

Thumbnail 1900

また、多くのユーザーのパフォーマンスとコストパフォーマンスを向上させるための素晴らしい機能も実装しました。その中には、ストレージからの大量の読み取りが必要な状況に対応するTiered Cacheが含まれています。大きなワーキングセットサイズを持ち、より高速な読み取りが必要な場合、PostgreSQLは通常、ブロックがShared Buffersにあれば、そこから読み取って素早く応答します。もしそこになければ、ストレージから読み取りますが、これには時間がかかります。時々のストレージ読み取りは許容できますが、頻繁な読み取りはアプリケーションのパフォーマンスに影響を与える可能性があります。

Thumbnail 1910

この課題に対処するため、I/O最適化されたストレージを使用する際のTiered Cacheオプションを提供するようになりました。Aurora バージョン14.9+、15.3+、または16で、R6GDまたはR6IDの異なるインスタンスタイプを注文するだけです。このストレージの一部をSpillなどの一時オブジェクトのキャッシングに使用し、メモリより大きなデータを扱う際のソートを高速化します。主なユースケースは、メインメモリの4倍のサイズを持つTiered Cacheです。

Thumbnail 1940

Thumbnail 1970

実装方法は次のとおりです:Shared Buffersの一部をメタデータとして使用し、読み取りを実行する前にこのメタデータをチェックします。データがキャッシュにない場合、Tiered Cacheに触れることなくブロックをキャッシュに読み込み、読み取りパスをシンプルに保ちます。ブロックの読み取りを停止してShared Buffersから排出される際、通常の処理に影響を与えることなく非同期でTiered Cacheに移動し、メタデータを更新してTiered Cache内の位置を追跡します。

Thumbnail 2000

このようなシステムにおける主な課題は、通常、チェックポイントを伴う階層型キャッシュの更新に関連しており、エージングやその他のプロセスにより複雑になる可能性があります。しかし、Auroraは従来のチェックポイントを使用しないため、この問題を回避できます。更新の無効化については、単にメタデータを無効化するだけでよく、階層型キャッシュに触れる必要はありません。これによりキャッシュへの過剰な書き込みを防ぎ、NVMeストレージの消耗を抑えることができ、非常に効率的な運用が可能になります。

モノリスからマイクロサービスへ:段階的な移行アプローチ

Thumbnail 2020

Sysbenchを使用したパフォーマンスの違いを見てみましょう。ここでは、読み取り専用のポイントセレクトを均一分布で実行します。これは標準的なSysbench設定とは異なり、少数のブロックに集中せず、すべてのブロックを読み取ることを確実にします。Extra Largeインスタンス4台を使用した場合、作業セットのサイズは約85ギガバイトで、メモリに完全に収まります。階層型キャッシュを使用する場合でも通常の設定でも、すべてがShared Buffersから取得されるため、同じ結果が得られ、非常に高速な読み取りで約0.23ミリ秒を達成します。

Thumbnail 2060

Thumbnail 2080

しかし、作業セットのサイズを4倍の300ギガバイト以上に増やすと、ストレージレベルのレイテンシーが発生し始めます。まだある程度のキャッシングは行われていますが、ほとんどの読み取りはストレージから行われ、その結果、レイテンシーは4倍に増加します。この時点で、いくつかの選択肢があります。16 XLインスタンスにアップグレードすることもできますが、経営陣は喜ばないかもしれません。あるいは、パフォーマンスの低下を受け入れるか、クエリを書き直すという選択肢もあります。クエリの書き直しは多くの場合最良の解決策ですが、必ずしも実現可能とは限りません。

Thumbnail 2100

階層型キャッシュを導入することで、NVMeが加わります。紫色の線がNVMeクエリを表しており、一部のデータはメモリから、残りはNVMeストレージから取得されていることを示しています。

データの一部がメモリから、残りがNVMeから取得されているのが分かります。NVMeはRAMの4倍のサイズがあるため、すべてのデータが収まります。レイテンシーは50%増加しただけで、これは若干の上昇ですが、アプリケーションが気付くほどの差ではないでしょう。この技術を使用することで、既存のシステムを大幅に高速化するか、CPUをそれほど必要としない場合は、より小さなシステムに移行してコストを削減することができます。これは、モノリスを分割して多数のデータベースを運用する際の管理性において、非常に有益です。

Thumbnail 2140

モノリスを分割する例について、もう一度見ていきましょう。まず、比較的小規模なサプライヤーデータベースがあります。最初にすべきことは、セキュリティの観点から、権限設定とアカウントの使用状況を変更して、本当に分離されているかを確認することです。移行してから誰かがそのデータベースに依存していたことが判明するのは避けたいですからね。そのため、サプライヤーだけがこのデータベースを使用していることを確認することが重要です。確認が済めば移行できますが、このデータベースは週5日間頻繁に使用されているものの、サイズは小さいため、独立したデータベースに移行するのはコストがかかりすぎるように思えます。

Thumbnail 2180

Thumbnail 2200

Thumbnail 2220

ここで活躍するのが Amazon Aurora Serverless です。これは従量課金制のシステムで、単なるインスタンスタイプの一つです。R6iの代わりにDB.serverlessを選ぶだけです。 CPUとメモリの両方を1秒単位でスケールアップ・ダウンできます。特にメモリのスケーリングは非常にクールな技術で、私たちは多くの時間をかけて開発しました。しかも、スケーリング中もパフォーマンスに影響はありません。 先ほど述べたように、使用量に応じた課金です。ここではAWS Lambdaを例に挙げていますが、LambdaとServerlessは相性が良いとはいえ、通常のアプリケーションでも問題ありません。Lambdaが起動する時は少量のメモリとCPUから始まりますが、必要に応じてCPUとメモリを追加していき、かなりの量まで拡張できます。現在では256 ACUまで拡張可能で、これは16XLに相当する大きさです。

Thumbnail 2240

Thumbnail 2250

Thumbnail 2260

使用していない時は縮小し、最近導入されたServerlessのゼロスケーリング機能を使えば、このアプリケーションの場合、週末は誰も使用しないためデータベースを完全にシャットダウンしてさらなるコスト削減が可能です。このコスト効率の良いソリューションを手に入れたので、次はIntuitが行ったのと似たような手法を使います。 まず、Serverlessデータベースを起動し、AWS Database Migration Service(AWS DMS)を使用して、サプライヤーデータのレプリケーションを開始します。 データベースが完全に同期されたら、更新を停止します。新しいサプライヤーアプリケーションを起動しますが、DMSを使って元のデータベースへのレプリケーションも設定していることに注目してください。これは、新しいアプリケーションコードに問題が発生した場合に備えたフォールバック用です。問題がなければ、しばらくしてからこのレプリケーションを削除し、モノリスからデータを削除できます。

Thumbnail 2280

Thumbnail 2300

Thumbnail 2310

ここまでは比較的明確でしたが、次はより複雑なシナリオ、つまり絡み合ったソリューションについて見ていきましょう。サプライヤーアプリケーションと、おそらくカスタマーアプリケーションも移行したいと考えています。 まず、先ほどと同じようにセキュリティ分析を行って、誰が何を使用しているかを把握します。すると、配送アプリケーションはカスタマーデータを読み取り専用で使用していることがわかります。 注文アプリケーションも同様で、顧客情報の読み取りだけを行い、実際には修正を行っていません。配送データについても同じことが言えます。注文アプリケーションは単に配送状況を確認しているだけです。

Thumbnail 2330

Thumbnail 2340

これらのアプリケーションは絡み合っているものの、読み取り専用のレベルであることがわかりました。そこで、ここではServerlessを例に示していますが、Provisionedインスタンスでも構いませんが、カスタマーと配送用の新しいデータベースとDMSをセットアップします。先ほどと同様に、これらのデータベースへのレプリケーションを行います。 次に、これらのアプリケーション用に新しいアプリケーションをセットアップします。配送には顧客データが必要でしたが、直接データにアクセスするのではなく、Microservicesを簡素化して分離するために、新しいアプリケーションを通じてアクセスするようにします。

Thumbnail 2370

ここまでは順調に進んでいますが、ここで問題が発生します。あのOrderingアプリはどうなるのでしょうか?まだテーブルにアクセスする必要がありますよね。同時に移行しなければならないのでしょうか?それは少し大変そうです。いいえ、その必要はありません - Orderingデータベースのリファクタリングに取り組むまでの間、 Monolithデータベースに対して逆方向のレプリケーションを設定し、新しいデータベースからの長期的なレプリケーションを維持することができます。リファクタリングが完了すれば、この接続を切ることができますが、それまではこの方法で段階的な移行が可能です。20や30のコンポーネントがある場合を想像してみてください - 昔のAmazonでは、1つのデータベースに30から40以上のものが入っていて、かなり混沌としていました。多くのものを分離する必要があり、何年もかかるような大規模な移行は避けたかったので、この手法を広く活用しました。

Thumbnail 2400

まだOrderingデータベースと時系列データに関する課題が残っています。

Thumbnail 2420

Thumbnail 2430

Thumbnail 2440

そこで、Intuitが時系列データに対して行ったのと同様のアプローチを取ることにします。 古いデータの保存にはAmazon S3を使用します。過去1年分の注文データを1つのS3アイテムにまとめます。 これには、クエリに必要な注文項目の詳細情報がすべて含まれます。そして、アプリケーションを書き換えて、S3に対してクエリを実行するようにします。 S3はAuroraへの読み取りと比べてレイテンシーが高くなりますが、データベースから何千回もブロックを取得する往復通信ではなく、S3への1回の呼び出しで済むことを覚えておいてください。これは実際、アプリケーション側でもデータベース側でもはるかに効率的になる可能性があります。

Thumbnail 2460

Thumbnail 2480

これを実施すれば、データベースからそれらのデータを削除でき、データベースはより小さく、効率的で、コスト効果の高いものになります。これは、Monolithを分割する際の重要な検討事項の1つです。つまり、もはや書き込みが行われず、読み取り専用となったデータをどのように異なる方法で扱えるかを考えることです。 ここまでかなり良い成果を上げていますが、まだOrderingデータベースが残っており、これが急速に成長しています。このままで収まるのかどうか心配になってきました。

Thumbnail 2490

Thumbnail 2510

Thumbnail 2520

Thumbnail 2530

Thumbnail 2540

そこでShardingモデルに移行することにします。AWS Database Migration Serviceなどを使用して、データを複数のShardにレプリケートすることができます。これは良い方法ですが、Ryanが言っていたように、多くのShardの管理は複雑になる可能性があります。少なくともスケールは確保できましたが、管理の負担は増えています。 その負担の1つがRe-shardingです。最初のShardingを行う際、通常は推測で、 4〜5個のShardが適切だろうと考えます。 これ以上必要にならないだろうと思うかもしれませんが、もちろん成長は続き、Re-shardingが必要になります。これは予想以上に頻繁に起こります。なぜなら、人々の時間的な展望は数年程度だからです。私はAmazonに25年いますが、始めた当時に選んだ数字はおそらく間違っていたでしょう。

Thumbnail 2550

Thumbnail 2560

Thumbnail 2570

Shardingにおけるもう一つの課題が一貫性です。これらのShardに新しいカラムを追加する際には、すべてのShardで正しく実行され、アプリケーションがこれらの変更をロールアウトする間も適切に処理できることを確認する必要があります。現時点でのオープンオーダーの数を集計するような処理を行う場合、各Shardでの実行タイミングがわずかにずれるため、若干の不整合が生じます。それが許容できる場合もありますが、認識しておくべき課題です。バックアップは恐らく最も大きな課題の一つで、Shard間でトランザクションを実行している場合、リストア時にその時間境界をまたぐShard間トランザクションが破綻する可能性があります。

Thumbnail 2590

Thumbnail 2600

これはかなり複雑です。キャパシティ管理も別の課題となります。単一の大規模データベースであれば、負荷管理の観点からは簡単です - 1日の最大負荷に対応できるようにサーバーのサイズを確保すればよいのです。しかし、小さなShardに分割すると、顧客の行動に応じて負荷が移動するのが一般的です。朝にホットだったものが午後には冷えている、またはその逆というケースです。結局はShardをスケールアップすることになり、多数のShardがあるため、すべてのShardで無駄なスペースが増えることによってコストが実際にはかなり高くなる可能性があります。

Thumbnail 2620

Thumbnail 2640

Thumbnail 2650

この課題に対する私たちの答えが、Aurora Limitless Databaseです。これは私たちのShardingソリューションです。通常通りAmazon Auroraクラスターを注文しますが、インスタンスの代わりにデータベースShardグループを作成します。これにより、接続先となる分散トランザクションルーターレイヤーが提供されます。名前が示す通り、このレイヤーはトランザクションとルーティングを処理します。接続は通常クラスターで使用するCNAMEを通じてこのルーティングレイヤーに行われます。そのため、アプリケーションから見ると何も変わらず、このルーティングレイヤーが各Shardにクエリを振り分けて結果を返します。

Thumbnail 2670

Thumbnail 2680

このシステムは非常に優れたスケーラビリティを持っています。私たちのベンチマークでは、200万トランザクション/秒以上という印象的な性能を達成しています。ホットShardが発生した場合、自動的にRe-shardingを実行することもできますし、手動でSplit実行のタイミングを決めることもできます。これらのデータShardとルーターには、Aurora Limitlessが持つServerless機能を活用しています。1日の中で負荷が上下する場合でも、256 ACUまでスケール可能なため、30〜40%の増減であればRe-shardingを行う必要はありません。システム全体でグローバルクロックを使用しているため、クエリとDDLの一貫性のあるバックアップが可能です。DDLを発行すると、実際にはすべてのノードに送信され、1つの分散トランザクションとして実行されるため、おかしな結果を心配する必要はありません。バックアップを要求した場合も同様です。

Thumbnail 2710

Thumbnail 2720

すべてのトランザクションが完全に正確になります。これにより多くの作業が簡素化され、アプリケーションの変更も最小限で済みます。今では注文アプリケーションをAurora Limitless Databaseに移行しましたが、多数のShardを管理する必要がなくなり、よりシンプルになったと思いませんか?

Zero-ETL統合とAurora Limitless Database:次世代のデータ管理ソリューション

Thumbnail 2730

Thumbnail 2740

Thumbnail 2750

私たちのジャーニーは順調に進んでいます。注文システムが完成し、顧客システムも完成し、配送システムも完成し、そしてサプライヤーアプリケーションも完成しました。でも、分析についてはどうでしょうか?以前、分析のためのシンプルで優れたソリューションがありましたよね。これをどうすればいいでしょうか?通常、分析を行う場合、一方にOLTP用のリレーショナルデータベースがあり、もう一方にデータウェアハウジング用のAmazon Redshiftのようなものがあります。

Thumbnail 2770

そのデータを連携させるには、通常データパイプラインを構築する必要があります。AWS Database Migration Service、Amazon S3、その他様々なAWSサービスが関係してくるかもしれません。おそらくデータエンジニアがそれを担当し、常に正常に動作していることを監視する必要があります。これは機能しますが、複雑です。そこで私たちはこれを簡素化したいと考え、それがRyanが先ほど言及したzero-ETL統合です。Amazon AuroraインスタンスからAmazon Redshiftへのzero-ETL統合を設定するだけで完了です。ロードと管理はすべて私たちが処理します。私がテストした際には、約5〜10秒のラグで動作していたので、実質的にリアルタイムと言えます。実際にリアルタイムダッシュボードを作成することができます。

Thumbnail 2800

Thumbnail 2810

どのようにしてその速度を実現しているのでしょうか?このレプリケーションではストレージレベルでの処理を行っています。ヘッドノードに影響を与えないだけでなく、非常に高速で効率的です。Amazon Redshiftへの並列ダイレクトエクスポートを行っています。Change Data Capture(CDC)についても、ヘッドノードではなくストレージから実行します。そしてそれをAmazon Redshiftにストリーミングします。これらすべてが非常に効率的で高速です。

Thumbnail 2820

これで私たちのすべてのプロパティが揃い、zero-ETLを設定しました。注目すべき点は、最大50個のデータベースから単一のAmazon Redshiftクラスターにzero-ETL接続を設定できることです。それぞれに個別のRedshiftクラスターを用意する必要はありません。私たちはシステムを簡素化しました - 確かに最初よりもデータベースの数は増えましたが、すべて適切に管理されたシステム上で動作しており、管理の大部分はAurora側で行われています。これは、マイクロサービスのコントロールを得て、モノリスの問題を解消しつつ、注意を怠るとなりがちな過度なマイクロサービスの乱立を避けることができる、良いモデルだと言えます。

Thumbnail 2860

関連セッションをいくつかご紹介します。今年は素晴らしい取り組みをしており、動画が非常に早くアップロードされています。例えば、最初の2つは私が行った講演で、既に動画が視聴可能です。他のものもまだアップされていない場合は、まもなくアップロードされる予定です。ぜひご覧いただき、アンケートへのご協力もお願いいたします。


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

Discussion