TiDB悲観的トランザクションモード

TiDBの使用法を従来のデータベースに近づけ、移行のコストを削減するために、v3.0以降、TiDBは楽観的なトランザクションモデルに加えて悲観的なトランザクションモードをサポートしています。このドキュメントでは、TiDBペシミスティックトランザクションモードの機能について説明します。

ノート:

v3.0.8以降、新しく作成されたTiDBクラスターは、デフォルトでペシミスティックトランザクションモードを使用します。ただし、v3.0.7以前からv3.0.8以降にアップグレードした場合、これは既存のクラスタには影響しません。つまり、新しく作成されたクラスターのみがデフォルトで悲観的トランザクションモードを使用します

トランザクションモードの切り替え

tidb_txn_modeのシステム変数を構成することにより、トランザクションモードを設定できます。次のコマンドは、クラスタに新しく作成されたセッションによって実行されるすべての明示的なトランザクション(つまり、非自動コミットトランザクション)をペシミスティックトランザクションモードに設定します。

SET GLOBAL tidb_txn_mode = 'pessimistic';

次のSQLステートメントを実行して、ペシミスティックトランザクションモードを明示的に有効にすることもできます。

BEGIN PESSIMISTIC;
BEGIN /*T! PESSIMISTIC */;

BEGIN PESSIMISTIC;およびBEGIN OPTIMISTIC;ステートメントは、 tidb_txn_modeシステム変数よりも優先されます。これらの2つのステートメントで開始されたトランザクションは、システム変数を無視し、悲観的および楽観的なトランザクションモードの両方の使用をサポートします。

行動

TiDBのペシミスティックトランザクションは、MySQLのトランザクションと同様に動作します。 MySQLInnoDBとの違いの小さな違いを参照してください。

  • 悲観的なトランザクションの場合、TiDBはスナップショット読み取りと現在の読み取りを導入します。

    • スナップショット読み取り:トランザクションが開始する前にコミットされたバージョンを読み取る、ロックされていない読み取りです。 SELECTステートメントの読み取りはスナップショット読み取りです。
    • 現在の読み取り:最新のコミットされたバージョンを読み取るのはロックされた読み取りです。 UPDATE 、またはINSERTステートメントのSELECT FOR UPDATEは現在の読み取りDELETE

    次の例は、スナップショット読み取りと現在の読み取りの詳細な説明を提供します。

    セッション1セッション2セッション3
    CREATE TABLE t(INT);
    INSERT INTO T VALUES(1);
    悲観的に始める;
    UPDATE t SET a = a + 1;
    悲観的に始める;
    SELECT * FROM t; -スナップショット読み取りを使用して、現在のトランザクションが開始する前にコミットされたバージョンを読み取ります。結果はa=1を返します。
    悲観的に始める;
    SELECT * FROM t FOR UPDATE; -現在の読み取りを使用します。ロックを待ちます。
    専念; -ロックを解除します。セッション3のSELECTFORUPDATE操作はロックを取得し、TiDBは現在の読み取りを使用して最新のコミットされたバージョンを読み取ります。結果はa=2を返します。
    SELECT * FROM t; -スナップショット読み取りを使用して、現在のトランザクションが開始する前にコミットされたバージョンを読み取ります。結果はa=1を返します。
  • UPDATE 、またはDELETEステートメントを実行すると、最新のコミットされたデータが読み取られ、データが変更され、変更された行にペシミスティックロックが適用されINSERT

  • SELECT FOR UPDATEステートメントの場合、ペシミスティックロックは、変更された行ではなく、コミットされたデータの最新バージョンに適用されます。

  • トランザクションがコミットまたはロールバックされると、ロックが解除されます。データを変更しようとする他のトランザクションはブロックされ、ロックが解除されるのを待つ必要があります。 TiDBはマルチバージョン同時実行制御(MVCC)を使用しているため、データを読み取ろうとするトランザクションはブロックされません。

  • 複数のトランザクションが互いのそれぞれのロックを取得しようとすると、デッドロックが発生します。これは自動的に検出され、トランザクションの1つがランダムに終了し、MySQL互換のエラーコード1213が返されます。

  • トランザクションは、新しいロックを取得するために最大innodb_lock_wait_timeout秒(デフォルト:50)待機します。このタイムアウトに達すると、MySQL互換のエラーコード1205が返されます。複数のトランザクションが同じロックを待機している場合、優先順位はトランザクションのstart tsにほぼ基づいています。

  • TiDBは、同じクラスタで楽観的トランザクションモードと悲観的トランザクションモードの両方をサポートします。トランザクション実行にはどちらのモードも指定できます。

  • TiDBはFOR UPDATE NOWAIT構文をサポートし、ロックが解放されるのをブロックして待機しません。代わりに、MySQL互換のエラーコード3572が返されます。

  • Point GetBatch Point Getの演算子がデータを読み取らない場合でも、指定された主キーまたは一意のキーをロックします。これにより、他のトランザクションが同じ主キーまたは一意のキーにデータをロックまたは書き込むことができなくなります。

  • TiDBはFOR UPDATE OF TABLES構文をサポートしています。複数のテーブルを結合するステートメントの場合、TiDBはOF TABLESのテーブルに関連付けられている行にのみペシミスティックロックを適用します。

