MySQL vs. TiDB-分散トランザクションの比較検証(7): TiDB分散トランザクションの理論

##### [前回] [MySQL vs. TiDB-分散トランザクションの比較検証(6): TiDBクラスタの導入](https://qiita.com/mingchun_zhao/items/8965b27fdfce7caf58e6)

## はじめに

TiDBの分散トランザクションを勉強します。

## TiDBトランザクションのフロー

- 1\. トランザクション開始
    - クライアントが、`Timestamp Oracle`(TSO)から現在のタイムスタンプ`startTS`を取得
    - TSOはタイムスタンプの単調増加を保証するため、startTSを使用しトランザクションの時系列を識別できる
- 2\. トランザクション処理
    - 読み取り操作
        - RPC要求をstartTSと一緒にTiKVに送信
        - TiKVはMVCC(MultiVersion Concurrency Control)を使用し、startTSより前に書き込まれたデータを確実に返す
            - ※ MVCCの説明は後続
    - 書き込み操作
        - TiKVは楽観的並行性制御を使用し、現在のトランザクションが他のトランザクションに影響を与えないと仮定する
            - ※ 楽観的並行性制御の説明は後続
        - データはサーバーに書き込まれず、クライアント側にキャッシュされる
- 3\. トランザクションコミット
    - TiKVは2PC(2フェーズコミット)アルゴリズムを使用するが、通常の2PCと差異あり
        - 独立したトランザクションマネージャーが存在せず
        - コミット状態を、コミット対象キーから選択されたPrimaryKeyのコミット状態によって判断
    - コミットの詳細フェーズ
        - 1\) 下書き(Prewrite)開始
            - クライアントが、複数TiKVサーバーに書き込み対象データを送信
            - データがサーバーに保存されると、サーバーは該当キーをロック済みに設定
                - トランザクションのPrimaryKeyを記録
            - いずれかのノードで書き込み競合が発生した場合
                - トランザクションは中止されロールバックされる
        - 2\) 下書き(Prewrite)終了
            - 新しいタイムスタンプをTSOから取得し、commitTSとして設定
        - 3\) コミット(Commit)
            - PrimaryKeyを使用し、リクエストをTiKVサーバに送信
            - TiKVがコミットを処理するプロセス
                - PrimaryKeyロックをクリーンアップ
                - 該当コミットレコードをcommitTSと一緒に書き込む
                - PrimaryKeyコミット終了し、トランザクションがコミットされる
                - 他のロック中のキーは、Primarykey状態により、コミット状態と当該commitTSを取得
                    - ※ ロッククリーンアップのコスト削減のため、トランザクションのすべての関連キーをバックエンドで非同期にサブミット

### MVCCとは

Wikipediaの[MultiVersion Concurrency Control(MVCC, マルチバージョン・コンカレンシー・コントロール)](https://ja.wikipedia.org/wiki/MultiVersion_Concurrency_Control)から、

- MVCCとは
    - データベース管理システムの可用性を向上させる制御技術
    - 複数ユーザからの同時処理要求に対し、同時並行性と整合性を保証する仕組み
- MVCCのメリット
    - 書き込み処理(トランザクション)中に、他のユーザによる読み取りアクセスがあった場合
    - 書き込みの直前の状態(スナップショット)を処理結果として返す
    - よって、書き込み中に読み取りができ、読み取り中も書き込みができる
- MVCCの可用性を達成するには
    - 最低限、全ての処理が`どの順番`で行われたかを確実に記録する必要あり
    - そのため、全ての更新処理が、タイムスタンプ/トランザクションIDなどを用いて制御される

## 楽観的並行性制御とは

Wikipediaの[楽観的並行性制御(optimistic concurrency control)](https://ja.wikipedia.org/wiki/%E6%A5%BD%E8%A6%B3%E7%9A%84%E4%B8%A6%E8%A1%8C%E6%80%A7%E5%88%B6%E5%BE%A1)から、

- 並列制御(ロック)手段の一種で、楽観的ロックの概念
- 他と競合してはならないトランザクションにおいて
    - 開始時、他との競合を気にせず(楽観的)、排他処理を行なわない
    - 更新処理完了時、他からも更新処理があったかを確認
        - 更新ありの場合、自分の更新処理を破棄、エラーを返す
        - 更新なしの場合、自分の更新処理を実施、OKを返す
- [TiDBの楽観的トランザクション](https://docs.pingcap.com/tidb/stable/troubleshoot-lock-conflicts#optimistic-transaction-mode)(※ PingCAP社のドキュメントから引用)

<img align="middle" width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/ad2244fd-7aaf-96f0-b4a1-9aed05c3ecd3.png">

## 悲観的並行性制御とは
 
Wikipediaの[悲観的並行性制御(pessimistic concurrency control)](https://ja.wikipedia.org/wiki/%E6%82%B2%E8%A6%B3%E7%9A%84%E4%B8%A6%E8%A1%8C%E6%80%A7%E5%88%B6%E5%BE%A1)から、

- 並列制御(ロック)手段の一種で、悲観的ロックの概念
- 他と競合してはならないトランザクションにおいて
    - 開始時、他の更新処理と競合しないかロック確認
        - ロックありの場合、解除されるまで待機するか、エラーを返し処理をあきらめる
        - ロックなしの場合、他から更新できないようにロックをかける(排他制御)
    - 更新処理完了時、ロック解除
- [TiDBの悲観的トランザクション](https://docs.pingcap.com/tidb/stable/troubleshoot-lock-conflicts#pessimistic-transaction-mode)(※ PingCAP社のドキュメントから引用)

<img align="middle" width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/b9848976-8850-120f-c0ff-1982dc6c5f38.png">

## TiDB分散トランザクションの理解に役立つ文章

- [トランザクジョンのコマンド構文](https://docs.pingcap.com/tidb/stable/transaction-overview)
- [分散アルゴリズムとロックの仕組み](https://tikv.github.io/deep-dive-tikv/distributed-transaction/introduction.html)
- [下書き(Prewrite)フェーズの詳細](https://pingcap.com/blog/tikv-prewrite-request-life-story)
- [TiKVトランザクションのディープダイブ](https://pingcap.com/blog/deep-dive-into-tikv#transaction)


## 終わりに

TiDB分散トランザクションの理論を勉強しました。
次回は、TiDB分散トランザクションの検証です。
お楽しみに。

##### [次回] [TiDB-分散トランザクションの比較検証(8): TiDB分散トランザクションの基本動作](https://qiita.com/mingchun_zhao/items/182173b869e01777ed8d)