8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「ゲームで体感!Aurora DSQL の OCC(楽観的同時実行制御)」の結果ログから Aurora DSQL の動作を考察する

Last updated at Posted at 2025-07-09

今年(2025 年)7 月 5 日開催の JAWS ミート 2025 の LT で、表題のとおり Aurora DSQL の OCC(楽観的同時実行制御)を「利用」した簡単なゲームを実施しました。

この記事では、そのゲームの際に取得したログから、Aurora DSQL の OCC(楽観的同時実行制御)の動作を追って考察してみます。

Aurora DSQL とは?

AWS が 2024 年 12 月の re:Invent 2024 で発表した、SQL が使えるサーバレス大規模分散データベースです。

使える SQL 構文に制約はありますが、PostgreSQL とはワイヤープロトコル互換となっており、psqlコマンドや PostgreSQL 向けの各種管理アプリケーション、接続用ライブラリを使って接続可能です。

分散処理によるスケーラビリティや地理冗長 Active-Active クラスタによる耐障害性の高さをウリにしたデータベースですが、先日(2025 年 5 月下旬)一般提供が開始(GA) されました。

なお、プレビューから GA に至るまでにコードを Kotlin から Rust に書き換えたことが、Amazon.com CTO である Werner Vogels 博士 のブログ「All Things Distributed」の記事で語られています。

OCC(楽観的同時実行制御)とは?

Aurora DSQL では書き込み処理のスループット向上のために OCC(楽観的同時実行制御) を採用しています。

ブレビューが始まった頃に書いた記事で説明しているので詳細は省略しますが、一言でいうと ロックを使わない同時実行制御方式 です。

一般的な RDBMS ではロックを使う PCC(悲観的同時実行制御)を採用しているので、その動作の違いがアプリケーション設計に大きな影響を与えます。

JAWS ミート当日の LT では

こちらの資料を使って説明しながらゲーム 「最後にコミットした人が勝ち!」 を実施しました。

(ゲーム自体は Amazon Q CLI に作ってもらいました)

※14 〜 16 ページにあるリンク(ゲームの URL)の先はすでに閉鎖しています。

出題

ゲームの前に、

image.png

を出題した上で、以下のルールでゲームを開始しました。

ゲーム開始!

  • 最初に名前を登録
  • ゲームが始まったら制限時間内に攻撃ボタンを押す
    • 押すと DSQL 上のテーブル行をUPDATE→ 1 秒待つ→COMMIT
    • 同時に複数の人が攻撃した場合、COMMITが成功した人が勝ち
      • 勝つとUPDATECOMMITの待ち時間が 1 秒増える(最大 5 秒まで)
      • 負けると 1 秒にリセット
  • 攻撃ボタンは時間内に何度押しても OK
  • 制限時間内で一番最後にCOMMITした人が優勝!
    • ボタンを押した後のCOMMITが制限時間外なら攻撃失敗

7F0ADA45-85EB-46A4-B545-90BB039DC40D_1_201_a.jpeg

当日の様子は、こちらの参加記録ブログ記事後半部分に掲載しました。

ゲーム制作時点では東京+大阪+ソウルのマルチリージョンクラスタ構成が組めなかったので、東京リージョンのシングルリージョンクラスタ構成で Aurora DSQL を用意しました。

答え合わせ

image.png

ゲームの後、参加者に聞いてみたのですが、意外と理解されておらず「A」と思っていた方が多かったようです。

ゲーム後に残ったログから考察

というわけで、ここからがこの記事の本題です(前置きが長かった)。

当日のゲームは 1 分間で実施しましたが、察しの良い方ならお分かりのとおり、このゲームは

  • 終了手前を狙ってコミットが完了するように攻撃する
  • それ以前の時間帯に一切攻撃しない
    • うっかり攻撃成功して「待ち時間」を増やさない

のがポイントです。

ただ、普通に考えると「終了の 1 秒ちょっと前」に攻撃したくなるのですが、実は 「さらにその 1 秒前」を狙って攻撃するのがポイントです。

実際のログは

ゲームは 2025/07/05 13:44:32.472 に開始され、2025/07/05 13:45:32.472 に終了しました。

この 1 分間に 28 人の参加者がいて、560 件以上のログが記録されていました。

ただ、実際の勝敗に直接影響したのは残り数秒間だけでしたので、その部分だけ 30 行分抜き出して見やすいように加工しました。

※コミット時刻は実際の時刻ではなく単純に攻撃開始時刻に待ち時間を加えたものになっています。

