1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

MySQL vs. TiDB-分散トランザクションの比較検証(9): TiDBで銀行振込みのシミュレーション

Last updated at Posted at 2022-05-13
[前回] MySQL vs. TiDB-分散トランザクションの比較検証(8): TiDB分散トランザクションの基本動作

はじめに

今回は、TiDB分散トランザクションの例として、銀行振込みのシミュレーションです。

検証シナリオ

分散トランザクションの例として、A銀行からB銀行へ振込みを行います。

image.png

分散トランザクションは、以下2操作で構成されます。

A銀行口座から10万円引出す
B銀行口座に10万円振込む

処理が二つのシステム(データベース)に分散され、
どちらか失敗しても、振込みは成立しません。

検証準備

端末を三つ用意します

端末1: TiDBクラスタを起動
端末2: TiDBトランザクションを実行
端末3: 別セッションからTiDBステータスを確認

端末1から

TiDBクラスタを起動

$ tiup playground --db 2 --pd 3 --kv 3
... ...
CLUSTER START SUCCESSFULLY, Enjoy it ^-^
To connect TiDB: mysql --comments --host 127.0.0.1 --port 4000 -u root -p (no password)
To connect TiDB: mysql --comments --host 127.0.0.1 --port 4001 -u root -p (no password)
To view the dashboard: http://127.0.0.1:2379/dashboard
PD client endpoints: [127.0.0.1:2379 127.0.0.1:2382 127.0.0.1:2384]
To view the Prometheus: http://127.0.0.1:9090
To view the Grafana: http://127.0.0.1:3000

端末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);

B銀行のデータベースとテーブルを作成

銀行データベース: b_bank
口座テーブル: account

レコードをINSERTします。

ユーザー: foo
残高: 0

CREATE DATABASE b_bank;
USE b_bank;
CREATE TABLE account(name VARCHAR(10) PRIMARY KEY, balance DECIMAL(10,2));
INSERT INTO account VALUES('foo', 0);

端末3から

TiDBに接続

$ tiup client

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

my:root@127.0.0.1:4000=>

A、B銀行の口座残高を確認

SELECT * FROM a_bank.account;
 name |  balance  
------+-----------
 foo  | 500000.00 
(1 row)
SELECT * FROM b_bank.account;
 name |  balance  
------+-----------
 foo  | 0.00 
(1 row)

検証スタート

端末2から

分散トランザクション開始

START TRANSACTION;
START TRANSACTION

A銀行から10万円引き出す

UPDATE a_bank.account SET balance=balance-100000 WHERE name='foo';
UPDATE 1

B銀行に10万円振り込む

UPDATE b_bank.account SET balance=balance+100000 WHERE name='foo';
UPDATE 1

トランザクションの同じセッションから、A、B銀行残高を確認

SELECT * FROM a_bank.account;
 name |  balance  
------+-----------
 foo  | 400000.00 
(1 row)

SELECT * FROM b_bank.account;
 name |  balance  
------+-----------
 foo  | 100000.00 
(1 row)

コミットしていないのに、残高変わったようです(?)。

トランザクションモードを確認

SELECT @@tidb_txn_mode;
 @@tidb_txn_mode 
-----------------
 pessimistic 
(1 row)

悲観的モードになっています。

トランザクションのステータスを確認

SELECT * FROM information_schema.tidb_trx\G
*************************** 1. row ***************************
ID: 433178055110295555
START_TIME: 2022-05-13T20:59:02.358+09:00
CURRENT_SQL_DIGEST:
CURRENT_SQL_DIGEST_TEXT:
STATE: Idle
WAITING_START_TIME:
MEM_BUFFER_KEYS: 4
MEM_BUFFER_BYTES: 182
SESSION_ID: 407
USER: root
DB: b_bank
ALL_SQL_DIGESTS: ["f53534242526f5f17dd442bf4429823244510563047efdcc0679741ca5833ea6","df9f53eb4cb1672927cb6374dd27fa80a8124ec0186f390ea41cac113d8428ac","dc5f0aff8b925c386a79b6e33f64e79e814e2310a12f0d793fe9ab4c9c8c0eee","28eafac12d18f34fb1bd6a857b73b37fb446d04eacbc3e18834f07ac9eb3c352","e82a3bae628989f0af1c7ce80dd40ddb0eb532f0e4f245e3f07280da22509428","c4ef5a83e75b42191d7e4e51ff33f5a712b8b41e743952a668b405076ce134ac","d7815f6adab7ceebe67882038b7d29c081675c0e94751110ff74213523b6998e"]

