デッドロック

DEADLOCKSは、現在の TiDB ノードで最近発生したいくつかのデッドロック エラーの情報を示しています。

USE information_schema; DESC deadlocks;
+-------------------------+---------------------+------+------+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------------------+---------------------+------+------+---------+-------+ | DEADLOCK_ID | bigint(21) | NO | | NULL | | | OCCUR_TIME | timestamp(6) | YES | | NULL | | | RETRYABLE | tinyint(1) | NO | | NULL | | | TRY_LOCK_TRX_ID | bigint(21) unsigned | NO | | NULL | | | CURRENT_SQL_DIGEST | varchar(64) | YES | | NULL | | | CURRENT_SQL_DIGEST_TEXT | text | YES | | NULL | | | KEY | text | YES | | NULL | | | KEY_INFO | text | YES | | NULL | | | TRX_HOLDING_LOCK | bigint(21) unsigned | NO | | NULL | | +-------------------------+---------------------+------+------+---------+-------+

DEADLOCKSテーブルは複数の行を使用して同じデッドロック イベントを表示し、各行にはデッドロック イベントに関係するトランザクションの 1 つに関する情報が表示されます。 TiDB ノードが複数のデッドロック エラーを記録する場合、各エラーはDEADLOCK_ID列を使用して区別されます。同じDEADLOCK_IDは、同じデッドロック イベントを示します。 DEADLOCK_IDはグローバルな一意性を保証せず、永続化されないことに注意してください。同じ結果セット内の同じデッドロック イベントのみが表示されます。

DEADLOCKSテーブルの各列フィールドの意味は次のとおりです。

  • DEADLOCK_ID : デッドロック イベントの ID。テーブルに複数のデッドロック エラーが存在する場合、この列を使用して、異なるデッドロック エラーに属する行を区別できます。
  • OCCUR_TIME : デッドロック エラーが発生した時刻。
  • RETRYABLE : デッドロック エラーをリトライできるかどうか。再試行可能なデッドロック エラーの説明については、セクション再試行可能なデッドロック エラーを参照してください。
  • TRY_LOCK_TRX_ID : ロックを取得しようとするトランザクションの ID。この ID はトランザクションのstart_tsでもあります。
  • CURRENT_SQL_DIGEST : 排他獲得トランザクションで現在実行中のSQL文のダイジェスト。
  • CURRENT_SQL_DIGEST_TEXT : ロックを取得するトランザクションで現在実行されている SQL ステートメントの正規化された形式。
  • KEY : トランザクションがロックしようとするブロックされたキー。このフィールドの値は、16 進文字列の形式で表示されます。
  • KEY_INFO : KEYの詳細情報。 キー情報節を参照してください。
  • TRX_HOLDING_LOCK : 現在キーのロックを保持しており、ブロックを引き起こしているトランザクションの ID。この ID はトランザクションのstart_tsでもあります。

DEADLOCKSテーブルに記録できるデッドロック イベントの最大数を調整するには、TiDB 構成ファイルのpessimistic-txn.deadlock-history-capacity構成を調整します。デフォルトでは、最近の 10 件のデッドロック イベントの情報がテーブルに記録されます。

KEY_INFO

KEY_INFO列目はKEY列目の詳細情報を示します。情報は JSON 形式で表示されます。各フィールドの説明は次のとおりです。

  • "db_id" : キーが属するスキーマの ID。
  • "db_name" : キーが属するスキーマの名前。
  • "table_id" : キーが属するテーブルの ID。
  • "table_name" : キーが属するテーブルの名前。
  • "partition_id" : キーが配置されているパーティションの ID。
  • "partition_name" : キーが配置されているパーティションの名前。
  • "handle_type" : 行キー (つまり、データ行を格納するキー) のハンドル型。可能な値は次のとおりです。
    • "int" : ハンドル タイプは int です。これは、ハンドルが行 ID であることを意味します。
    • "common" : ハンドル型は int64 ではありません。この型は、クラスター化インデックスが有効になっている場合、int 以外の主キーに表示されます。
    • "unknown" : ハンドル タイプは現在サポートされていません。
  • "handle_value" : ハンドル値。
  • "index_id" : インデックス キー (インデックスを格納するキー) が属するインデックス ID。
  • "index_name" : インデックス キーが属するインデックスの名前。
  • "index_values" : インデックス キーのインデックス値。