No.	攻撃開始時刻          	攻撃成否	 参加者	待ち時間(秒)	コミット時刻	
 1	2025/07/05 13:45:27.831	  成功 	 Xさん	      1	    2025/07/05 13:45:28.831	
 2	2025/07/05 13:45:27.859	  失敗 	 Yさん	      1   	2025/07/05 13:45:28.859	
 3	2025/07/05 13:45:28.022	  失敗 	    	      1   	2025/07/05 13:45:29.022	
 4	2025/07/05 13:45:28.127	  失敗 	    	      1   	2025/07/05 13:45:29.127	
 5	2025/07/05 13:45:28.651	  失敗 	    	      1   	2025/07/05 13:45:29.651	
 6	2025/07/05 13:45:28.802	  失敗 	    	      1   	2025/07/05 13:45:29.802	
 7	2025/07/05 13:45:29.282	  失敗 	 Xさん	      2   	2025/07/05 13:45:31.282	
 8	2025/07/05 13:45:29.319	  成功 	 Yさん	      1   	2025/07/05 13:45:30.319	
 9	2025/07/05 13:45:29.337	  失敗 	    	      1   	2025/07/05 13:45:30.337	
10	2025/07/05 13:45:29.383	  失敗 	    	      1   	2025/07/05 13:45:30.383	
11	2025/07/05 13:45:29.416	  失敗 	    	      1   	2025/07/05 13:45:30.416	
12	2025/07/05 13:45:29.485	  失敗 	    	      1   	2025/07/05 13:45:30.485	
13	2025/07/05 13:45:29.514	  失敗 	    	      1   	2025/07/05 13:45:30.514	
14	2025/07/05 13:45:29.985	  失敗 	    	      1   	2025/07/05 13:45:30.985	
15	2025/07/05 13:45:30.519	  失敗 	 Yさん	      2   	2025/07/05 13:45:32.519	
16	2025/07/05 13:45:30.530	  成功 	 Zさん	      1   	2025/07/05 13:45:31.530	
17	2025/07/05 13:45:30.601	  失敗 	    	      1   	2025/07/05 13:45:31.601	
18	2025/07/05 13:45:30.682	  失敗 	    	      1   	2025/07/05 13:45:31.682	
19	2025/07/05 13:45:30.735	  失敗 	    	      1   	2025/07/05 13:45:31.735	
20	2025/07/05 13:45:30.958	  失敗 	    	      1   	2025/07/05 13:45:31.958	
21	2025/07/05 13:45:31.120	  失敗 	    	      1   	2025/07/05 13:45:32.120	
22	2025/07/05 13:45:31.218	  失敗 	    	      1   	2025/07/05 13:45:32.218	
23	2025/07/05 13:45:31.274	  失敗 	    	      1   	2025/07/05 13:45:32.274	
24	2025/07/05 13:45:31.380	  失敗 	    	      1   	2025/07/05 13:45:32.380	
25	2025/07/05 13:45:31.641	  失敗 	    	      1   	2025/07/05 13:45:32.641	
26	2025/07/05 13:45:31.722	  失敗 	    	      1   	2025/07/05 13:45:32.722	
27	2025/07/05 13:45:31.740	  失敗 	    	      1   	2025/07/05 13:45:32.740	
28	2025/07/05 13:45:31.806	  失敗 	 Xさん	      1   	2025/07/05 13:45:32.806	
29	2025/07/05 13:45:32.431	  失敗 	    	      1   	2025/07/05 13:45:33.431	
30	2025/07/05 13:45:32.851	  失敗 	    	      1   	2025/07/05 13:45:33.851	

参加者については、勝敗の流れに直接影響した 3 名のみ、以下のとおりに表示しました。

  • X さん : 最終的な勝者の 2 人前に攻撃成功
  • Y さん : 最終的な勝者の 1 人前に攻撃成功
  • Z さん : 最終的な勝者

以降、順を追って見ていきます。

No.1 〜 6 : X さん攻撃成功とその影響

No.	攻撃開始時刻          	攻撃成否	 参加者	待ち時間(秒)	コミット時刻	
 1	2025/07/05 13:45:27.831	  成功 	 Xさん	      1	    2025/07/05 13:45:28.831	
 2	2025/07/05 13:45:27.859	  失敗 	 Yさん	      1   	2025/07/05 13:45:28.859	
 3	2025/07/05 13:45:28.022	  失敗 	    	      1   	2025/07/05 13:45:29.022	
 4	2025/07/05 13:45:28.127	  失敗 	    	      1   	2025/07/05 13:45:29.127	
 5	2025/07/05 13:45:28.651	  失敗 	    	      1   	2025/07/05 13:45:29.651	
 6	2025/07/05 13:45:28.802	  失敗 	    	      1   	2025/07/05 13:45:29.802	