MySQLInnoDBとの違い

  1. TiDBがWHERE句で範囲を使用するDMLまたはSELECT FOR UPDATEステートメントを実行する場合、範囲内の同時DMLステートメントはブロックされません。

    例えば:

    CREATE TABLE t1 ( id INT NOT NULL PRIMARY KEY, pad1 VARCHAR(100) ); INSERT INTO t1 (id) VALUES (1),(5),(10);
    BEGIN /*T! PESSIMISTIC */; SELECT * FROM t1 WHERE id BETWEEN 1 AND 10 FOR UPDATE;
    BEGIN /*T! PESSIMISTIC */; INSERT INTO t1 (id) VALUES (6); -- blocks only in MySQL UPDATE t1 SET pad1='new value' WHERE id = 5; -- blocks waiting in both MySQL and TiDB

    この動作は、TiDBが現在ギャップロックをサポートしていないためです。

  2. TiDBはSELECT LOCK IN SHARE MODEをサポートしていません。

    SELECT LOCK IN SHARE MODEを実行すると、ロックなしの場合と同じ効果があるため、他のトランザクションの読み取りまたは書き込み操作がブロックされることはありません。

  3. DDLを使用すると、悲観的なトランザクションのコミットが失敗する可能性があります。

    MySQLでDDLを実行すると、実行中のトランザクションによってDDLがブロックされる可能性があります。ただし、このシナリオでは、DDL操作はTiDBでブロックされないため、悲観的なトランザクションコミットの失敗につながります: ERROR 1105 (HY000): Information schema is changed. [try again later] 。 TiDBは、トランザクションの実行中にTRUNCATE TABLEステートメントを実行するため、 table doesn't existエラーが発生する可能性があります。

  4. START TRANSACTION WITH CONSISTENT SNAPSHOTを実行した後でも、MySQLは他のトランザクションで後で作成されるテーブルを読み取ることができますが、TiDBは読み取ることができません。

  5. 自動コミットトランザクションは、楽観的ロックを優先します。

    悲観的モデルを使用する場合、自動コミットトランザクションは、最初に、オーバーヘッドの少ない楽観的モデルを使用してステートメントをコミットしようとします。書き込みの競合が発生した場合、ペシミスティックモデルがトランザクションの再試行に使用されます。したがって、 tidb_retry_limit0に設定されている場合でも、書き込みの競合が発生すると、自動コミットトランザクションはWrite Conflictエラーを報告します。

    SELECT FOR UPDATEステートメントはロックを待機しません。

  6. ステートメントでEMBEDDED SELECTによって読み取られたデータはロックされていません。

  7. TiDBで開いているトランザクションは、ガベージコレクション(GC)をブロックしません。デフォルトでは、これによりペシミスティックトランザクションの最大実行時間が1時間に制限されます。この制限は、TiDB構成ファイルの[performance]の下max-txn-ttlを編集することで変更できます。

分離レベル

TiDBは、ペシミスティックトランザクションモードで次の2つの分離レベルをサポートします。

パイプラインロックプロセス

ペシミスティックロックを追加するには、TiKVにデータを書き込む必要があります。ロックを正常に追加した場合の応答は、コミットしてRaftを介して適用した後にのみTiDBに返すことができます。したがって、楽観的なトランザクションと比較して、悲観的なトランザクションモードは必然的に待ち時間が長くなります。

ロックのオーバーヘッドを削減するために、TiKVはパイプラインロックプロセスを実装します。データがロックの要件を満たすと、TiKVはすぐにTiDBに後続の要求を実行するよう通知し、ペシミスティックロックに非同期で書き込みます。このプロセスにより、ほとんどの遅延が減少し、悲観的なトランザクションのパフォーマンスが大幅に向上します。ただし、ネットワークパーティションがTiKVで発生するか、TiKVノードがダウンしている場合、ペシミスティックロックへの非同期書き込みが失敗し、次の側面に影響を与える可能性があります。

  • 同じデータを変更する他のトランザクションをブロックすることはできません。アプリケーションロジックがロックまたはロック待機メカニズムに依存している場合、アプリケーションロジックの正確性が影響を受けます。

  • トランザクションのコミットが失敗する可能性は低いですが、トランザクションの正確性には影響しません。

アプリケーションロジックがロックまたはロック待機メカニズムに依存している場合、またはTiKVクラスタの異常の場合でもトランザクションコミットの成功率を可能な限り保証したい場合は、パイプラインロック機能を無効にする必要があります。

Pipelined pessimistic lock

この機能はデフォルトで有効になっています。これを無効にするには、TiKV構成を変更します。

[pessimistic-txn] pipelined = false

TiKVクラスタがv4.0.9以降の場合、この機能を動的に無効にすることもできTiKV構成をオンラインで変更する

set config tikv pessimistic-txn.pipelined='false';

このページは役に立ちましたか?