Idle状態になっています。

端末3から

トランザクションとは別セッションから、A、B銀行残高を確認

SELECT * FROM a_bank.account;
 name |  balance  
------+-----------
 foo  | 500000.00 
(1 row)

SELECT * FROM b_bank.account;
 name |  balance  
------+-----------
 foo  | 0.00 
(1 row)

残高が更新されていません。
分散トランザクションを開始したセッションのみ、残高が更新された理由は、
現時点で、分散トランザクションのステータスが、
第1フェーズの下書き(Prewrite)が終わっただけで、
第2フェーズのコミットはまだ行われていないからです。

端末2から

分散トランザクションをロールバック

ROLLBACK;
ROLLBACK

A、B銀行残高を確認

SELECT * FROM a_bank.account;
 name |  balance  
------+-----------
 foo  | 500000.00 
(1 row)

SELECT * FROM b_bank.account;
 name | balance 
------+---------
 foo  | 0.00 
(1 row)

残高が元とおりに戻りました。

トランザクションのステータスを確認

SELECT * FROM information_schema.tidb_trx\G

終了したので存在しません。

上記シナリオを再度実施し、コミット操作を確認

端末2から

分散トランザクション開始

START TRANSACTION;
START TRANSACTION

A銀行から10万円引き出す

UPDATE a_bank.account SET balance=balance-100000 WHERE name='foo';
UPDATE 1

B銀行に10万円振込む

UPDATE b_bank.account SET balance=balance+100000 WHERE name='foo';
UPDATE 1

コミット

COMMIT;
COMMIT

A、B銀行残高を確認

SELECT * FROM a_bank.account;
 name |  balance  
------+-----------
 foo  | 400000.00 
(1 row)

SELECT * FROM b_bank.account;
 name |  balance  
------+-----------
 foo  | 100000.00 
(1 row)

期待とおり口座振込みできました。
分散トランザクション成功、やったー。

トランザクションのステータスを確認

SELECT * FROM information_schema.tidb_trx\G

終了したので存在しません。

端末3から

トランザクションとは別セッションからも、A、B銀行残高を確認

SELECT * FROM a_bank.account;
 name |  balance  
------+-----------
 foo  | 400000.00 
(1 row)

SELECT * FROM b_bank.account;
 name |  balance  
------+-----------
 foo  | 100000.00 
(1 row)

別セッションからも、期待とおり残高更新が確認できました。

分散トランザクションにおける TiDB vs. MySQL

スナップショットの取得タイミングが異なる

  • TiDB
    • BEGINSTART TRANSACTIONでトランザクション開始直後に
    • データベースのスナップショットを取得
  • MySQL
    • BEGINSTART TRANSACTIONでトランザクション開始後
    • InnoDBからデータ取得する最初のSELECT(SELECT FOR UPDATEは対象外)が実行されたら
    • スナップショットを取得

言い換えると、TiDBの下記三つのコマンドは、

  • BEGIN
  • START TRANSACTION
  • START TRANSACTION WITH CONSISTENT SNAPSHOT

MySQLの下記コマンドに相当

  • START TRANSACTION WITH CONSISTENT SNAPSHOT

TiDBの一意制約レイジーチェックの最適化

  • Lazy check of constraintsとは
    • TiDBの楽観的トランザクションで
    • プライマリキーや一意制約のチェックを
    • COMMIT時に行う(通常のDML実行時でなく)
  • メリット
    • 制約チェックをバッチ処理し
    • ネットワーク通信を減らすことで
    • パフォーマンスを向上できる
  • デフォルト設定の変更
    • パラメータtidb_constraint_check_in_placeTRUEに設定すると
    • 本機能が無効に

終わりに

TiDB分散トランザクション例を用いて、MySQL XAと比較しました。
次回は、分散トランザクションの同時実行制御を検証してみます。
お楽しみに。

[次回] MySQL vs. TiDB-分散トランザクションの比較検証(10): 同時実行制御(TiDB)
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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?