No.1 のタイミングで X さんが攻撃成功した(X さんのトランザクションのCOMMITが他の並行トランザクションのCOMMITに先行した)ことにより、

  • 2025/07/05 13:45:27.831 〜 2025/07/05 13:45:28.831 の間にトランザクションが走っていて
    • トランザクション開始がこの時間の範囲より前、またはこの範囲内
  • 2025/07/05 13:45:28.831 より後にCOMMITが実行された

No.2(Y さん)〜 6 が攻撃失敗しています。

そして X さんが攻撃成功したことで、X さんの(次回攻撃時の)待ち時間が 2 秒に増えました。

No.7 〜 14 : Y さん攻撃成功とその影響

No.	攻撃開始時刻          	攻撃成否	 参加者	待ち時間(秒)	コミット時刻	
 5	2025/07/05 13:45:28.651	  失敗 	    	      1   	2025/07/05 13:45:29.651	
 6	2025/07/05 13:45:28.802	  失敗 	    	      1   	2025/07/05 13:45:29.802	
 7	2025/07/05 13:45:29.282	  失敗 	 Xさん	      2   	2025/07/05 13:45:31.282	
 8	2025/07/05 13:45:29.319	  成功 	 Yさん	      1   	2025/07/05 13:45:30.319	
 9	2025/07/05 13:45:29.337	  失敗 	    	      1   	2025/07/05 13:45:30.337	
10	2025/07/05 13:45:29.383	  失敗 	    	      1   	2025/07/05 13:45:30.383	
11	2025/07/05 13:45:29.416	  失敗 	    	      1   	2025/07/05 13:45:30.416	
12	2025/07/05 13:45:29.485	  失敗 	    	      1   	2025/07/05 13:45:30.485	
13	2025/07/05 13:45:29.514	  失敗 	    	      1   	2025/07/05 13:45:30.514	
14	2025/07/05 13:45:29.985	  失敗 	    	      1   	2025/07/05 13:45:30.985	

関係するトランザクションが No.5 〜 14 の範囲になるので No.5・6 も含めて示しています。

No.5・6 ですが、No.8 の Y さんの攻撃(トランザクション)より先行して始まりUPDATECOMMITも先行していますが、前述のとおり No.1 の X さんのCOMMITに遅れたために失敗しています。

たとえ先行COMMITしても失敗していれば並行トランザクションのCOMMITの成否には影響しませんので、結果として No.8 の Y さんのCOMMITは成功します。

No.7 の X さんの攻撃(BEGINUPDATE)は Y さんに先行していますが、待ち時間が増えた結果 Y さんよりも後にCOMMITしているので失敗しています。

そして No.9 〜 14 は先の例と同様 Y さんのCOMMITに遅れたので失敗しています。

加えて Y さんが攻撃成功したことで、Y さんの次回待ち時間が 2 秒に増え、X さんが失敗したことで次回待ち時間が 1 秒にリセットされました。

No.16 〜 24 : Z さん攻撃成功とその影響

こちらも関係するトランザクションが No.14 〜 24 の範囲になるので No.14 も含めて示しています。

また失敗理由が「時間超過」なので本来はここから外れますが、No.15 も含めて考察します。

No.	攻撃開始時刻          	攻撃成否	 参加者	待ち時間(秒)	コミット時刻	
14	2025/07/05 13:45:29.985	  失敗 	    	      1   	2025/07/05 13:45:30.985	
15	2025/07/05 13:45:30.519	  失敗 	 Yさん	      2   	2025/07/05 13:45:32.519	
16	2025/07/05 13:45:30.530	  成功 	 Zさん	      1   	2025/07/05 13:45:31.530	
17	2025/07/05 13:45:30.601	  失敗 	    	      1   	2025/07/05 13:45:31.601	
18	2025/07/05 13:45:30.682	  失敗 	    	      1   	2025/07/05 13:45:31.682	
19	2025/07/05 13:45:30.735	  失敗 	    	      1   	2025/07/05 13:45:31.735	
20	2025/07/05 13:45:30.958	  失敗 	    	      1   	2025/07/05 13:45:31.958	
21	2025/07/05 13:45:31.120	  失敗 	    	      1   	2025/07/05 13:45:32.120	
22	2025/07/05 13:45:31.218	  失敗 	    	      1   	2025/07/05 13:45:32.218	
23	2025/07/05 13:45:31.274	  失敗 	    	      1   	2025/07/05 13:45:32.274	
24	2025/07/05 13:45:31.380	  失敗 	    	      1   	2025/07/05 13:45:32.380	

