
Fintech
イベント
マガジン
技術ブログ
本記事は 2026 年 5 月 5 日 に公開された「 Amazon Aurora DSQL for global-scale financial transactions 」を翻訳したものです。 Amazon Aurora DSQL を使えば、強い整合性と低レイテンシーを両立しながら、複数の AWS リージョンにまたがるグローバル規模の金融トランザクションを実行できます。従来はこの選択にコストが伴いました。夜間のリコンシリエーションバッチ、手動フェイルオーバー手順、顧客残高や決済を扱うシステムでの短時間のデータ不整合リスクなどです。Amazon Aurora DSQL はグローバルに整合性のある強い耐久性を持つトランザクションを、アクティブ-アクティブの可用性とサーバーレス運用で提供し、従来のトレードオフを解消します。 本記事ではまず、分散整合性に対する従来のアプローチが金融ワークロードで不十分な理由を検証します。次に Amazon Aurora DSQL のアーキテクチャが分散整合性の課題にどう対処するかを説明し、3 つの本番ユースケース (勘定系、グローバル支出管理、デジタル通貨インフラストラクチャ) に適用します。最後に実装上の考慮事項と、 Amazon Aurora DSQL 無料利用枠 での始め方を紹介します。 金融サービスデータベースに求められる要件の変化 金融データベースには常に整合性と可用性が求められてきました。変わったのは運用環境です。10 年前、トランザクション処理のほとんどはリージョナルでした。銀行の中央台帳は 1 つのデータセンターで稼働し、トレーディングシステムは単一の取引所に対応し、日次バッチによる突合処理は当たり前のものとして受け入れられていました。現在、顧客は地理的に分散した拠点間でのリアルタイムな可視性を求め、規制当局は取引報告の期限を厳格化し、マルチリージョンでの可用性はもはや付加価値ではなく競争上の必須要件となっています。 よくあるシナリオで課題を説明します。あるリージョンの口座から引き落とし、別のリージョンの口座に入金する処理を、単一のトランザクションで実行する必要があります。従来の解決策は 2 フェーズコミット (2PC) で、コーディネーターノードが各参加者から合意を集めてからコミットします。動作はしますが、コーディネーターが単一障害点となり、ラウンドトリップ全体にわたってロックを保持し、部分的な障害にはテストが困難で運用コストの高いリカバリロジックが必要です。リージョン間ではコーディネーターのラウンドトリップに数百ミリ秒が加わり、クロスリージョントランザクション中のロック競合が最も重要なタイミングでスループットを制限する可能性があります。 多くのチームが代替手段として選ぶのは、非同期レプリケーションによる結果整合性、競合解決を伴うマルチプライマリ構成、あるいは専用の分散データストアです。これにより 2PC の調整負荷は回避できますが、その負担はアプリケーション開発者にのしかかります。共有状態を扱うサービスすべてに冪等性、競合解決、突合ロジックを実装しなければなりません。一時的な不整合を許容し、それを運用リスクモデルに織り込むチームもあります。分析やキャッシュのワークロードでは合理的なトレードオフですが、顧客残高、決済、取引を直接扱う場合には正当化が難しくなります。 Amazon Aurora DSQL はこの 2 つのアプローチの間を埋めます。2PC の調整負荷なしに強い整合性を提供し、結果整合性の突合負債も発生しません。 Amazon Aurora DSQL のアーキテクチャと金融サービスへの意義 Amazon Aurora ストレージエンジンの利点を、AWS リージョン間の分散運用向けに拡張した形で利用できます。 Amazon Aurora DSQL の紹介 でアーキテクチャの詳細を解説しています。ここでは金融サービスワークロードで最も重要な特性に焦点を当てます。 アクティブ-アクティブのマルチリージョン設計です。クラスターをデプロイした全リージョンで読み書きが可能です。各リージョンのノードは対等なピアとしてトランザクションを受け付け、書き込みトランザクションはリージョン間およびウィットネスリージョンに同期レプリケートされます。 ウィットネスリージョン は、軽量かつ中立的な第三の拠点で、コミットの判定に参加することで 3 拠点間のクォーラム(多数決)を維持し、トランザクションの永続性を確認します。クォーラムには 3 つの参加者のうち少なくとも 2 つの合意が必要なため、3 リージョンが必要です。2 つのアクティブリージョンのうち 1 つが停止しても、残りのアクティブリージョンとウィットネスリージョンで過半数を構成できるため、中断やデータ損失なくトランザクションのコミットが継続されます。もしウィットネスなしの 2 リージョン構成だったら、1 リージョンが失われた時点で、処理中のトランザクションがコミットされたのかどうかすら確認できなくなります。 マルチリージョンクラスターにより、データベースレイヤーで最大 99.999% の可用性を実現します。マルチリージョン運用を必要とするレジリエンス戦略において、手動フェイルオーバー、プライマリ/セカンダリの調整、フェイルオーバー後のデータ突合の構築・維持が不要になります。これは、各リージョンで独立して動作するアクティブ-アクティブのアプリケーション層と組み合わせると最も効果的で、スタック全体がすべてのレイヤーで集中的な調整なしにリージョン障害を吸収できるようになります。 サーバーレスで運用・スケーリング。キャパシティプランニング、レプリカ管理、シャーディング戦略の設計は不要です。コンピュート、コミット、ストレージの各レイヤーが独立して自動的にスケールします。Amazon Aurora DSQL は消費したコンピュートと I/O に対して課金されます。マーケットオープンや四半期末のスパイク時に使用した分だけ支払い、閑散期のアイドルには課金されません。予測困難な需要パターンを持つ金融ワークロードでは、従来のプロビジョニング型データベースアーキテクチャと比較して大幅なコスト削減が見込めます。 整合性モデル。トランザクションは最寄りのリージョンでローカルに実行され、Amazon Aurora DSQL は変更を伴うトランザクションのコミット時にのみリージョン間で調整します。整合性モデルはスナップショット分離を伴う楽観的同時実行制御 (OCC) で、トランザクション実行中にロックを保持しません。読み取り専用トランザクションはローカルのレイテンシーで完了し、リージョン間調整なしに一貫性のあるスナップショットを参照できます。書き込みトランザクションはコミット時にのみクロスリージョン調整コストが発生するため、調整ウィンドウは最小限に抑えています。 代わりに、各トランザクションはデータの一貫したスナップショットに対して動作し、Amazon Aurora DSQL はコミット時にのみ競合をチェックします。2 つのトランザクションが同じ行を変更した場合、一方が正常にコミットされ、もう一方はシリアライゼーションエラーとなり、アプリケーション側でリトライします。 この特性は以降のユースケースで重要です。通常は異なる行 (異なる口座、異なる取引) に触れるワークロードでは、競合は最小限です。同じ行を頻繁に更新するワークロードでは、カウンターをインプレースで更新するのではなく新しい行を追加するなど、行レベルの競合を減らすスキーマ設計が有効です。 Amazon Aurora DSQL のドキュメント で OCC 向けスキーマパターンの詳細なガイダンスを提供しています。 PostgreSQL 互換性。PostgreSQL を使用しているチームは、既存の SQL 構文、ドライバー、クライアントライブラリを Amazon Aurora DSQL でそのまま使用できます。本記事の例では馴染みのある PostgreSQL パターンを使用しており、既存のリレーショナルスキーマを最小限の変更で移行できます。Amazon Aurora DSQL が現在サポートしていない PostgreSQL 機能については、 Amazon Aurora DSQL の使用に関する考慮事項 を参照してください。 金融サービスのユースケース 以下のユースケースに共通するテーマは、複雑なマルチデータベースアーキテクチャを単一のグローバルに整合性のあるデータレイヤーに置き換え、突合プロセスや手動フェイルオーバー手順を排除する点です。異なるのは具体的な運用コンテキストと規制上の要件です。 勘定系と台帳の整合性 勘定系アプリケーションは、顧客口座、残高、トランザクションの正確なリアルタイム台帳を管理します。地理的に分散して運用する大規模銀行は、従来はリージョンごとに別々の勘定系を運用するか、バッチ処理でデータを同期していました。 これには 2 つの問題があります。プライマリリージョンがダウンすると、トランザクション処理が停止するか、データ損失を伴うフェイルオーバーが発生します。通常運用時でも、あるリージョンでの残高クエリが別のリージョンで処理された最近のトランザクションを反映していない場合があります。規制当局と顧客は、リージョン間での継続的な可用性とリアルタイムの正確性を期待しています。 Amazon Aurora DSQL は、各支店やリージョンのアプリケーションがローカルエンドポイントに読み書きを行い、更新は全リージョンに自動伝播することで、この問題を解決します。米国東部 (オハイオ) で処理された入金は、米国西部 (オレゴン) から照会する窓口担当者にも即座に表示されます。あるリージョンが利用不能になっても、残りのリージョンはデータ損失も手動フェイルオーバーもなくトランザクション処理を継続します。データベースが単一のグローバルに整合性のある状態を提供するため、システム間の突合なしに全リージョンから規制報告を作成できます。 具体例として、2 つの口座間の資金移動を考えます。従来のマルチリージョンアーキテクチャでは、リージョナルデータベース間の部分的な障害に対処するために、Saga パターン、メッセージキュー、補償トランザクションが必要になる場合があります。Amazon Aurora DSQL では単一の ACID (原子性、整合性、分離性、耐久性) トランザクションに簡素化できます。 以下のスキーマは、Amazon Aurora DSQL の分散アーキテクチャ向けに最適化されたいくつかの設計選択を示しています。UUID 主キーはリージョン間でのシーケンシャル ID の調整負荷を回避します。CHECK 制約はアプリケーションコードではなくデータベースレベルでビジネスルールを適用します。TIMESTAMPTZ 列はどのリージョンがトランザクションを処理しても一貫したタイムスタンプを提供します。これらの例ではわかりやすさのためにリテラル値を使用しています。本番環境では SQL インジェクションを防ぐため、データベースドライバーを通じたパラメータ化クエリを必ず使用してください。アプリケーションコードで送金開始前に十分な残高があることを検証する必要があります。以下の SQL は Amazon Aurora DSQL playground でインタラクティブに実行できます。 -- Schema: simplified core banking ledger CREATE TABLE accounts ( account_id UUID PRIMARY KEY, customer_id UUID NOT NULL, balance NUMERIC(18,2) NOT NULL CHECK (balance >= 0), currency VARCHAR(3) NOT NULL, updated_at TIMESTAMPTZ DEFAULT NOW() ); CREATE TABLE transactions ( transaction_id UUID PRIMARY KEY DEFAULT gen_random_uuid(), from_account UUID NOT NULL, to_account UUID NOT NULL, amount NUMERIC(18,2) NOT NULL, description TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Funds transfer as a single ACID transaction BEGIN; UPDATE accounts SET balance = balance - 500.00, updated_at = NOW() WHERE account_id = 'acct-1234' AND balance >= 500.00; UPDATE accounts SET balance = balance + 500.00, updated_at = NOW() WHERE account_id = 'acct-5678'; INSERT INTO transactions (from_account, to_account, amount, description) VALUES ('acct-1234', 'acct-5678', 500.00, 'Funds transfer'); COMMIT; 口座の更新と取引き録は、アプリケーションがどのリージョンに接続していても原子的にコミットされます。送金元の残高が不足している場合、CHECK 制約で弾かれトランザクション全体がロールバックされます。片方の口座だけが引き落とされ、もう片方に入金されていない、そんな中間状態は起こりません。Saga オーケストレーション、補償トランザクション、夜間の突合バッチは不要です。 振替は通常、異なる口座行を操作するので、異なる口座に対する並行トランザクションは Amazon Aurora DSQL の楽観的同時実行モデルで競合なくコミットされます。まれに 2 つのトランザクションが同時に同じ口座を対象とするケースでは、OCC がコミット時に競合を検出し、一方のトランザクションがリトライされます。アプリケーション側でロックを取る必要はなく、整合性は保たれます。 グローバル支出管理と法人カードシステム 現代の支出管理サービスは、世界中の数千の企業のあらゆる金融取引を承認・追跡する集中的な意思決定レイヤーとして機能します。カードの利用、ACH (Automated Clearing House) 送金、電信送金、経費精算のいずれも、残高、与信限度額、加盟店管理、リスクスコア、会計マッピングに対する複数のトランザクション更新を発生させます。これらの操作は異なるロケーションから数秒以内に発生することが多く、わずかな不整合 (例: 承認判定に対して残高更新が遅れる) でも取引の拒否、過剰支出、不正リスクの露出につながります。 Amazon Aurora DSQL を使えば、リージョン間で単一のグローバルに整合性のある台帳を維持できます。各リージョンがローカルで書き込みを受け付け、同じグローバルに整合性のあるトランザクションセットの一部としてコミットします。これは、異なるリージョンにデプロイされた複数の決済プロセッサーや銀行パートナーと連携する場合に特に有用です。最大の価値は、統合された台帳と突合レイヤーにあり、リージョナルデータベース間のバッチ同期なしにグローバルに整合性のある残高ビュー、支出管理、会計記録を維持できます。 デジタル通貨インフラストラクチャ グローバルなデジタル通貨発行体は、複数のリージョン、ブロックチェーン、銀行パートナーにまたがる発行、償還、送金、決済をサポートする常時稼働サービスを運用しています。これらのサービスは、トークン供給量、顧客残高、取引状態を正確に追跡するリアルタイム台帳の維持が不可欠です。発行(ミント)、焼却(バーン)、送金イベントを取引所、決済プロセッサー、銀行パートナーの近くでローカルに処理でき、Amazon Aurora DSQL がそれらを原子的にコミットしてグローバルに可視化します。流通供給量、顧客残高、取引履歴はリージョン間で継続的に同期されます。 AWS 無料利用枠で始める 永続的な AWS 無料利用枠 と、分散データベース設計の専門知識がなくても開発を加速する AI スキルを利用できます。無料利用枠には毎月 100,000 Database Processing Units (DPU) と 1 GB のストレージが無料で含まれ、開発環境の運用や小規模アプリケーションのサポートに十分な容量です。 Amazon Aurora DSQL AI スキル は、分散ワークロード向けのスキーマ設計、外部キーなしの参照整合性、初日から本番対応のアプリケーション構築を支援します。Kiro や Claude Code などの AI コーディングツールと連携し、分散トランザクション向けに最適化されたスキーマ設計、レジリエントなマルチリージョンアプリケーションアーキテクチャの構築、既存の PostgreSQL ワークロードの Amazon Aurora DSQL への移行などのタスクについてインタラクティブなガイダンスを提供します。 Amazon Aurora DSQL スキルの全セットについては、 Amazon Aurora DSQL ステアリングガイド を参照してください。 まとめ 本記事では、Amazon Aurora DSQL がグローバルに分散した ACID トランザクション、最大 99.999% の稼働率を持つアクティブ-アクティブの可用性、サーバーレス運用を単一のマネージドサービスで実現する方法を紹介しました。2 フェーズコミットと結果整合性の限界にアーキテクチャがどう対処するかを説明し、金融サービスチームが構築する 3 つの本番パターン (原子的なクロスリージョン送金を行うコアバンキング台帳、グローバルに整合性のある経費管理システム、リージョン間で流通供給量と残高を同期するデジタル通貨プラットフォーム) に適用しました。 実際に試すには、 Amazon Aurora DSQL サービスページ から無料利用枠クラスターを作成し、 開発者ガイド で接続設定、クエリパターン、スキーマ設計を確認してください。アーキテクチャの詳細や機能比較については Amazon Aurora DSQL のドキュメント を参照し、移行のビジネスケース構築については AWS アカウントチームにご相談ください。 著者について Trevor Spires Trevor は、AWS の金融サービス担当シニアソリューションアーキテクトです。キャピタルマーケットおよびフィンテックのお客様と密接に連携し、コアインフラストラクチャと AI システムのクラウドでのスケーリングとセキュリティ確保を支援しています。 Raluca Constantin Raluca は、Amazon Aurora DSQL を専門とする AWS のシニアデータベースエンジニアです。Oracle、MySQL、PostgreSQL、クラウドネイティブソリューションにわたる 18 年のデータベース経験を持ち、データベースのスケーラビリティ、パフォーマンス、リアルタイムデータ処理に注力しています。 Jigna Gandhi Jigna は、AWS の金融サービス担当シニアソリューションアーキテクトです。フィンテック、Web3、銀行組織と密接に連携し、最新の金融プラットフォームを支えるスケーラブルでセキュアかつレジリエントなクラウドおよび AI ソリューションを設計しています。 Narendra Reddy Bathina Narendra は、AWS の金融サービス担当テクニカルアカウントマネージャーです。フィンテックのお客様と連携し、データベース、ストレージ、クラウドオペレーションの豊富な現場経験を活かして、本番システムのレジリエンス、パフォーマンス、スケーラビリティの向上を支援しています。 Viraj Padte Viraj は、AWS の金融サービス担当シニアソリューションアーキテクトです。さまざまなフィンテックのお客様と連携し、コアビジネスおよび AI を活用したプラットフォームとソリューションを支えるエンタープライズ対応のインフラストラクチャを設計しています。 この記事は Kiro が翻訳を担当し、Solutions Architect の Kenta Nagasue がレビューしました。
脱「モンキーAI」、Gemini Enterpriseによる「インラインAI」への移行 AIを導入しても成果が出ない企業の多くが陥っているのが、いわゆる「モンキーAI(Monkey AI)」の状態です。これは、あるツールからデータをコピーし、別のAIチャットツールに貼り付けて結果を得て、また元のツールに戻すという、非効率な「往復作業」を指します。
本記事は 2025 年 5 月 19 日に公開された How Amazon maintains accurate totals at scale with Amazon DynamoDB を翻訳したものです。翻訳は Solutions Architect の嶋田 朱里が担当しました。 Amazon の Finance Technologies Tax チーム (FinTech Tax) は、世界中の法域で税額計算、税額控除、納付、報告といった重要なサービスを管理しています。このアプリケーションは、複数の国際マーケットプレイスで年間数十億件の取引を処理しています。 この投稿では FinTech Tax チームが Amazon DynamoDB のトランザクションと条件付き書き込みを使用して、段階的な源泉徴収を実装した方法を紹介します。 これらの DynamoDB の機能を使用することで、拡張性と回復力があるイベント駆動の税額計算サービスを構築し、大規模でもミリ秒レベルのレイテンシーを実現しました。 また、一貫したパフォーマンスを実現しながら、データの正確性を厳密に維持するための設計上の決定と実装の詳細についても探ります。 要件 Amazon は複数の法域にまたがる複雑なフィンテック (金融技術) 分野の税制環境で事業を行っており、さまざまな源泉徴収税の要件を管理する必要があります。同社には、膨大な取引量を処理できる堅牢な税処理ソリューションが必要です。このシステムは、毎日数百万件の取引をリアルタイムで処理し、個人ごとの累積取引額の正確な記録を源泉徴収税計算のために維持する必要があります。主な要件には、段階的な源泉徴収税率を正確に適用すること、および Amazon の既存システムとのシームレスな統合が含まれます。このソリューションはデータの整合性と高可用性を維持し、さまざまな源泉徴収税制度に対する規制遵守をサポートする必要があります。 課題 主な課題は世界中の複雑に絡み合った税法に厳密に準拠することにあります。特に、段階的課税モデルでは、個人の総取引額が財務年度内の特定の閾値を超えるかどうかに基づいて、異なる源泉徴収税率が適用されます。個人の累積取引額が増加し、あらかじめ定義された閾値を超えると、その取引に適用される源泉徴収税率が変更されます。例えば、総額が 100,000 インドルピー (INR) に達するまでは低い税率が適用され、その閾値を超えると、より高い税率が適用されます。 次の図は、累積取引金額の閾値に基づいて税率が段階的に変化する様子を示した、3 段階の税率モデルを示しています。 段階的課税モデルの課題は、源泉徴収についてリアルタイムの計算を行いながら、各個人の累計取引額を正確に追跡・記録管理することにあります。 Amazon は 1 日に数百万件のトランザクションを処理しなければなりません。 さらに、正の取引・負の取引(例:プラスまたはマイナスの会計調整)に関わらず、正しい源泉徴収税率をリアルタイムで適用することが求められます。 これには高い取引量 (個人あたり約 150 トランザクション/秒) を処理しながら、正確な記録を維持できるシステムが必要です。 ソリューションの概要 次の図は Amazon の源泉徴収税計算サービスの全体アーキテクチャです。 ワークフローは以下のステップで構成されています: クライアントが Amazon API Gateway に源泉徴収税計算リクエストを送信します。 API Gateway が税額計算 (Tax Computation) AWS Lambda を呼び出します。 税額計算 Lambda 関数が、DynamoDB の個人の累積トランザクションストア(Cumulative Transaction Store)テーブルを取得します。累積トランザクションストアテーブルは過去の累計値をもとに、ユーザーごとの累積取引金額をリアルタイムで管理します。これにより、段階的な税率を適用するための個人の累積取引金額の合計を正確に追跡できます。 Lambda 関数は取引の詳細と個人の累計金額に基づいて、ルールエンジンライブラリから適用される税率を取得します。取得した税率と取引データをもとに、税額が計算されます。 計算結果は取引データの監査と履歴管理のために DynamoDB の取引監査ストア (Transaction Audit Store) に格納されます。 現在の取引金額をもとに、個人の累積取引金額が累積トランザクションストアに更新されます。 DynamoDB 操作中に発生する一時的なエラー (例: ConditionalCheckFailed 、 TransactionConflict ) は、 Amazon Simple Queue Service (Amazon SQS) キューに送られ、再試行されます。 クライアントエラー (400 Validation Exception、401 Unauthorized、403 Forbidden など) や永続的なサーバー障害によるエラーは、SQS DLQ で処理されます。 実装上の考慮事項 トランザクションを受信すると、システムはルールエンジンから導出された閾値に対して個人の累積取引額を評価して、適用される税率を判断します。その後、累積取引金額は累積トランザクションストアに更新され、監査証跡も記録されます。 複数のスレッドが同一個人のデータベースを同時に更新しようとすると、競合が発生します。一般的な 楽観的排他制御 (OCC) の手法は、累積値を読み取り、指定範囲の値に対する税率を計算し、累積値が読み取り以降変更されていないという条件付きでトランザクションを書き込みます。もし値が変更されていた場合はループの最初から処理をやり直します。 トラフィックが多い場合、この再実行が頻繁に発生する可能性があります。 私たちのアプローチは、一般的な OCC パターンを改良したものです。条件の判定を「累積値が最初に読み取った時点の範囲内に留まっているか」のみに絞っています。 累積値が変化しても、その値が閾値を超えない限り、ループを再実行する必要はありません。 この方法により、条件の不一致が少なくなるため、スループットが上がります。個人の累積値がより高い範囲に移行した場合は、書き込み操作が失敗します。 その場合は、更新された値をもとに、読み取りと書き込みを再試行する必要があります。 OCC 戦略とは異なり、このアプローチでは最後の読み取り以降に値が変化していても処理が成功します。これにより、競合を最小限に抑え、スループットを向上させることができます。同時更新(累積合計が閾値を超えるケース)によって条件付き書き込みが失敗し、 ConditionalCheckFailedException が発生することがありますが、これは想定された動作であり、データの不整合を示すものではありません。 一時的なエラーを処理し、同じトランザクションの重複処理を防ぐために、クライアント要求トークン (Client Request Token, CRT) を含んだ TransactWriteItems 操作を実行することで、インクリメント操作を冪等性のある状態で行えます。 TransactionCanceledException は、 エクスポネンシャルバックオフ などのエラー処理メカニズムで処理されます。 この戦略の組み合わせにより、システムはデータの整合性を維持しながら、高いスループットとスケーラビリティを実現できます。 複雑なロック機構が不要になり、従来のOCCソリューションと比べて効率性が向上します。また、大規模な設定やチューニングを必要とせず、さまざまなトランザクション量や同時実行レベルに柔軟に対応できる、高性能なソリューションを提供します。 累積トランザクションストア 累積トランザクションストアテーブルは、特定の個人の取引金額の累積和を維持するために使用されます。以下のデータモデルを使用します: { "indvidual_id": { "S": "TIN1" // 累積合計を管理する単位となる一意識別子 }, "cumulative_amount_consumed": { // 使用された金額の累積合計を表す "N": "0" } } 税控除対象品目の在庫管理 税額控除監査ストア(Tax Deduction Audit Store)テーブルは、各取引の税控除率の監査記録を保存するために使用されます。以下のデータモデルを使用します: { "transaction_primary_key": { "S": "XXX111#2024-01-01T13:05:28" // トランザクションの一意識別子(PartitionKey#SortKey) }, "transaction_amount": { "S": "1000". //トランザクション全体の金額 }, "transaction_tax_amount": { "S": "100". //控除される税額 }, "transaction_tax_rate":{ "S":"10". //このトランザクションに適用される税率(パーセント表記) } ... } 条件付き書き込みのコード 次のコードは dynamodb.transact_write_items() を使用して、累積トランザクションストアと取引監査ストアの 2 つの DynamoDB テーブルにまたがるアトミックな条件付き書き込み操作を示しています。累積トランザクションストアから既存のレコードを取得し、現在の取引金額と既存データに基づいて cumulative_amt_consumed (累積消費金額)の更新値を計算します。同時に、取引監査ストアに新しいレコードを記録し、ID、値、税額、税率などのトランザクション詳細を記録します。 transact_write_items() メソッドは、取引トランザクションストアテーブルへの更新操作と取引監査ストアテーブルへの put 操作を 1 つのトランザクションとして実行します。 2 つの操作がともに成功すれば、両方のテーブルに変更がコミットされます。そうでない場合は、トランザクション全体がロールバックされ、データの整合性が保たれます。 SAMPLE_TIN = 'TIN1' # 累積トランザクションストアにおける一意の識別子を表す SAMPLE_AMOUNT = 5000 # transact_write_items で処理される売上値を表す SAMPLE_TRANSACTION_ID = 'XXX111' DEFAULT_TAX_RATE = 10 # 既定の税率(パーセンテージ値) LOWER_TAX_RATE = 5 # 低い方の税率(パーセンテージ値) RETRYABLE_ERRORS = ( 'TransactionConflictException', 'ConditionalCheckFailedException', 'ProvisionedThroughputExceededException', 'ThrottlingException', 'ServiceUnavailableException', 'InternalServerErrorException' ) MAX_RETRIES = 3 RETRY_DELAY = 0.1 # 秒 def send_to_error_queue(error_message, is_retryable, transaction_id): queue_url = 'TransientErrorQueue' if is_retryable else 'NonTransientErrorQueue' message_body = { 'error_message': error_message, 'transaction_id': transaction_id } try: sqs.send_message( QueueUrl=queue_url, MessageBody=json.dumps(message_body) ) except Exception as e: print(f"Failed to send message to {queue_url}: {str(e)}") def process_transaction(tin, amount, transaction_id): for attempt in range(MAX_RETRIES + 1): try: response = dynamodb.get_item(TableName='CumulativeTransactionStore', Key={'cumulativeStore_primary_key': {'S': tin}}) item = response.get('Item') if not item: print("Record not found.") return cumulative_amount_consumed = int(item.get('cumulative_amount_consumed', {}).get('N', '0')) threshold_value = int(item.get('threshold_value', {}).get('N', '0')) current_amount = amount if (cumulative_amount_consumed + current_amount < threshold_value): update_expression = 'SET cumulative_amount_consumed = cumulative_amount_consumed + :val, tax_rate = :tax_rate' tax_rate = DEFAULT_TAX_RATE max_value = threshold_value min_value = 0 else: update_expression = 'SET cumulative_amount_consumed = cumulative_amount_consumed + :val, tax_rate = :tax_rate' tax_rate = LOWER_TAX_RATE max_value = sys.maxsize min_value = threshold_value expression_attribute_values = { ':val': {'N': str(current_amount)}, ':tax_rate': {'N': str(tax_rate)}, ':lo': {'N': str(min_value)}, ':hi': {'N': str(max_value)} } dynamodb.transact_write_items( TransactItems=[ { 'Update': { 'TableName': 'CumulativeTransactionStore', 'Key': {'cumulativeStore_primary_key': {'S': tin}}, 'UpdateExpression': update_expression, 'ConditionExpression': 'cumulative_amount_consumed < :hi AND cumulative_amount_consumed >= :lo', 'ExpressionAttributeValues': expression_attribute_values, } }, { 'Put': { 'TableName': 'TaxDeductionAuditStore', 'Item': { 'transactionID': {'S': transaction_id}, 'transaction_amount': {'N': str(amount)}, 'transaction_tax_amount': {'N': str(amount * tax_rate / 100)} } } } ], ClientRequestToken=transaction_id ) print(f"Transaction processed successfully on attempt {attempt + 1}") return # Success, exit the function except Exception as e: error_code = e.response['Error']['Code'] error_message = f"Error accessing DynamoDB: {error_code} - {e.response['Error']['Message']}" is_retryable = error_code in RETRYABLE_ERRORS if is_retryable and attempt < MAX_RETRIES: print(f"Retryable error occurred on attempt {attempt + 1}. Retrying...") time.sleep(RETRY_DELAY * (2 ** attempt)) # Exponential backoff else: send_to_error_queue(error_message, is_retryable, transaction_id) # If we've exhausted all retries error_message = f"Max retries ({MAX_RETRIES}) exceeded. Last error: {error_message}" send_to_error_queue(error_message, True, transaction_id) # Main execution try: process_transaction(SAMPLE_TIN, SAMPLE_AMOUNT, SAMPLE_TRANSACTION_ID) except Exception as e: print(f"Transaction processing failed: {str(e)}") 結果 システムのパフォーマンス評価では、実行時間を 30 秒に固定し、スレッド数を変えながら一連のテストを実施しました。 各実行後に累積トランザクションストアをゼロにリセットすることで、さまざまな負荷条件下でのシステムの動作を包括的に分析しました。 1 スレッドから 130 スレッドにスケールアップするにつれて、処理されたトランザクション数が一貫して増加したことから、システムが大規模な並列処理の場面においても高い並行性を効果的に処理できることが示されました。 しかし、この処理能力の向上には一時的な競合の増加が伴いました。これは、大規模な並列処理の場面において、パフォーマンスと競合管理のトレードオフを浮き彫りにしています。 一時的なアクセスの競合は、複数のトランザクションが同時に同じアイテムを更新しようとしたときに発生し、一部のトランザクションがキャンセルされることになります。このデータが示すのは、スレッド数を増やしても競合管理のオーバーヘッドが増大するため、スループットが大幅には向上しなくなるということです。 次のグラフはスレッド数とトランザクションメトリクスの相関関係を示しています。 これにより、スループットと競合率が同時実行スレッドの増加に伴ってどのように変化するかがわかります。 結論 この投稿では、Amazon Fintech チームが DynamoDB の強力な条件付き書き込み機能を使用することで、段階的税率アプリケーション向けのシンプルかつ高いスケーラビリティを持つソリューションを実装した方法を紹介しました。 この手法を採用し、まれに発生する ConditionalCheckFailedException を先に見越して処理することで、大量の同時トランザクションが発生するシナリオにおいても、高いスループットとスケーラビリティを実現しながら、データの一貫性を維持することができます。 この手法は、同時リクエスト数が増加するにつれボトルネックになりがちな楽観的ロックの必要性をスマートに排除しています。代わりに、Amazon Fintech システムは DynamoDB の組み込みの同時アクセス制御メカニズムを活用し、高負荷状況でも一貫したデータと効率的な更新を可能にしています。 拡張性のあるトランザクション処理システムを独自に実装するには、DynamoDB の 条件付き更新 機能を確認してください。詳しいガイダンスが必要な場合は、DynamoDB の ドキュメント を参照するか、AWS サポートにお問い合わせください。 著者について Jason Hunter はカリフォルニア在住の Amazon DynamoDB 専任のプリンシパルソリューションアーキテクトです。2003 年から NoSQL データベースに携わっています。Java、オープンソース、XML への貢献で知られています。 DynamoDB の投稿 や Jason Hunter が書いた他の投稿は、 AWS Database Blog で見つけることができます。 Balajikumar Gopalakrishnan は、Amazon Finance Technology の Principal Engineer です。 2013 年から Amazon に在籍し、Amazon の顧客の生活に直接影響を与える技術を通じて、実世界の課題を解決してきました。 仕事以外では、ハイキング、絵画、家族と過ごすことを楽しんでいます。また、映画好きでもあります。 Jay Joshi は、Amazon Finance Technology のソフトウェア開発エンジニアです。 2020 年から Amazon に在籍し、主に世界各地の法域での税額計算とレポーティングのためのプラットフォームの構築に従事しています。 仕事以外では、家族や友人と過ごしたり、新しい料理の行き先を探索したり、バドミントンをするのが好きです。 Arjun Choudhary は 2019 年からAmazon の Finance Technology 部門でソフトウェア開発エンジニアとして働いています。主な業務は、グローバルな法人税の源泉徴収プラットフォームの開発です。仕事以外では、小説を読んだり、クリケットやバレーボールをしたりして楽しんでいます。















