Spanner トランザクションには、同時実行制御のモードとして、 ペシミスティックとオプティミスティックの 2 つがあります。同時実行制御モードの選択は、トランザクションが同時読み取りと書き込みを処理する方法に影響し、パフォーマンス、レイテンシ、トランザクションの中止率に影響します。アプリケーションのパフォーマンスと整合性の要件に最適なモードを選択してください。
デフォルトの動作は、分離レベル トランザクションで使用するによって異なります。
- シリアル化可能な分離では、 デフォルトでペシミスティック同時実行制御が使用されます。
- 反復可能な読み取りの分離、 デフォルトでオプティミスティック同時実行制御が使用されます。
ペシミスティック同時実行制御
デフォルトでは、Spanner は シリアル化可能な分離でペシミスティック同時実行を使用します。反復可能な読み取りの分離で ペシミスティック同時実行を使用することもできます。
シリアル化可能な分離でのペシミスティック同時実行
このモードでは、同時実行トランザクションが同じデータを競合する可能性があることを前提としています。 トランザクション内でデータの読み取りまたは書き込みが行われると、データに対してロックを事前に取得します。また、トランザクションの早い段階で取得したロックが、後続のステートメントでも保持されていることを確認します。Spanner は、ロックの競合を検出すると、wound-wait アルゴリズムを使用して競合を解決します。
ペシミスティック同時実行では、トランザクションの実行フェーズと commit フェーズの両方で、トランザクションがデータのロックを取得します。
- 読み取りの場合: トランザクションがデータを読み取ると、実行フェーズで
共有読み取り(
ReaderShared)ロック を取得します。これらのロックは、トランザクションが commit されるまで保持されます。 - DML と書き込みの場合:
- 実行中に、DML または書き込みによって変更されたデータに対して、トランザクションが行の存在に対する読み取りロックを取得する場合があります。
- commit 時には、トランザクションは書き込まれたデータに対して書き込みロックまたは排他ロックを取得しようとします。書き込みロックは同時読み取りをブロックしますが、特に両方が書き込みロックを使用している場合は、同時書き込みをブロックしないことがあります。つまり、複数のトランザクションが commit に進むことができ、書き込み / 書き込みの競合は、wound-wait アルゴリズムを使用して commit 時に解決されます。すべてのロックは、トランザクションが commit されるまで保持されます。
反復可能な読み取りの分離でのペシミスティック同時実行
反復可能な読み取りの分離でペシミスティック同時実行を使用して、書き込みをシリアル化します。このモードでは、読み取りオペレーションはスナップショットを使用しますが、
排他ロック
はFOR UPDATE クエリまたは
lock_scanned_ranges=exclusive ヒントから読み取られたデータと、DML クエリで書き込まれたデータに適用されます。
シリアル化可能な分離でのペシミスティック同時実行のメリット
シリアル化可能な分離でペシミスティック同時実行を使用する主なメリットは、競合の多いワークロードでトランザクションの進行を支援できることです。Spanner は、競合時に新しいトランザクションよりも古いトランザクションを優先するため、トランザクションが最終的に完了し、繰り返し中止されるトランザクションの量を減らすことができます。
反復可能な読み取りの分離でのペシミスティック同時実行のメリット
反復可能な読み取りの分離では、ロックを取得したトランザクションが、FOR UPDATE を使用したクエリの一部として読み取られたデータ、または DML クエリの一部として読み取られたデータが、トランザクションの commit 前に同時実行トランザクションによって変更された場合、commit 時に中止される可能性があります。ただし、ロックを取得すると、トランザクションが commit
されるまで、それ以上の同時更新を防ぎ、書き込みをシリアル化します。
ペシミスティック同時実行のリスク
シリアル化可能な分離でのペシミスティック同時実行には、次のリスクがあります。
- 長時間実行される読み取りは、レイテンシの影響を受けやすい書き込みをブロックする可能性があります。
- 完了前にユーザー インタラクションを伴うトランザクションでは、ロックが長時間保持され、他のオペレーションがブロックされる可能性があります。
シリアル化可能な分離でのペシミスティック同時実行のユースケース
ペシミスティック同時実行は、読み取り / 書き込みと書き込み / 書き込みの競合が多いワークロードに適しています。トランザクションの中止と再試行にコストがかかる場合にも適しています。ワークロードで長時間ロックの遅延が過剰に発生する場合や、ロックの競合によって大きな影響を受ける場合を除き、このデフォルト モードを使用してください。
反復可能な読み取りの分離でのペシミスティック同時実行のユースケース
ロックを取得するために FOR UPDATE 句または DML クエリが必要なワークロードには、反復可能な読み取りでペシミスティック同時実行を使用します。このアプローチは、これらのステートメントのロックを取得する他のデータベースから
Spanner に移行されたワークロードに特に役立ちます。
オプティミスティック同時実行制御
Spanner には、オプティミスティック同時実行制御もあります。反復可能な読み取りの分離を使用する場合、デフォルト モードはオプティミスティック同時実行制御です。オプティミスティック同時実行制御を使用するようにシリアル化可能な分離を構成することもできます。
オプティミスティック同時実行制御は、競合がまれであることを前提としています。読み取り /
書き込みトランザクション内でも、読み取りとクエリはロックを取得せずに続行されます。
Spanner のデフォルトのシリアル化可能な分離では、読み取りは commit 時に検証されます。これにより、同時に commit された他のトランザクションが、トランザクションによって以前に読み取られたデータを変更しないようにします。反復可能な読み取りの分離を使用する場合、
またはヒントのいずれかを含む
読み取りは、FOR UPDATElock_scanned_ranges=exclusivecommit 時に
検証されます。Spanner は、競合を検出すると、トランザクションを中止します。
オプティミスティック同時実行の仕組み
オプティミスティック同時実行は、Spanner が読み取り、クエリ、トランザクションの commit を実行する方法を変更します。読み取りフェーズでロックフリー実行を行い、commit 時に整合性を検証します。
読み取りとクエリの場合
読み取りとクエリはロックフリーです。オプティミスティック トランザクション内のすべての読み取りとクエリは、単一のスナップショット タイムスタンプで実行されます。Spanner は、最初の読み取りまたはクエリが実行されるときにこのタイムスタンプを選択します。これにより、トランザクション内の後続の読み取りとクエリで、最初の読み取りまたはクエリの前に commit された書き込みが認識されます。
読み取りと書き込みの場合
読み取りと書き込みを行うオプティミスティック トランザクションの場合、Spanner は commit 時に検証ステップを実行します。競合が検出されず、次の条件が満たされた場合にのみ、トランザクションは正常に commit されます。
- 同時に commit された書き込みが、このトランザクションによって読み取られたデータと競合しない。つまり、読み取りタイムスタンプの後、このトランザクションが独自の書き込みを commit する前に、書き込みが commit されていない。
- 読み取りタイムスタンプ以降、スキーマが変更されていない。
分離レベルによって、検証される読み取りのセットが決まります。シリアル化可能な分離では、すべての読み取りが検証されます。反復可能な読み取りの分離では、
FOR UPDATE または lock_scanned_ranges=exclusive ヒントのいずれかを含む読み取りは
commit 時に検証されます。
競合が多い場合、オプティミスティック トランザクションは繰り返し中止される可能性があります。一方、ペシミスティック トランザクションは、古いトランザクションの commit を許可し、新しいトランザクションを再試行することで、読み取り / 書き込みの競合を解決します。
オプティミスティック同時実行のメリット
オプティミスティック同時実行には、次の利点があります。
- 読み取りはロックを取得しない: オプティミスティック トランザクションは読み取りのロックを取得しないため、長時間実行される読み取りはレイテンシの影響を受けやすい書き込みをブロックしません。
- 読み取り専用トランザクションの commit レイテンシの短縮: オプティミスティック トランザクション内のすべての読み取りは同じスナップショット タイムスタンプに基づいているため、これらの読み取りの実行時または commit 時に整合性を検証する必要がなく、レイテンシが大幅に短縮されます。
オプティミスティック同時実行のリスク
オプティミスティック同時実行には、特にシリアル化可能な分離で使用する場合、読み取り / 書き込みの競合が多い場合にリスクが生じます。ワークロードでシリアル化可能な分離でオプティミスティック同時実行制御を使用する前に、これらのリスクを理解してください。
- 読み取り / 書き込みの競合が多い場合、同時書き込みによってオプティミスティック トランザクションの読み取りが無効になる可能性があるため、オプティミスティック トランザクションの中止率が高くなる可能性があります。
- 競合が継続的に発生すると、トランザクションが繰り返し中止され、トランザクションの飢餓状態から commit されない可能性があります。
オプティミスティック同時実行のユースケース
オプティミスティック同時実行は、読み取り / 書き込みの競合が少ないトランザクション ワークロードに適しています。シリアル化可能なトランザクションの場合、トランザクションの中止を許容できるワークロードにもメリットがあります。
次のワークロードでは、オプティミスティック同時実行を検討してください。
- 長時間実行されるトランザクションを含む、優先度の低い、レイテンシ許容型のワークロード: 長時間実行される読み取りまたはクエリによって、レイテンシの影響を受けやすい書き込みが遅延する可能性がある場合は、オプティミスティック同時実行を使用します。これにより、読み取りロックによる遅延を回避できます。たとえば、接続が遅いモバイル クライアントのトランザクションや、多くの行または広い範囲の読み取りロックを保持する低 SLA トランザクションなどです。
- 読み取りレイテンシの影響を受けやすい、読み取り / 書き込みの競合が少ないトランザクション ワークロード: マルチリージョン構成では、オプティミスティック同時実行を使用して、読み取りをリージョンで処理し、読み取りレイテンシを短縮し、ホット スプリットへのスパイク状の読み取りトラフィックによる本番環境の問題を回避します。また、リーダーの過負荷または利用不可時の読み取り可用性も向上します。
- ほとんどのトランザクションが読み取り専用のトランザクション ワークロード: オプティミスティック同時実行に切り替えると、これらのワークロードで一般的な読み取り専用トランザクションの commit レイテンシが短縮されます。読み取り / 書き込みトランザクションの中止率が高くならないように、読み取り / 書き込みの競合を抑えてください。
読み取り / 書き込みの競合が頻繁に発生する、レイテンシの影響を受けやすいトランザクション ワークロードには、オプティミスティック同時実行を使用しないでください。
同時実行制御を構成する
Spanner クライアント ライブラリ、REST API、RPC API を使用して、読み取り / 書き込みトランザクションの同時実行モードを指定できます。
クライアント ライブラリ
Java
Go
Node.js
Python
C#
C++
REST
Spanner TransactionOptions
REST API の ReadWrite メッセージには ReadLockMode 列挙型があり、
PESSIMISTIC ロックモードまたは OPTIMISTIC ロックモードを選択できます。
RPC
Spanner Transactionoptions
RPC API の ReadWrite メッセージには ReadLockMode 列挙型があり、PESSIMISTIC ロックモードまたは OPTIMISTIC ロックモードを選択できます。
ドライバ
Spanner のドライバを使用して、接続レベルで接続パラメータとして read_lock_mode を設定するか、トランザクション レベルで SET ステートメント オプションとして設定できます。各ドライバの詳細については、
ドライバの概要をご覧ください。
次のステップ
- Spanner の分離レベルについて確認する。
- 反復可能な読み取りの分離を使用する方法を確認する。