No.14 は先の No.8(Y さん)に遅れたことによりトランザクションが失敗しているので No.16 の Z さんのトランザクション成否には影響しません。

No.15(Y さん)は前回の攻撃成功により待ち時間が 2 秒になった結果、COMMITのタイミングがゲーム終了時刻を過ぎてしまったので失敗しています。仮に No.8 で成功していなければ、待ち時間が 1 秒で時間内にCOMMITが完了し、かつ Z さんに先行するのでタイミング的には優勝でした(残念!)。

No.17 〜 24 は先の例と同様 Z さんのCOMMITに遅れたので失敗しています。

No.25 〜 30 : 時間切れ

No.	攻撃開始時刻          	攻撃成否	 参加者	待ち時間(秒)	コミット時刻	
25	2025/07/05 13:45:31.641	  失敗 	    	      1   	2025/07/05 13:45:32.641	
26	2025/07/05 13:45:31.722	  失敗 	    	      1   	2025/07/05 13:45:32.722	
27	2025/07/05 13:45:31.740	  失敗 	    	      1   	2025/07/05 13:45:32.740	
28	2025/07/05 13:45:31.806	  失敗 	 Xさん	      1   	2025/07/05 13:45:32.806	
29	2025/07/05 13:45:32.431	  失敗 	    	      1   	2025/07/05 13:45:33.431	
30	2025/07/05 13:45:32.851	  失敗 	    	      1   	2025/07/05 13:45:33.851	

これらは Z さんのトランザクションと並行していませんが、COMMITのタイミングがゲーム終了時刻を過ぎてしまったので失敗しています。

図示すると

こんな感じになるでしょうか。

image.png

PCC(悲観的同時実行制御)の場合はどうなる?

※考察上 SQL 文の実行オーバーヘッドは無視します。

たとえば Aurora DSQL ではなく PostgreSQL を使うケースではどうなるか?を考えてみます。

といっても、同じ流れで処理する場合、一度の攻撃で 1 秒以上のロックが掛かり累積していく関係上、DB へのアクセスのタイムアウトが頻発してゲームにならないので、

  • ゲームが始まったら制限時間内に攻撃ボタンを押す
    • 押すと DSQL 上のテーブル行をUPDATE→ 1 秒待つ→COMMIT
    • 同時に複数の人が攻撃した場合、COMMITが成功した人が勝ち
      • 勝つとUPDATECOMMITの待ち時間が 1 秒増える(最大 5 秒まで)
      • 負けると 1 秒にリセット

の部分を、

  • ゲームが始まったら制限時間内に攻撃ボタンを押す
    • 押すと PostgreSQL 上のテーブル行を SELECT ... FOR UPDATE NOWAIT
      • エラーが出なければ(ロックが取れたら)勝ち
        • UPDATE→ 1 秒待つ→COMMIT
        • COMMITROLLBACK前の待ち時間が 1 秒増える(最大 5 秒まで)
      • エラーが出たら(ロックが取れなければ)負け
        • 待つ→ROLLBACK
        • COMMITROLLBACK前の待ち時間が 1 秒にリセット

に置き換えます。

すると、

No.	攻撃開始時刻          	攻撃成否	 参加者	待ち時間(秒)	コミット時刻	
 7	2025/07/05 13:45:29.282	  失敗 	 Xさん	      2   	2025/07/05 13:45:31.282	

が「失敗」から「成功」に変わります。待ち時間の間、他の並行トランザクション(No.2 〜 6)はロックが取れず、エラーになるからです。

そして、No.8 〜 23 は No.7(X さん)のロックに阻まれロックが取れずに失敗します。

OCC ではトランザクション時間が長いほど不利でしたが、PCC ではトランザクション時間が長いほうが有利になります。

しかし、その直後

24	2025/07/05 13:45:31.380	  失敗 	    	      1   	2025/07/05 13:45:32.380	

X さんのCOMMIT直後・終了直前の「すき間」に滑り込んで成功するので、勝者は No.24 の攻撃を行った参加者になります。

図示すると

こちらはこんな感じでしょうか。

image.png

というわけで

当日は資料の最終ページ↓を出し忘れたのですが、

image.png

通常の RDBMS とは異なる「Aurora DSQL ならではの特性」を理解した上で使いましょう!

8
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?