上記のフィールドで、フィールドの情報が該当しない場合、または現在利用できない場合、そのフィールドはクエリ結果で省略されます。たとえば、行キー情報にはindex_idindex_name 、およびindex_valuesは含まれません。インデックス キーにhandle_typehandle_valueが含まれていません。パーティション化されていないテーブルにはpartition_idpartition_nameは表示されません。削除されたテーブルのキー情報は、 table_namedb_iddb_name 、およびindex_nameなどのスキーマ情報を取得できず、テーブルが分割されたテーブルであるかどうかを区別できません。

ノート:

パーティショニングが有効になっているテーブルからキーが取得され、クエリ中に何らかの理由 (たとえば、キーが属するテーブルが削除されたなど) でキーが属するスキーマの情報をクエリできない場合、IDキーが属するパーティションの番号がtable_idフィールドに表示される場合があります。これは、TiDB が複数の独立したテーブルのキーをエンコードするのと同じ方法で、異なるパーティションのキーをエンコードするためです。したがって、スキーマ情報が欠落している場合、TiDB は、キーがパーティション化されていないテーブルに属しているか、テーブルの 1 つのパーティションに属しているかを確認できません。

再試行可能なデッドロック エラー

ノート:

DEADLOCKSテーブルは、デフォルトでは再試行可能なデッドロック エラーの情報を収集しません。テーブルで再試行可能なデッドロック エラー情報を収集する場合は、TiDB 構成ファイルで値pessimistic-txn.deadlock-history-collect-retryableを調整できます。

トランザクション A がトランザクション B によって既に保持されているロックによってブロックされ、トランザクション B が現在のトランザクション A によって保持されているロックによって直接的または間接的にブロックされている場合、デッドロック エラーが発生します。このデッドロックでは、次の 2 つのケースが考えられます。

  • ケース 1: トランザクション B は、トランザクション A の開始後、トランザクション A がブロックされる前に実行されたステートメントによって生成されたロックによって (直接的または間接的に) ブロックされる可能性があります。
  • ケース 2: トランザクション A で現在実行されているステートメントによって、トランザクション B もブロックされる可能性があります。

ケース 1 では、TiDB はトランザクション A のクライアントにデッドロック エラーを報告し、トランザクションを終了します。

ケース 2 では、トランザクション A で現在実行されているステートメントが、TiDB で自動的に再試行されます。たとえば、トランザクション A が次のステートメントを実行するとします。

update t set v = v + 1 where id = 1 or id = 2;

トランザクション B は、次の 2 つのステートメントを連続して実行します。

update t set v = 4 where id = 2; update t set v = 2 where id = 1;

次に、トランザクション A がid = 1id = 2で 2 つの行をロックすると、2 つのトランザクションは次の順序で実行されます。

  1. トランザクション A は行をid = 1でロックします。
  2. トランザクション B は最初のステートメントを実行し、行をid = 2でロックします。
  3. トランザクション B は 2 番目のステートメントを実行し、行をid = 1でロックしようとしますが、これはトランザクション A によってブロックされます。
  4. トランザクション A は行をid = 2でロックしようとしますが、トランザクション B によってブロックされ、デッドロックが形成されます。

この場合、他のトランザクションをブロックしているトランザクション A のステートメントは、現在実行中のステートメントでもあるため、現在のステートメントのペシミスティック ロックを解決して (トランザクション B を実行し続けることができるように)、現在のステートメントを再試行できます。 . TiDB はキー ハッシュを内部的に使用して、これが該当するかどうかを判断します。

再試行可能なデッドロックが発生した場合、内部の自動再試行によってトランザクション エラーが発生しないため、クライアントに対して透過的です。ただし、この状況が頻繁に発生すると、パフォーマンスに影響が出る可能性があります。これが発生すると、TiDB ログにsingle statement deadlock, retry statementが表示されます。

