重要
このページは英語版のページを機械翻訳しています。原文はこちらからご覧ください。

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を使用すると、悲観的なトランザクションのコミットが失敗する可能性があります。

    DDLがMySQLで実行されると、実行中のトランザクションによってブロックされる可能性があります。ただし、このシナリオでは、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時間に制限されます。この制限は、 [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';

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

インメモリ悲観的ロック

v6.0.0では、TiKVはメモリ内のペシミスティックロックの機能を導入しています。この機能を有効にすると、ペシミスティックロックは通常、リージョンリーダーのメモリにのみ保存され、ディスクに永続化されたり、 Raftを介して他のレプリカに複製されたりすることはありません。この機能により、ペシミスティックロックを取得するオーバーヘッドを大幅に削減し、ペシミスティックトランザクションのスループットを向上させることができます。

インメモリペシミスティックロックのメモリ使用量がリージョンまたはTiKVノードのメモリしきい値を超えると、ペシミスティックロックの取得はパイプラインロックプロセスになります。リージョンがマージされるか、リーダーが転送されると、ペシミスティックロックの損失を回避するために、TiKVはメモリ内のペシミスティックロックをディスクに書き込み、他のレプリカに複製します。

インメモリペシミスティックロックは、パイプラインロックプロセスと同様に機能します。これは、クラスタが正常な場合のロック取得には影響しません。ただし、TiKVでネットワーク分離が発生した場合、またはTiKVノードがダウンした場合、取得したペシミスティックロックが失われる可能性があります。

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

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

[pessimistic-txn]
in-memory = false

この機能を動的に無効にするには、TiKV構成をオンラインで変更します。

set config tikv pessimistic-txn.in-memory='false';