LoginSignup
1
0

More than 1 year has passed since last update.

MySQL vs. TiDB-分散トランザクションの比較検証(12): デッドロック(TiDB)

Last updated at Posted at 2022-05-21
[前回] MySQL vs. TiDB-分散トランザクションの比較検証(11): 同時実行制御(MySQL)

はじめに

今回は分散トランザクションのデッドロック検証です。
まずは、TiDBに対し実施します。

デッドロック(Deadlock)とは

Wikipediaから、デッドロック(deadlock)の定義

  • 2つ以上のスレッドあるいはプロセスなどの処理単位が、互いの処理終了を待ち
  • 結果として、どの処理も先に進めなくなってしまうこと

お互い相手の処理が終わるのを延々に待ち続けてしまう状態。。。
第3者がロック解除してあげないと埒が明かなくなりそうです。
TiDBは、デッドロックをどうように対処するでしょうか。

検証シナリオ

image.png

同時に、二つの分散トランザクションから振込みボタンが押された、といったシナリオです。
この際、デッドロックが起きるメカニズムの例です。
※ 更新処理の順序と対象が肝

  • 更新1: トランザクションAにより
    • A銀行残高レコードから10万円引く
    • レコードがロックされた状態
  • 更新2: トランザクションBにより
    • B銀行残高レコードから10万円引く
    • レコードがロックされた状態
  • 更新3: トランザクションAにより
    • B銀行残高レコードに10万円足す
    • 更新2によりレコードロック中のため、その解除を待つ。。。
  • 更新4: トランザクションBにより
    • A銀行残高レコードに10万円足す
    • 更新1によりレコードロック中のため、その解除を待つ。。。

お互い待ち続ける状態。。。

検証スタート

  • 端末を三つ用意します
    • 端末1: TiDBクラスタを起動
    • 端末2: トランザクションAを実行
    • 端末3: トランザクションBを実行

端末1から、TiDBクラスタを起動

$ tiup playground --db 2 --pd 3 --kv 3

端末2から、検証前準備

  • TiDBに接続
$ tiup client

Enterを押すと、コマンドプロンプトが表示されます。

my:root@127.0.0.1:4000=>
  • A銀行のデータベースと口座テーブルを作成

銀行データベース: a_bank
口座テーブル: account
を作成し、レコードをINSERT。
ユーザー: foo
残高: 50万円

CREATE DATABASE a_bank;
USE a_bank;
CREATE TABLE account(name VARCHAR(10) PRIMARY KEY, balance DECIMAL(10,2));
INSERT INTO account VALUES('foo', 500000);
COMMIT;
  • B銀行のデータベースと口座テーブルを作成

銀行データベース: b_bank
口座テーブル: account
を作成し、レコードをINSERT。
ユーザー: foo
残高: 50万円

CREATE DATABASE b_bank;
USE b_bank;
CREATE TABLE account(name VARCHAR(10) PRIMARY KEY, balance DECIMAL(10,2));
INSERT INTO account VALUES('foo', 500000);
COMMIT;
  • A、B銀行残高を確認
select * from a_bank.account;
 name |  balance  
------+-----------
 foo  | 500000.00 
(1 row)

select * from b_bank.account;
 name |  balance  
------+-----------
 foo  | 500000.00 
(1 row)

端末2のセッションから、トランザクションA開始

start transaction;
START TRANSACTION

A銀行残高レコードから10万円引く

update a_bank.account set balance=balance-100000 where name='foo';
UPDATE 1

端末3から、TiDBに接続

  • TiDBに接続
$ tiup client

Enterを押すと、コマンドプロンプトが表示されます。

my:root@127.0.0.1:4000=>

端末3のセッションから、トランザクションB開始

start transaction;
START TRANSACTION

B銀行残高レコードから10万円引く

update b_bank.account set balance=balance-100000 where name='foo';
UPDATE 1

端末2のセッションから、トランザクションAを続行

B銀行残高レコードに10万円足す

update b_bank.account set balance=balance+100000 where name='foo';
待ち状態。。。

トランザクションBにより、B銀行残高レコードがロック中のため、
そのロック解除待ちの状態。。。

端末3のセッションから、トランザクションBを続行

A銀行残高レコードに10万円足す

update a_bank.account set balance=balance+100000 where name='foo';
error: mysql: 1213: Deadlock found when trying to get lock; try restarting transaction

トランザクションAにより、A銀行残高レコードがロック中のため、
そのロック解除待ちの状態。。。
となり、Deadlockに陥ると思いきや、
すぐDeadlockが検出され、処理中断されました。

TiDBでは、Deadlockが起きても、延々にお互いを待ち続けることなく、
すぐエラーハンドリングしてくれました、すごい!

DEADLOCKS表から詳細情報を確認

select * from information_schema.deadlocks\G
*************************** 1. row ***************************
DEADLOCK_ID: 1
OCCUR_TIME: 2022-05-22T08:14:04.277036+09:00
RETRYABLE: 0
TRY_LOCK_TRX_ID: 433369837169541121
CURRENT_SQL_DIGEST: dc5f0aff8b925c386a79b6e33f64e79e814e2310a12f0d793fe9ab4c9c8c0eee
CURRENT_SQL_DIGEST_TEXT: update `b_bank` . `account` set `balance` = `balance` + ? where `name` = ? ;
KEY: 7480000000000000475F69800000000000000101666F6F0000000000FA
KEY_INFO: {"db_id":69,"db_name":"b_bank","table_id":71,"table_name":"account","index_id":1,"index_name":"PRIMARY","index_values":["foo"]}
TRX_HOLDING_LOCK: 433369847222763525
*************************** 2. row ***************************
DEADLOCK_ID: 1
OCCUR_TIME: 2022-05-22T08:14:04.277036+09:00
RETRYABLE: 0
TRY_LOCK_TRX_ID: 433369847222763525
CURRENT_SQL_DIGEST: 05704c1de71e0adc626cf220a7fbae005553d5ef74ed6bf44dec053cd656d474
CURRENT_SQL_DIGEST_TEXT: update `a_bank` . `account` set `balance` = `balance` + ? where `name` = ? ;
KEY: 7480000000000000435F69800000000000000101666F6F0000000000FA
KEY_INFO: {"db_id":65,"db_name":"a_bank","table_id":67,"table_name":"account","index_id":1,"index_name":"PRIMARY","index_values":["foo"]}
TRX_HOLDING_LOCK: 433369837169541121

デッドロックの詳細情報を確認できます。

  • 発生時間
  • ロック(待たせる側、待たされる側)
  • SQL文
  • レコードのキー情報

ここから、デッドロックの発生原因を特定でき、
再発防止策を立てられそうです。

終わりに

TiDBに対し、分散トランザクションのデッドロックを検証しました。
次回は、MySQLの番です。お楽しみに。

[次回] MySQL vs. TiDB-分散トランザクションの比較検証(13(最終回)): デッドロック(MySQL)
1
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
1
0