例 1

テーブル定義と初期データは次のとおりであるとします。

create table t (id int primary key, v int); insert into t values (1, 10), (2, 20);

2 つのトランザクションは、次の順序で実行されます。

取引1トランザクション 2説明
update t set v = 11 where id = 1;
update t set v = 21 where id = 2;
update t set v = 12 where id = 2;トランザクション 1 がブロックされます。
update t set v = 22 where id = 1;トランザクション 2 は、デッドロック エラーを報告します。

次に、トランザクション 2 がデッドロック エラーを報告します。この時点で、 DEADLOCKSのテーブルに対してクエリを実行します。

select * from information_schema.deadlocks;

予想される出力は次のとおりです。

+-------------+----------------------------+-----------+--------------------+------------------------------------------------------------------+-----------------------------------------+----------------------------------------+----------------------------------------------------------------------------------------------------+--------------------+ | DEADLOCK_ID | OCCUR_TIME | RETRYABLE | TRY_LOCK_TRX_ID | CURRENT_SQL_DIGEST | CURRENT_SQL_DIGEST_TEXT | KEY | KEY_INFO | TRX_HOLDING_LOCK | +-------------+----------------------------+-----------+--------------------+------------------------------------------------------------------+-----------------------------------------+----------------------------------------+----------------------------------------------------------------------------------------------------+--------------------+ | 1 | 2021-08-05 11:09:03.230341 | 0 | 426812829645406216 | 22230766411edb40f27a68dadefc63c6c6970d5827f1e5e22fc97be2c4d8350d | update `t` set `v` = ? where `id` = ? ; | 7480000000000000355F728000000000000002 | {"db_id":1,"db_name":"test","table_id":53,"table_name":"t","handle_type":"int","handle_value":"2"} | 426812829645406217 | | 1 | 2021-08-05 11:09:03.230341 | 0 | 426812829645406217 | 22230766411edb40f27a68dadefc63c6c6970d5827f1e5e22fc97be2c4d8350d | update `t` set `v` = ? where `id` = ? ; | 7480000000000000355F728000000000000001 | {"db_id":1,"db_name":"test","table_id":53,"table_name":"t","handle_type":"int","handle_value":"1"} | 426812829645406216 | +-------------+----------------------------+-----------+--------------------+------------------------------------------------------------------+-----------------------------------------+----------------------------------------+----------------------------------------------------------------------------------------------------+--------------------+

DEADLOCKSつのテーブルに 2 行のデータが生成されます。両方の行のDEADLOCK_IDフィールドは1です。これは、両方の行の情報が同じデッドロック エラーに属することを意味します。最初の行は、キー"7480000000000000355F728000000000000002"で、ID "426812829645406216"のトランザクションが ID "426812829645406217"のトランザクションによってブロックされていることを示しています。 2行目は、 "7480000000000000355F728000000000000001"のキー上で、 426812829645406216のトランザクションが"426812829645406217"のトランザクションによってブロックされ、相互ブロッキングとなり、デッドロックを形成していることを示している。

例 2

DEADLOCKSテーブルに対してクエリを実行し、次の結果が得られたとします。

