1.トランザクション同時実行制御の原則の概要
1.1同時実行制御
の理由データベースは共有リソースであり、通常、同時に実行されるトランザクションは多数あります。複数のトランザクションが同時にデータベースにアクセスする場合、同じデータが同時に読み取られたり変更されたりします。並行操作が制御されていない場合、誤ったデータにアクセスして保存し、データベースの整合性を損なう可能性があります。したがって、データベース管理システムは同時実行制御メカニズムを提供する必要があります。
下の図のt6での左側のトランザクションT2の書き込み操作W(A)は、時刻t5でのトランザクションT1の書き込み操作を上書きし、トランザクションT1の更新を失います。下の図の右側のトランザクションT2は次のようになります。トランザクションT1によってロールバックされた書き込み操作。このデータは無効であり、ダーティリードと呼ばれます。さらに、トランザクションの同時実行により、繰り返し不可能な読み取り、ファントム読み取り、読み取りと書き込みの半順序などの問題も発生しますが、ここでは紹介しません。
図1左は更新の損失、右はダーティリード
リソースの使用率とトランザクションの実行効率を向上させ、応答時間を短縮するために、データベースではトランザクションの同時実行が可能です。ただし、複数のトランザクションが同時に同じオブジェクトで動作する場合は、競合が発生する必要があります。トランザクションの中間状態が他のトランザクションに公開され、一部のトランザクションが中間状態に応じてデータベースに誤った値を書き込む可能性があります他のトランザクションの。トランザクションの実行が同時トランザクションの影響を受けないようにするメカニズムを提供する必要があります。これにより、ユーザーは、自分で開始したトランザクションのみが現在実行されていると感じます。これは分離です。分離にはトランザクションの実行順序に関する高い要件があるため、多くのデータベースはさまざまなオプションを提供し、ユーザーは分離の一部を犠牲にしてシステムパフォーマンスを向上させることができます。これらの異なるオプションは、トランザクション分離レベルです。トランザクションの分離レベルは、一般に、低いものから高いものまで、コミットされていない読み取り、コミットされた読み取り、繰り返し可能な読み取り、およびシリアル化の4つに分けられます。最終的な目標は、時系列で実行することによってデータベースの整合性を損なうことを回避するために、合理的な順序で同時に実行されるトランザクションに対して論理的にシリアルな操作を実行することです。
図2並行操作のシリアル実行シーケンス
1.2一般的な同時実行制御方法
一般的な同時実行制御方法には、ロック、タイムスタンプ、有効性チェック、スナップショット、およびマルチバージョンメカニズムが含まれます。ここでは、Yunxiデータベースに関連するいくつかの同時実行制御を紹介します。
1.2.1ロック
データベーストランザクションの同時機能を最大化するために、データベースのロックは、共有ロックとミューテックスロックの2つのモードで設計されています。トランザクションが共有ロックを取得する場合、読み取り操作のみを実行できるため、共有ロックは読み取りロックとも呼ばれます。トランザクションがデータ行のミューテックスロックを取得する場合、トランザクションはデータ行の読み取りと書き込みを行うことができます。したがって、相互排除ロックは書き込みロックとも呼ばれます。現在のトランザクションがデータの行に対応するロックを取得する方法がない場合、他のトランザクションが現在のデータに対応するロックを解放するまで待機状態になり、ロックを取得して対応する操作を実行できます。 。
図3相互排除ロックと共有ロックの互換性
Two-Phase Locking Protocol(2PL)は、トランザクションの直列化可能性を保証するプロトコルであり、トランザクションのロックの取得と解放を、成長と縮小の2つの異なるフェーズに分割します。成長フェーズでは、トランザクションはロックを取得できますが、ロックを解放できません。縮小フェーズでは、トランザクションはロックのみを解放でき、新しいロックを取得できません。
マルチスレッドプログラミングではデッドロックが発生することがよくあります。リソースの競合に複数のスレッドが関与した場合、現在のスレッドまたはトランザクションがデッドロックを引き起こすかどうかを検討する必要があります。有向待機グラフがループを生成するかどうかによって、そうでないかどうかを判断できます。デッドロックが発生します。デッドロックから回復する方法は実際には非常に簡単です。最も一般的な解決策は、リング全体でトランザクションを選択してロールバックし、待機グラフ全体のサイクルを中断することです。
図4デッドロックの生成
1.2.2タイムスタンプ
各トランザクションにタイムスタンプを割り当て、これを使用してトランザクションが実行される順序を決定します。トランザクション1のタイムスタンプがトランザクション2のタイムスタンプよりも短い場合、データベースシステムは、トランザクション1がトランザクション2の前にT / Oベースの同時実行制御を実行することを確認する必要があります。読み取りと書き込みにロックは不要で、レコードの各行にマークが付けられます。最後に変更して読み取ったトランザクションのタイムスタンプ。トランザクションのタイムスタンプが記録されたタイムスタンプよりも小さい場合(「将来の」データを読み取ることができない場合)、中止後に再実行する必要があります。レコードXに読み取りと書き込みの2つのタイムスタンプ(WTS(X)とRTS(X))がマークされているとすると、トランザクションのタイムスタンプはTTSであり、可視性は次のように判断されます。
読み取り:
TTS <WTS(X):オブジェクトはトランザクションに表示されず、トランザクションを中止し、新しいタイムスタンプで最初からやり直します。
TTS> WTS(X):オブジェクトはトランザクションに表示されます。RTS(X)= max(TTS、RTS(X))を更新します。繰り返し可能な読み取りを満たすために、トランザクションはXの値を複製します。
書き込み:
TTS <WTS(X)|| TTS <RTS(X):トランザクションを中止し、最初からやり直します。
TTS> WTS(X)&& TTS> RTS(X):トランザクション更新X、WTS(X)=TTS。
その欠点は次のとおりです。長いトランザクションのタイムスタンプが小さいため、長いトランザクションは餓死しやすく、実行期間後に更新されたデータが読み取られて中止される可能性が高くなります。読み取り操作でも書き込みが生成されます。 (RTSを記述します)。
1.2.3マルチバージョン同時実行制御
データベースは、レコードの複数の物理バージョンを維持します。トランザクションが書き込まれると、書き込まれたデータの新しいバージョンが作成され、読み取り要求は、トランザクション/ステートメントの開始時のスナップショット情報に従って、その時点ですでに存在するデータの最新バージョンを取得します。それがもたらす最も直接的な利点は次のとおりです。書き込みは読み取りをブロックせず、読み取りは書き込みをブロックせず、読み取り要求は競合(シングルバージョンT / Oなど)または待機(シングルバージョン2PLなど)が原因で失敗することはありません。データベース要求の場合、読み取り要求は書き込み要求よりも多い傾向があります。ほとんどすべての主流のデータベースは、この最適化テクノロジーを採用しています。
図5マルチバージョンの同時読み取りおよび書き込み操作
2. Yunxiデータベースの同時実行制御メカニズム
YunxiデータベースはPercolatorの同時実行制御モデルを採用しており、Yunxiデータベースの値はストレージレイヤーに直接書き込まれません。代わりに、すべてが「書き込みインテント」と呼ばれる一時的な状態で書き込まれ、値が属するトランザクションレコードを識別する追加の値。操作が書き込みインテントに遭遇するたびに、トランザクションレコードの状態を検索して、書き込みインテント値をどのように処理するかを認識します。
2.1トランザクションレコード
トランザクション実行のステータスを追跡するために、トランザクションレコードの値をKVストアに書き込み、トランザクションの書き込みインテントはこのレコードを指します。これにより、すべてのトランザクションが検出した書き込みインテントを確認できます。これは、分散環境での同時実行サポートにとって重要です。トランザクションレコードは、次のいずれかのトランザクションの状態を表します。
- PENDING:すべての値の初期状態。書き込みインテントトランザクションがまだ進行中であることを示します。
- COMMITTED:トランザクションが完了した後、このステータスは値を読み取ることができることを示します。
- ステージング:並列コミット機能を有効にするために使用されます。このレコードによって参照される書き込みインテントの状態に応じて、トランザクションがコミットされる場合とされない場合があります。
- ABORTED:トランザクションが失敗するか、クライアントによって中止された場合、トランザクションはこの状態になります。
- レコードが存在しません:トランザクションが、トランザクションレコードが存在しない書き込みインテントに遭遇した場合、書き込みインテントのタイムスタンプを使用して、続行する方法を決定します。書き込みインテントトランザクションは、タイムスタンプがトランザクションの有効性のしきい値内にある場合はトランザクション
PENDING
と見なされ、そうでない場合はトランザクションと見なされABORTED
ます。
2.2書き込みインテント
これらは基本的にマルチバージョンの同時実行制御値(MVCCとも呼ばれ、ストレージレイヤーでより詳細に説明されています)であり、値が属するトランザクションレコードを識別する付加値が付いています。それらは、複製されたロックと複製された一時値の組み合わせと考えてください。
操作が(MVCC値ではなく)書き込みインテントに遭遇すると、トランザクションレコードの状態を検索して、書き込みインテント値をどのように処理するかを確認します。トランザクションレコードが失われた場合、アクションは書き込みインテントのタイムスタンプをチェックし、期限切れかどうかを評価します。
操作がキーの書き込みインテントに遭遇するたびに、それを「解決」しようとします。結果は、書き込みインテントのトランザクションレコードによって異なります。
- COMMITTED:この操作は、書き込みインテントを読み取り、トランザクションレコードへの書き込みインテントのポインターを削除することにより、書き込みインテントをMVCC値に変換します。
- 中止:書き込みインテントは無視され、削除されます。
- 保留中:これは、トランザクションの競合があり、解決する必要があることを示します。
- ステージング:トランザクションコーディネーターは、トランザクションレコードのハートビートがまだ存在するかどうかを確認する必要があります。存在する場合は、待機する必要があります。
2.3競合の解決
2.3.1書き込みの競合
1.トランザクションに明確な優先度設定がある場合、優先度が比較されてプッシュ操作が決定され、優先度の高いトランザクションは優先度の低いトランザクションをロールバックします。
2.優先順位がない場合、タイムスタンプが大きいトランザクションは、タイムスタンプが小さいトランザクションのキューに入り、トランザクションレコードがコミットまたは中止されるのを待ちます。
2.3.2書き込みと読み取りの競合
1.トランザクションに明確な優先度設定がある場合、優先度が比較されてプッシュ操作が決定されます。優先度の高いトランザクションは、優先度の低いトランザクションのタイムスタンプをトランザクションのタイムスタンプにプッシュします。優先度が高い。
2.優先順位がない場合、タイムスタンプが大きいトランザクションは、タイムスタンプが小さいトランザクションのキューに入り、トランザクションレコードがコミットまたは中止されるのを待ちます。
2.3.3読み取り後の書き込み
読み取り操作が値を読み取ると、読み取りタイムスタンプはタイムスタンプキャッシュに保存され、読み取り値の最高水準点が示されます。書き込み操作が発生した場合、書き込みトランザクションのタイムスタンプが短い場合は、このタイムスタンプキャッシュに対してタイムスタンプを確認します。キャッシュの最新の値をタイムスタンプするよりも、書き込み後の読み取りが発生します。書き込みトランザクションのタイムスタンプがプッシュバックされ、トランザクションの再開(読み取りの更新)に影響を与える可能性があります
3.3。Yunxiデータベース並行性コントローラー
3.1なぜ並行コントローラーになりたいのですか?
- 要求の同期処理とトランザクションの競合処理を1か所に一元化し、トピックを個別に記録、理解、およびテストできるようにします。
- トランザクションのキューイングを簡素化し、トランザクションがRPCをプッシュする頻度を減らし、ウェイターがインテント解決の直後に続行できるようにします。
- 更新にはkvレベルのSELECTを実行し、共有機能にはSELECTを実行できるロックフレームワークを作成します。
- トランザクションが競合する場合の公平性に関するより強力な保証を提供して、競合シナリオでのテールレイテンシを削減します
3.2並行コントローラの基本構造
同時実行マネージャーは、着信要求を順序付け、それらの要求を発行して競合する操作を実行するトランザクションを分離する構造です。ソートプロセス中に競合が検出され、検出された競合はパッシブキューイングとアクティブプッシュの組み合わせによって解決されます。リクエストが注文されると、他のリクエストと競合することを恐れずに自由に評価できます。この分離は、要求の存続期間中は保証されますが、要求が完了すると終了します。
トランザクション内のすべてのリクエストは、リクエストの存続期間中、またはリクエストの完了後(ロックを取得したと仮定)に、他のリクエストから分離する必要がありますが、リクエストはすべてトランザクションの存続期間内である必要があります。
コアは、ラッチマネージャとロックテーブルの2つの部分です。
- lmは、リクエストを並べ替えて、リクエストを確実に分離することです。
- ltは、リクエストのロックと順序付けを提供します。これは、ロックを取得した一連の進行中のトランザクションを保持する、各ノードのメモリ内データ構造です。ロックメカニズムは書き込みインテントと互換性があるため、評価プロセス中にリクエストが外部ロックを検出すると、この情報がインポートされます。
3.3同時コントローラー制御プロセス
- リクエストSequenceReqからラッチを取得して、reqの競合がないことを確認し、メモリロックテーブルを確認します。競合がある場合は、ラッチを解放して、対応するロックを待ちます。
- その後、リクエストは正常に実行され、適用を適用した後、現在のトランザクションのロック情報がロックテーブルに追加されます。
- そして、リクエストが完了した後、FinishReqはラッチを解放して他のリクエストを続行します
- 最後に、トランザクションがコミットまたはロールバックされた後の解決インテントが完了すると、ロックテーブル内のトランザクションによって占有されていたロックが解放され、トランザクションを待機している他の要求がウェイクアップされます。
3.4ラッチマネージャー
ラッチマネージャーは着信要求を注文し、並行マネージャーの監視下でそれらの要求を分離します。ラッチは、低レベルの継続時間ミューテックスのようなものです
作業の方法:
1.範囲の書き込み要求は、範囲のLeaseHolderによってシリアル化され、特定の順序で配置されます。
2.このシリアル化を強化するために、LeaseHolderはラッチを使用して、これらの書き込まれた値への非競合アクセスを提供します
3. LeaseHolderに入る他の要求は、ラッチによってロックされているのと同じキーのセットを要求し、続行する前にラッチを取得する必要があります。
4.読み取り要求はラッチを生成することもでき、複数の読み取り要求は同時に同じキーのラッチを保持できます(互換性があります)が、読み取りラッチと書き込みラッチは互換性がありません。
ラッチを確認する別の方法は、ミューテックスに似ています。ミューテックスは、単一の低レベルの要求の期間にのみ必要です。実行時間の長い高レベルのリクエスト(つまり、クライアント側のトランザクション)を調整するために、永続的な書き込みインテントシステムを使用します。
3.5ロックテーブル
これは、ロックを取得した一連の進行中のトランザクションを保持する、各ノードのメモリ内データ構造です。各ロックにはキューが関連付けられており、ロックが解放されるのを待っているトランザクションはその中にキューに入れられます。ローカルに保存されたlockWaitQueue内のアイテムは、RPCによって既存のTxnWaitQueueに伝播されます。このTxnWaitQueueは、トランザクションレコードが配置されているRaftグループのリーダーノードに保存されます。
すべてのロックがマネージャーの制御下に直接保存されるわけではないため、並べ替えプロセス中にすべてのロックを検出できるわけではありません。具体的には、書き込みインテント(コピーされた排他ロック)はMVCCキースペースにインラインで格納されるため、評価が要求されるまで検出されません。この形式のロックストレージに対応するために、マネージャーは外部ロックに関する情報を並行マネージャー構造に統合します。
ロックの有効期間は、ロックホルダー(トランザクション)の有効期間よりも長く、ロックは、特定のキーで提供される分離の期間を、ロック所有者のトランザクション自体の有効期間まで延長します。これらは(通常)トランザクションがコミットまたは中止された場合にのみ解放されます。
ただし、すべてのロックがマネージャーの制御下に直接保存されるわけではないため、並べ替えプロセス中にすべてのロックを検出できるわけではありません。具体的には、書き込みインテント(コピーされた排他ロック)はMVCCにインラインで保存されるため、評価が要求されるまで検出されません。現在、コンカレントマネージャは複製されていないロックテーブル構造で動作します
3.6 TxnWaitQueue
TxnWaitQueueは、書き込みトランザクションをプッシュできない、遭遇したすべてのトランザクションを追跡し、続行する前にブロッキングトランザクションが完了するのを待つ必要があります。ブロッキングトランザクションIDを格納するデータ構造です
重要:これらのアクティビティは、トランザクションレコードを含む範囲のRaftグループのリーダーである単一のノードで実行されます。
トランザクションが解決されると、シグナルがTxnWaitQueueに送信されます。これにより、そのトランザクションによってブロックされたすべてのトランザクションの実行を開始できます。
ブロックされたトランザクションは、自身のトランザクションのステータスをチェックして、それらがまだアクティブであることを確認します。ブロックされたトランザクションが中止された場合は、削除する必要があります。
トランザクション間にデッドロックがある場合(つまり、トランザクションが互いの書き込みインテントによってブロックされている場合)、トランザクションの1つがランダムに中止されます。
3.7lockTableWaiter
lockTableWaiterは、ロック待機キューにロックを保持している競合するトランザクションを担当します。これにより、ビジネスコーディネーターの出張やデッドロックが発生した場合でも、要求を継続できます。
ウェイターは、ロックテーブルで競合するロックが解放されるのを待つように要求するロジックを実装します。同様に、呼び出し元が要求する前に競合する要求を待つロジックを実装します。ロック待機キューは呼び出し元の一部です。
この待機状態は、ロックテーブル内の一連の状態遷移に応答します。
1.競合するロックが解放されます
2.競合が更新され、競合が発生しなくなります
3.ロック待機キュー内の競合する要求はロックを取得します
4.ロック待機キュー内の競合する要求はロック待機キューを終了します
これらの状態状態遷移は通常反射的であり、ウェイターはロックが解放されるか、他の参加者によって終了されるのを待つことができます。
LockManagerは、競合するロックの状態遷移への対応をサポートします
RequestSequencerインターフェースは、競合するロック待機キューの状態遷移への対応をサポートします
ただし、トランザクションコーディネーターの障害またはトランザクションのデッドロックが発生した場合、ウェイターの介入なしに状態遷移が発生することはありません。前進を確実にするために、ウェイターは競合するロックホルダーまたは競合するロック待機キューの先頭を積極的にプッシュする必要がある場合があります。この動作のプッシュには、競合するトランザクションレコードのリース所有者へのRPCが必要です。これにより、通常、RPCはリース所有者のtxnWaitQueueのキューに入れられます。コストがかかるため、プッシュはすぐには実行されず、遅延後にのみ実行されます。