OLTPスループットとレイテンシの限界
DSQLのSLO容量・レイテンシは各対照群の何倍か?
結果の要約
この実験では、同じ注文業務を同じレイテンシ目標(SLO)で実行したときに、DSQLが対照群よりどれだけ多くのリクエストを処理し、レイテンシがどう異なるかを確認しました。業務は商品照会40%、注文履歴照会30%、注文作成20%、注文キャンセル10%の混合で、SLOは読み取りp95 50 ms・p99 100 ms、書き込みp95 100 ms・p99 200 ms、技術的失敗率0.1%以下です。実験は2回に分けて実行しました。2026-09-28には4サービスを同時に起動してパイロットと同時実行数の探索を行いましたが、DSQLの探索が初期化の遅さと予算の制約で止まったため、2026-09-29にDSQLだけを新たに起動し、セルごとにデータを削除しない方式で再測定しました。
接続数を固定して休みなくリクエストを送る方式(closed-loop)で、DSQLは接続64個で6,680 TPS、接続256個で24,541 TPSを処理し、いずれもSLOを守りました。接続256個でも注文作成のp99は35.7 msで、接続64個(30.4 ms)とほぼ同じでした。同じ方式による対照群の測定(2026-09-28)では、接続256個で3つの対照群すべての書き込みレイテンシがSLOを超え、SLOを守った最高スループットはRDS Multi-AZ(R1)5,839 TPS、Aurora Provisioned(A1)3,375 TPS、Aurora Serverless v2(A2)11,559 TPSでした。接続256個の条件で、DSQLはA2の約2.1倍、R1の約4.2倍、A1の約7.3倍を処理しました。このとき負荷発生器のCPUは80.8%で飽和基準(85%)に近かったため、DSQLの値はサービスの限界ではなく、今回の測定の下限です。
レイテンシの絶対値はDSQLの方が長くなりました。同じ1,600 TPSで、DSQLの注文作成p95は41.0 ms(2026-09-28)、A2は6.8 msで、2026-09-29の測定ではDSQLの書き込みp95は約28–30 msでした。リクエストを決められた到着率で送る方式(open-loop)では、DSQLは6,750 TPSまでSLOを守り、8,100 TPSでp99が200 msを超えました。ただしこの失敗はDSQLの処理レイテンシ(p95約28 msで変化なし)ではなく、負荷発生器がプロセスごとに分けて使う接続を待った時間(待機p99約190 ms)によるものであるため、open-loopの限界は測定ツールの接続プールの限界と解釈します。すべてのセルで業務不変条件の違反は0件でした。計画していた共通到着率での本測定と反復はできなかったため、サービス間の差は1回の測定値です。
本番利用の観点
スループットの面では、DSQLは今回の実験で最も大きくスケールしました。接続256個で毎秒2万4千件以上の注文混合業務をレイテンシの増加なしに処理し、同じ条件で既存サービスはすべてレイテンシ目標を超えました。容量計画なしに負荷が増えても耐えられる点は、トラフィックの変動が大きいサービスに有利です。その代わり、リクエスト1件のレイテンシはAuroraより3–6倍長く(書き込みp95約30–40 ms)、リクエストごとに複数のクエリを順に実行する画面では応答時間が延びます。同じスループットを出すには接続と同時実行数をより多く使う必要があり、高いスループットを維持し続けるとDPU料金が大きくなります(E010)。
確認する問い
DSQLのSLO容量・レイテンシは各対照群の何倍か?
接続256個の固定同時実行数を基準に答えられます。DSQLのSLO通過スループットは、A2の約2.1倍以上、R1の約4.2倍以上、A1の約7.3倍以上です。レイテンシは逆に、DSQLが3–6倍長くなります。共通到着率(0.5/1.0/1.2 × Qref)での本測定は行っていません。
実行条件
- リージョンと日時: ソウル(ap-northeast-2)。1回目(4構成)2026-09-28 03:34–12:07 UTC、2回目(DSQL単独)2026-09-29 08:11–11:10 UTC。
- 構成:
- D1:Aurora DSQLシングルリージョン、IAMトークン認証、パブリックエンドポイント。
- R1:RDS for PostgreSQL 16、
db.r6g.xlargeMulti-AZ、gp3 400 GiB。 - A1:Aurora PostgreSQL 16 Provisioned、
db.r6g.xlargewriter 1台 + 別AZのreader 1台、Aurora Standard。 - A2:Aurora PostgreSQL 16 Serverless v2、writer 1台 + reader 1台、各4–32 ACU、Aurora Standard。
- データ: 顧客100万、商品20万、注文1,100万、注文明細2,750万、元帳1,100万行(約5 GiB)。D1のロード行数はDBで直接数え、設計値と一致することを確認しました。
- 業務と判定: 上記の混合業務、明示的な
REPEATABLE READ、共通の再試行ポリシー。技術的失敗率0.1%以下とSLOの両方を守った場合に通過です。セルごとに在庫・注文・元帳の不変条件を検査しました。 - 負荷発生器: 構成ごとにSpotランナー1台。パイロットは
c7g.4xlarge、探索はSpotの容量不足と中断のため、4構成すべてでc6g.4xlargeを使いました。発生器のCPUは最大69.7%(A2 接続256)で、飽和基準(85%)を下回っていました。 - セル時間: パイロットはウォームアップ60 s + 測定120 s、探索と2回目の測定はウォームアップ120 s + 測定300 s、各1回。
- 2回目の測定(DSQL単独): 新しいDSQLクラスターに同じデータをロードし、セルが作成した行を削除せずに積み上げました。整合性はセルごとに、そのセルが作成した行だけを選んで検査しました(セルごとに個別に割り当てたID範囲と業務IDの接頭辞)。セルごとに注文が約1%ずつ増えます。ランナーは
c6g.4xlargeで開始し、Spotの中断によりm7g.4xlargeに交換しました。接続64・256と5,400 TPS以上のセルはm7g.4xlargeで実行しました。対照群は2026-09-28の結果をそのまま比較に使いました。 - 計画から変わった点:
- 本測定(0.5/1.0/1.2 × Qref)と境界探索は実行できませんでした。
- 費用上限をUSD 50から60に引き上げました(2026-09-28 ユーザーの決定)。
- 対照群とDSQLの探索は、異なる日に、異なるランナー仕様(
c6g.4xlarge対m7g.4xlarge)と異なるランナーの位置で実行しました。DSQLのRTTは1回目が2.7–5.1 ms、2回目が1.6–1.8 msで、書き込みレイテンシも2回目の方が約30%短くなりました。 - 費用上限:1回目USD 60(2026-09-28 ユーザーの決定)、2回目USD 20(2026-09-29 ユーザーの決定)。
性能結果
固定到着率パイロット(open-loop)
p95 / p99、単位ms。すべてのセルで失敗率0、不変条件違反0件、SLO通過。
| 構成 | 到着率 | 商品照会 | 注文履歴 | 注文作成 | 注文キャンセル | RTT |
|---|---|---|---|---|---|---|
| D1 | 100 | 10.5 / 12.3 | 14.3 / 16.1 | 47.6 / 55.2 | 50.0 / 59.2 | 2.8 |
| D1 | 400 | 10.3 / 11.5 | 13.2 / 14.3 | 47.6 / 53.6 | 48.1 / 54.2 | 3.0 |
| D1 | 1600 | 9.1 / 10.6 | 11.7 / 13.3 | 41.0 / 46.2 | 41.4 / 47.6 | 5.1 |
| A2 | 100 | 3.6 / 4.5 | 9.9 / 11.8 | 13.1 / 16.2 | 7.6 / 9.4 | 0.3 |
| A2 | 400 | 2.4 / 2.8 | 3.9 / 5.2 | 9.3 / 11.4 | 9.0 / 10.9 | 0.1 |
| A2 | 1600 | 2.2 / 2.7 | 2.6 / 3.2 | 6.8 / 7.9 | 6.9 / 8.1 | 0.1 |
A2のwriterは1600 TPSで12 ACUを使用しました。D1はリクエスト試行1回あたり約0.0375 DPUを消費しました。
同時実行数固定の探索(closed-loop)
成功スループット(TPS)とSLO判定。すべてのセルで失敗率0、不変条件違反0件。対照群は2026-09-28、D1の接続64・256は2026-09-29の測定です。
| 構成 | 接続16 | 接続64 | 接続256 | SLOを守った最高スループット |
|---|---|---|---|---|
| D1 | 1,006 通過(1回目) | 6,680 通過 | 24,541 通過 | 24,541以上(下限) |
| R1 | 3,065 通過 | 5,839 通過 | 5,347 超過 | 5,839 |
| A1 | 3,375 通過 | 3,322 超過 | 4,254 超過 | 3,375 |
| A2 | 5,657 通過 | 11,559 通過 | 15,115 超過 | 11,559 |
- D1 接続256のp95 / p99(ms):商品照会5.6 / 6.4、注文履歴8.3 / 9.5、注文作成30.4 / 35.7、注文キャンセル28.9 / 32.9。接続64(4.9 / 5.5、7.6 / 8.4、27.8 / 30.4、27.0 / 29.8)とほぼ同じで、接続を4倍に増やしてもレイテンシはほとんど増えませんでした。このときランナーのCPUは80.8%でした。
- D1 接続256の試行スループットは26,285 TPSで、成功スループットより約7%多くなりました。差はコミット時点の競合(
40001)の後に再試行した試行です。 - A1 接続64は注文履歴照会のp99が178.7 msで、読み取りSLO(100 ms)を超えました。
- 接続256では、3つの対照群すべてで書き込みp95が書き込みSLO(100 ms)を超えました(注文作成p95:R1 163.4 ms、A1 250.7 ms、A2 122.5 ms)。
- D1 接続16(1回目)は1,006 TPSと低くなりましたが、これは1回目の測定ではD1のレイテンシが2回目より長く(RTT 2.7–5.1 ms)、接続数が少ないためリクエストあたりのレイテンシがスループットを制限したからです。
到着率固定での段階的引き上げ(open-loop、DSQL単独)
| 到着率 | 成功TPS | 判定 | 注文作成p95 / p99 | 接続待機p99 |
|---|---|---|---|---|
| 2,400 | 2,329 | 通過 | - | - |
| 3,600 | 3,493 | 通過 | - | - |
| 5,400 | 5,202 | 通過 | - | - |
| 6,750 | 6,416 | 通過 | 27.8 / 101.4 | 26.5 ms |
| 8,100 | 7,758 | 超過 | 28.1 / 255.7 | 189.7 ms |
- 8,100 TPSではすべての業務でp99が200 msを超えましたが、待機時間を除いた処理レイテンシ(p95約28 ms)は変わりませんでした。ランナーは接続256個を16個のプロセスに16個ずつ分けて使うため、到着が集中したプロセスではリクエストが接続を待ちました。したがって、open-loopの6,750 TPSはDSQLの限界ではなく、今回の測定ツールの接続プールの限界と解釈します。
- リクエスト試行1回あたりのDPUは0.029–0.032で(2,400 TPSで0.032、26,285 TPSで0.029)、パイロットでの推定値0.0375よりやや低くなりました。
開発・運用のしやすさ
- 大量削除が遅い: セルが作成した行を元に戻す初期化で、D1は約13万件のレシートと関連行(注文・明細・元帳・在庫復元の合計約60万行の変更)を処理するのに6–7分かかりました。最初の実装はバッチごとに対象の照会を再実行して27分の制限を超え、対象を1回だけ照会するよう修正した後も、接続64セルの初期化は制限時間内に終わりませんでした。対照群では同じ初期化がセル時間に問題を起こしませんでした。
- 外部キーの逆方向インデックス: 注文を削除する際、元帳の
order_idにインデックスがなかったため、削除のたびに元帳全体を走査し、D1はトランザクションの300秒制限(ProgramLimitExceeded)に達しました。この問題はA2でも24分かかる削除として現れました。インデックスを追加して解決しました。 - 非同期インデックス: DSQLの
CREATE INDEX ASYNCで作成したインデックスは、ビルドが終わる前からpg_indexesに表示されました。pg_index.indisvalidが真になるまで待つようツールを修正しました。 - 一時的なエラー: ロード中に
XX000 server unavailableが発生したため、再試行の対象に追加しました。トランザクションあたり3,000行の制限に合わせて、ロードと削除を分割しました。 - 接続管理: DSQLの接続には1時間の制限があるため50分ごとに再接続し、IAMトークンは10分間キャッシュしました。
- トークンの同時署名: 2回目の測定で、接続256個が同時にIAMトークンに署名しようとして、インスタンスの認証情報の照会が失敗しました(
NoCredentialsError)。プロセスごとに署名を1回だけ行うようロックをかけ、一時的な認証情報エラーを再試行するよう修正しました。 - 初期化の代わりに積み上げ: DSQLの大量削除が遅い問題を避けるため、2回目の測定ではセルが作成した行を削除しませんでした。当初は、Spotの中断で止まった試行が残した行を再試行が自分の行として数える問題があったため、試行ごとに固有のID範囲を使うよう修正しました。
費用
1回目の測定(4構成、2026-09-28):推定費用は実行中にハーネスが使用量と単価から計算した値で、実際の請求額は2026-09-29にCost Explorer(ソウルリージョン、2026-09-28 UTC、使用タイプ別)で確認した値です。実験はすべて2026-09-28 UTC内に実行されました。実験の前日にも発生していたアカウントの常時料金(ロードバランサー、S3、既存のパブリックIPv4など、1日約USD 2.9)は除外しました。照会時点のCost Explorerの値は月次締め前の推定状態です。
| 項目 | 推定費用 | 実際の請求額 | 使用量と差異 |
|---|---|---|---|
| D1 DPU | 約$10.7 | $11.49 | 1,148,488 DPU。ハーネスの最後の測定後の使用量(中断した接続64セル、削除前後)が推定から漏れていました。 |
| A2 コンピューティング | 約$31.3 | $23.99 | 119.9 ACU時間。推定は測定されていない区間を最大ACUで計算したため高くなりました。 |
| Aurora I/O(A1+A2) | 約$4.7 | $6.53 | 2,720万I/O(Aurora Standard)。最後の測定後のI/Oが推定から漏れていました。 |
| A1 インスタンス | 約$2.9 | $2.43 | db.r6g.xlarge 3.90インスタンス時間(writer+reader) |
| R1 | 約$2.7 | $2.12 | Multi-AZ 1.72時間 + gp3ストレージ |
| ランナー・その他 | 約$0.9 | $2.03 | Spotランナー13.95時間($1.68)、AZ間転送、パブリックIPv4、EBS |
| 合計 | 約$53 | $48.57 | 推定の約92%。上限USD 60、ガードUSD 54以内 |
2回目の測定(DSQL単独、2026-09-29):CloudWatch TotalDPUの合計1,784,023 DPU(約$17.84)とSpotランナー約$0.73で約$18.6と推定し、2026-09-30にCost Explorerで確認した実際の請求額は$18.54でした(DSQL DPU $17.84、Spotランナー$0.70)。同じ日に実行したE005・E006・E007・E009の実行とDSQL DPUが1行にまとめて請求されたため、クラスター別のCloudWatch DPUで分けました。両実行のCloudWatch合計(1,818,111 DPU)は請求されたDPU(1,818,110)と一致しました。このうちデータロードが517,021 DPU(約$5.17)、段階的引き上げ・closed-loopの測定が1,093,524 DPU(約$10.94)で、残りは同じクラスターで実行したE003・E008・E012です。2つの実行が共有したAZ間転送・EBS・パブリックIPv4の約$0.65は、どちらの実行にも割り当てていません。
- 今月のDSQL無料使用量(10万DPU)はE004ですべて使ったため、D1のDPUは無料使用量の差し引きなしに請求されます。
- A2は探索で15,000 TPSの負荷を受けてACUが大きく増え、パイロット後に決定を待つ間のアイドル時間も含まれたため、最大の費用(全体の約49%)となりました。
- Aurora StandardのI/O料金は$6.53で、A1のインスタンス料金より大きくなりました。負荷の大きい実験ではI/O-Optimizedの方が安くなる可能性があります(今回は比較していません)。
結論と限界
- スループット: 接続256個の固定同時実行数で、DSQLは24,541 TPS以上をSLO内で処理し、対照群のSLO通過最高スループット(R1 5,839、A1 3,375、A2 11,559 TPS)の2.1–7.3倍でした。DSQLの値は負荷発生器の限界に近い下限です。
- レイテンシ: DSQLの書き込みp95は約28–41 msで、Aurora Serverless v2(約7–9 ms)より3–6倍長くなりましたが、負荷が増えてもほとんど増えませんでした。
- 測定できなかったもの: 共通到着率(0.5/1.0/1.2 × Qref)での本測定、境界探索、反復間のばらつき、複数ランナーによるDSQLの実際の上限。
- 限界: すべてのセルは1回の実行です。DSQLと対照群の探索は、異なる日に異なるランナー仕様で実行されました。DSQLはパブリックエンドポイント、対照群はVPC内部の経路です。2回目の測定は、セルごとにデータが約1%ずつ増える条件です。
後片付けの記録
- 作成したリソース:
- BATCH:VPC、サブネット2つ、IGW、セキュリティグループ2つ、DBサブネットグループ、IAMロール・インスタンスプロファイル。
- 構成別:D1クラスター、R1インスタンス、A1・A2クラスターとwriter・reader、RDS管理のシークレット3つ。
- Spotランナー:交換分を含めて複数台。Spotの中断2回(06:45 UTCに2台、08:54–08:59 UTCに起動した3台)と容量不足のため交換しました。
- A2の再作成: パイロット後に費用を減らすためA2を削除し、本段階で再作成してロードしました。
- 削除完了時刻(UTC): R1・A1・A2 10:57:45、D1 12:06:31、BATCH 12:06:45。削除に失敗したリソースはありません。
- 検証(12:07:44 UTC):
e002.py verifyのremaining_count=0です。最初の検証(12:06:55)では、終了したランナーのSpotリクエスト1件がactive状態で残っていたため1となり、リクエストをキャンセルしてから再度検証しました。後片付けのコードがSpotリクエストを直接キャンセルしない点は修正課題です。 - 2回目の測定(2026-09-29、
e002-20260929t081139z-4dce): BATCHのネットワーク・IAM、DSQLクラスター1つ、Spotランナー2台(c6g.4xlargeは08:33 UTCにSpot中断、交換後はm7g.4xlarge)を作成しました。同じクラスターでE003・E008・E012を実行した後、11:08–11:10 UTCに削除し、e002.py verifyのremaining_count=0(11:10:30 UTC)を確認しました。ランナー終了時にSpotリクエストも併せてキャンセルするよう修正した後だったため、残ったSpotリクエストはありませんでした。手動のクロスチェックで、DSQLクラスター0個、実験タグ付きVPC 0個、実験用IAMロール0個、オープンなSpotリクエスト0個を確認しました。