+-------------+----------------------------+-----------+--------------------+------------------------------------------------------------------+-----------------------------------------+----------------------------------------+----------------------------------------------------------------------------------------------------+--------------------+ | DEADLOCK_ID | OCCUR_TIME | RETRYABLE | TRY_LOCK_TRX_ID | CURRENT_SQL_DIGEST | CURRENT_SQL_DIGEST_TEXT | KEY | KEY_INFO | TRX_HOLDING_LOCK | +-------------+----------------------------+-----------+--------------------+------------------------------------------------------------------+-----------------------------------------+----------------------------------------+----------------------------------------------------------------------------------------------------+--------------------+ | 1 | 2021-08-05 11:09:03.230341 | 0 | 426812829645406216 | 22230766411edb40f27a68dadefc63c6c6970d5827f1e5e22fc97be2c4d8350d | update `t` set `v` = ? where `id` = ? ; | 7480000000000000355F728000000000000002 | {"db_id":1,"db_name":"test","table_id":53,"table_name":"t","handle_type":"int","handle_value":"2"} | 426812829645406217 | | 1 | 2021-08-05 11:09:03.230341 | 0 | 426812829645406217 | 22230766411edb40f27a68dadefc63c6c6970d5827f1e5e22fc97be2c4d8350d | update `t` set `v` = ? where `id` = ? ; | 7480000000000000355F728000000000000001 | {"db_id":1,"db_name":"test","table_id":53,"table_name":"t","handle_type":"int","handle_value":"1"} | 426812829645406216 | | 2 | 2021-08-05 11:09:21.252154 | 0 | 426812832017809412 | 22230766411edb40f27a68dadefc63c6c6970d5827f1e5e22fc97be2c4d8350d | update `t` set `v` = ? where `id` = ? ; | 7480000000000000355F728000000000000002 | {"db_id":1,"db_name":"test","table_id":53,"table_name":"t","handle_type":"int","handle_value":"2"} | 426812832017809413 | | 2 | 2021-08-05 11:09:21.252154 | 0 | 426812832017809413 | 22230766411edb40f27a68dadefc63c6c6970d5827f1e5e22fc97be2c4d8350d | update `t` set `v` = ? where `id` = ? ; | 7480000000000000355F728000000000000003 | {"db_id":1,"db_name":"test","table_id":53,"table_name":"t","handle_type":"int","handle_value":"3"} | 426812832017809414 | | 2 | 2021-08-05 11:09:21.252154 | 0 | 426812832017809414 | 22230766411edb40f27a68dadefc63c6c6970d5827f1e5e22fc97be2c4d8350d | update `t` set `v` = ? where `id` = ? ; | 7480000000000000355F728000000000000001 | {"db_id":1,"db_name":"test","table_id":53,"table_name":"t","handle_type":"int","handle_value":"1"} | 426812832017809412 | +-------------+----------------------------+-----------+--------------------+------------------------------------------------------------------+-----------------------------------------+----------------------------------------+----------------------------------------------------------------------------------------------------+--------------------+

上記のクエリ結果のDEADLOCK_ID列は、最初の 2 行が一緒になってデッドロック エラーの情報を表し、互いに待機する 2 つのトランザクションがデッドロックを形成していることを示しています。次の 3 つの行は一緒に、別のデッドロック エラーの情報を表し、サイクル内で待機する 3 つのトランザクションがデッドロックを形成します。

CLUSTER_DEADLOCKS

CLUSTER_DEADLOCKSテーブルは、クラスター全体の各 TiDB ノードの最近のデッドロック エラーに関する情報を返します。これは、各ノードのDEADLOCKSテーブルの情報を組み合わせたものです。 CLUSTER_DEADLOCKSには、ノードの IP アドレスとポートを表示して異なる TiDB ノードを区別するための追加のINSTANCE列も含まれています。

DEADLOCK_IDはグローバルな一意性を保証しないため、 CLUSTER_DEADLOCKSテーブルのクエリ結果では、 INSTANCEDEADLOCK_IDを一緒に使用して、結果セット内のさまざまなデッドロック エラーの情報を区別する必要があることに注意してください。

USE information_schema; DESC cluster_deadlocks;
+-------------------------+---------------------+------+------+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------------------+---------------------+------+------+---------+-------+ | INSTANCE | varchar(64) | YES | | NULL | | | DEADLOCK_ID | bigint(21) | NO | | NULL | | | OCCUR_TIME | timestamp(6) | YES | | NULL | | | RETRYABLE | tinyint(1) | NO | | NULL | | | TRY_LOCK_TRX_ID | bigint(21) unsigned | NO | | NULL | | | CURRENT_SQL_DIGEST | varchar(64) | YES | | NULL | | | CURRENT_SQL_DIGEST_TEXT | text | YES | | NULL | | | KEY | text | YES | | NULL | | | KEY_INFO | text | YES | | NULL | | | TRX_HOLDING_LOCK | bigint(21) unsigned | NO | | NULL | | +-------------------------+---------------------+------+------+---------+-------+