[バックエンドチュートリアル]純粋なドライグッズ|データベースの同時実行制御を理解する方法に関する記事

著者:ワンダー、シニア開発エンジニアアリクラウドデータベース

01

データベースの同時実行制御の役割

1.1事の概念

同時実行制御を導入する前に、まずトランザクションを理解する必要があります。データベースには、追加、削除、変更、チェックなどのいくつかの基本的な操作が用意されており、ユーザーはこれらの操作を柔軟に組み合わせて複雑なセマンティクスを実現できます。多くのシナリオで、ユーザーは操作のグループをまとめて有効にしたいと考えていますが、これはトランザクションです。トランザクションは、データベースの状態変化の基本単位であり、1つ以上の操作(複数のSQLステートメントなど)が含まれています。

従来の振替トランザクションには、次の3つの操作が含まれます。(1)Aアカウントの残高が十分かどうかを確認します。(2)十分であれば、Aから100元を差し引く。(3)B口座に100元を加算します。

トランザクションには基本的な特性があります。この操作のグループは一緒に有効になるか、まったく有効になりません。トランザクションの実行中にエラーが発生した場合、実行されたすべての操作を取り消す必要があります。これがトランザクションのアトミシティです

障害の後で、部分的に有効なトランザクションを取り消すことができない場合、データベースは不整合な状態になり、これは実際の事実とは逆です。例えば、口座Aから100元を差し引いて送金取引が失敗し、口座Bがまだ金額を上げていない場合、口座Aからの控除操作を取り消さないと、世界はどうしても100元を失うことになります。原子性はロギング(変更前の値)によって達成でき、一部のデータベースはトランザクション操作をローカルにキャッシュします。障害が発生した場合は、キャッシュ内の操作を直接破棄します。

トランザクションがコミットされている限り、その結果は変更できません。システムがダウンしていても、再起動後のデータベースの状態はダウンタイム前と同じです。これがトランザクションの持続性です

データが不揮発性ストレージメディアに保存されている限り、ダウンタイムによってデータが失われることはありません。したがって、データベースは次の方法を使用して耐久性を確保できます。(1)トランザクションが完了する前に、すべての変更がディスクに保存されることが保証されます。または(2)コミットが完了する前に、トランザクションの変更情報がログの形式でディスクに保存され、データベースシステムのメモリ状態が再起動プロセス中にログに従って復元されます。一般的に言って、データベースは方法(2)を選択しますが、その理由は読者が考えることです。

リソース使用率とトランザクション実行効率を改善し、応答時間を短縮するために、データベースではトランザクションを同時に実行できます。ただし、複数のトランザクションが同じオブジェクトを同時に操作すると、必然的に競合が発生します。トランザクションの中間状態が他のトランザクションに公開され、一部のトランザクションが他のトランザクションの中間状態に基づいてデータベースに誤った値を書き込む可能性があります。トランザクションの実行が同時トランザクションの影響を受けないようにするメカニズムを提供する必要があります。これにより、ユーザーは現在、自分自身によって開始されたトランザクションのみが実行されていると感じます。これは分離です。

分離により、ユーザーは、同時実行の影響に関係なく、単一のトランザクションのロジックに集中できます。データベースは、同時実行制御メカニズムを通じて分離を保証します。分離にはトランザクションの実行順序を高くする必要があるため、多くのデータベースにはさまざまなオプションがあり、ユーザーは分離を犠牲にしてシステムパフォーマンスを向上させることができます。これらの異なるオプションは、トランザクション分離レベルです。

データベースは現実の世界を反映しています。たとえば、現実の世界には多くの制限があります。たとえば、アカウントがどのように転送されても、合計金額は変化せず、その他の実際的な制約もありません。年齢を負にすることはできません。また、性別には男性、女性、トランスジェンダーの3つのタイプしかありません。オプションなどの整合性制約。トランザクションの実行はこれらの制約を破ることはできず、トランザクションが1つの正しい状態から別の正しい状態に転送されるようにすることはできません。これは整合性です。

違いと最初の3つのプロパティは、データベースの実装によって完全に保証されています。整合性は、データベースの実装(原子性、耐久性、分離は整合性を確保するためでもあります)だけでなく、アプリケーション側で記述されたトランザクションロジックにも依存します。

1.2トランザクションの分離を確実にする方法

分離を確実にするための1つの方法は、トランザクションが互いに干渉しないように、すべてのトランザクションを順次実行することです。ただし、シリアル実行の効率は非常に低く、スループットを向上させて応答時間を短縮するために、通常、データベースでは複数のトランザクションを同時に実行できます。したがって、並行性制御モジュールは、分離の要件を満たすために、トランザクションの同時実行の効果がトランザクションの直列実行の効果(直列化可能性)とまったく同じであることを確認する必要があります。

同時実行制御が分離を保証する方法の説明を容易にするために、トランザクションモデルを簡略化します。トランザクションは1つ以上の操作で構成され、すべての操作は最終的に一連の読み取りと書き込みに分割できます。同時トランザクションのバッチ、すべての読み取りと書き込みの実行順序は、スケジュールとして定義されます。次に例を示します。

T1とT2は同時に実行され、可能なスケジュールは次のとおりです。

T1.read(A)、T2.read(B)、T1.write(A)、T1.read(B)、T2.write(A)

トランザクションの同時実行のスケジュール効果がシリアル実行(シリアルスケジュール)と同等である場合、シリアル化可能性は満たすことができます。スケジュールは読み取り操作と書き込み操作の順序を継続的に変更し、常にシリアル化可能なスケジュールになりますが、一部の交換ではトランザクション実行の結果が異なる場合があります。スケジュールでは、2つの隣接する操作の位置がトランザクションの結果を変更し、これら2つの操作が競合します。競合は、同時に次の条件を満たす必要があります。

  • これら2つの操作は異なるトランザクションからのものです

  • 少なくとも1つは書き込み操作です

  • 同じ操作

したがって、一般的な競合には次のものがあります。

  • 読み取りと書き込みの競合。トランザクションAは最初にデータ行を読み取り、トランザクションBはデータ行を変更し、トランザクションBは最初にトランザクション行を変更し、トランザクションAは行レコードを読み取ります。トランザクションAは異なる結果を読み取ります。この競合により、反復不能な読み取りビジョンとダーティな読み取りビジョンが発生する可能性があります。

  • 書き込みと読み取りの競合。読み取りと書き込みの競合と同じ理由。この矛盾は、汚い読書ビジョンにつながる可能性があります。

  • 競合を書き込みます。2つの操作がオブジェクトを順番に書き込み、後者の操作の結果が書き込みの最終結果を決定します。この競合により、更新プログラムのビジョンが失われる場合があります。

並行トランザクションのスケジュールによって競合する操作の実行順序が変更されないことがデータベースで保証されている限り、競合しない操作のスワップのみがシリアルスケジュールになり、それらは同等と見なすことができます。

この等価判断の方法は、競合等価と呼ばれます。2つのスケジュールの競合シーケンスは同じです。たとえば、次の例では、T1書き込み(A)はT3読み取り(A)と競合し、T1はT3の前に発生します。T1読み取り(B)とT2書き込み(B)が競合し、T2がT1の前にあるため、左側のトランザクションによって実行されるスケジュールは、T2、T1、およびT3によって実行されるシリアルスケジュール(右)と同等です。左の図の実行シーケンスは、競合の直列化を満たしています。

画像

画像.png ")

反例を分析してみましょう。T1読み取り(A)はT2書き込み(A)と競合し、T1はT2に先行し、T2書き込み(A)はT2書き込み(A)と競合し、T2はT1に先行します。次のスケジュールは、シリアルスケジュールと同じにすることはできません。競合するシリアライザビリティを満たしていない実行シーケンスであり、更新が失われます。

画像.png ")

一般に、シリアライザビリティは比較的厳密な要件であり、データベースシステムの同時パフォーマンスを向上させるために、多くのユーザーは分離要件を減らしてより良いパフォーマンスを求めています。データベースシステムは、ユーザーが柔軟に選択できるように複数の分離レベルを実装することがよくあります。トランザクション分離レベルについては、この記事を参照してください

同時実行制御の要件は明確ですが、それをどのように達成しますか?次の記事では、競合検出の楽観に従って、同時実行制御の一般的な実装方法を1つずつ紹介します。

02

2段階ロックに基づく同時実行制御

2.1 2PLは
操作が正しい順序で実行されることを保証する必要があるため、考える最も簡単な方法は、アクセスオブジェクトをロックして保護することです。データベースシステムのロックマネージャーモジュールは、オブジェクトにアクセスするためのロックのロックと解放を特に担当し、ロックを保持するトランザクションのみが対応するオブジェクトを操作できるようにしますロックは、SロックとXロックの2つのカテゴリに分類できます。Sロックは読み取り要求に使用される共有ロックであり、Xロックは書き込み要求に使用される排他ロックです。それらの互換性は次のとおりです。同じオブジェクトで動作し、2つの読み取り要求のみが相互に互換性があり、同時に実行できます。読み取りと書き込みの操作は、ロックの競合により順次実行されます。画像2PL(2フェーズロック)は、データベースの最も一般的なロックベースの同時実行制御プロトコルです。名前が示すように、2つのフェーズが含まれています。

  • フェーズ1:トランザクションは成長し、必要なすべてのロックをロックマネージャに要求します(ロックに失敗する可能性があります)。
  • フェーズ2:縮小、トランザクションは拡大フェーズで取得したロックを解放し、新しいロックは許可されません。

ロックとロックの解除を2つの段階に明確に分ける必要があるのはなぜですか?2PL同時実行制御の目的は、直列化を実現することです。同時実行制御が必要なすべてのロックを事前に適用しない場合は、ロックを解除した後、再度ロックを適用できます。同じオブジェクト間のトランザクション内に2つの操作があり、他のトランザクションがこれを変更します。オブジェクト(下の図に示すように)があり、シリアル化可能な競合に到達できず、不整合があります(次の例は更新が失われます)。画像2PLは、トランザクションが実行に必要なすべてのロックを取得する必要があるため、競合の直列化を保証できます。たとえば、実行中のトランザクションA トランザクションBと競合し、トランザクションBはすでに実行されているか、まだ待機しています。したがって、これらの競合する操作の実行順序は、BAまたはABが連続して実行される場合の競合する操作の実行順序と同じです。では、データベースが2PLを使用して一貫性と分離を保証している限り、この例を見てみましょう。画像上記の実行順序は2PLに沿っていますが、T2はコミットされていないデータを読み取ります。この時点でT1がロールバックされると、カスケードロールバックが発生します(T1の変更はトランザクションからは見えません)。したがって、データベースはS(trong)S(trict)2PLの拡張バージョンを使用することが多く、2PLとは少し異なります。縮小フェーズでは、トランザクションの完了後にのみロックを解放でき、トランザクションのコミットされていないデータを完全に排除します。読んだ。

2.2デッドロックの処理

並行トランザクションのロックのロックと解放は、必然的に問題のデッドロックを回避します。トランザクション1はAロックなどのBロックを保持し、トランザクション2はBロックなどのAロックを保持します。現在、デッドロックの問題には2つの解決策があります。

  • デッドロック検出:

データベースシステムは、待機グラフに従ってトランザクションの待機関係を記録します。ドットはトランザクションを表し、有向エッジは、トランザクションが別のトランザクションがロックを解放するのを待機していることを表します。待機グラフにリングが表示される場合、デッドロックが発生したことを意味します。システムのバックグラウンドは、待機グラフを定期的に検出します。リングが見つかった場合は、適切なトランザクションアボートを選択する必要があります。画像

  • デッドロック防止:

トランザクションがすでに保持されているロックを要求すると、データベースシステムはトランザクションの1つを強制終了してデッドロックを防止します(通常、トランザクションが長く続くほど、予約の優先順位が高くなります)。この予防的アプローチでは待機グラフは必要ありませんが、トランザクションが強制終了される頻度が高くなります。

2.3インテンションロック

行ロックのみがある場合、トランザクションが1億レコードを更新する必要がある場合、1億行ロックを取得する必要があり、大量のメモリリソースを消費します。ロックは、データベースの内部アクセスオブジェクトを保護するために使用されることがわかっています。これらのオブジェクトは、属性、タプル、ページ、テーブルであり、対応するロックは行ロックとページに分割できます。ロック、テーブルロック(属性ロックは実装されていません。OLTPデータベースの場合、操作の最小単位は行です)。トランザクションの場合、1億レコードを更新するなど、最小限のロックを取得するのが最善です。おそらく、テーブルロックを追加するだけで十分です。より高いレベルのロック(テーブルロックなど)は、リソースの使用を効果的に減らし、ロックチェックの数を大幅に減らすことができますが、同時実行性が大幅に制限されます。下位レベルのロック(行ロックなど)は同時実行に役立ちますが、多くのトランザクション要求オブジェクトの場合、多数のロックチェックが必要です。高レベルのロック制限の同時実行性の問題を解決するために、データベースシステムはインテンションロックの概念を導入しています。

  • 意図共有(IS):その中の1つ以上のオブジェクトがS-Lockによって保護されていることを示します。たとえば、ISでテーブルが追加された場合、テーブル内の少なくとも1つの行がS-Lockによって保護されます。
  • 意図的排他(IX):その中の1つ以上のオブジェクトがX-Lockによって保護されていることを示します。たとえば、テーブルとIXの場合、テーブル内の少なくとも1つの行はXロックによって保護されます。
  • Shared + Intention-Exclusive(SIX):内部の少なくとも1つのオブジェクトがX-Lockによって保護されており、それ自体がS-Lockによって保護されていることを示します。たとえば、操作ではテーブル全体のスキャンが必要であり、テーブルのいくつかの行を変更する場合、SIXをテーブルに追加できます。読者はXIXやXISがない理由について考えることができます

意図的ロックと通常のロックの互換性関係は次のとおりです画像。意図的ロックの利点は、IXがテーブルに追加されると、変更されている行がテーブルにあることを意味します。(1)この時点で、テーブルでDDL操作が開始され、テーブルのXロックが要求される必要があります。次に、テーブルがIXを保持している場合、テーブル内の行が1つずつ行ロックを保持しているかどうかを確認せずに直接待機するため、検査のオーバーヘッド効果的に削減されます(2)現時点では、他の読み取りトランザクションと書き込みトランザクションがあります。テーブルはXではなくIXで追加されるため、行の読み取り要求と書き込み要求は妨げられません(最初にIXをテーブルに追加し、次にS / Xをレコードに追加します)。トランザクションにXロックされた行が含まれていない場合、トランザクションは正常に実行され、システムの同時実行性が向上します。03

タイミング順序(T / O)に基づく同時実行制御

各トランザクションにタイムスタンプを割り当て、これを使用してトランザクションの実行順序を決定します。トランザクション1のタイムスタンプがトランザクション2より小さい場合、データベースシステムは、トランザクション2の前にトランザクション1が実行されるようにする必要があります。タイムスタンプの配布方法には、(1)物理クロック、(2)論理クロック、(3)混合クロックが含まれます。

3.1基本的なT / O

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。

ここでTTS> RTS(X)が必要なのは、次の状況を防ぐためです。新しいトランザクションTTS <RTS(Xの場合、読み取り要求のタイムスタンプはrts、Xは読み取られ、タイムスタンプはRTS(X)= rtsに設定されます。 )、そして更新が成功すると、rts読み取り要求が再度読み取られ、新しい変更を確認します。これは、繰り返し可能な読み取りに違反するため、読み取りと書き込みの競合を回避するためです。最後の読み取りと書き込みの時間はレコードに保存されます。これにより、競合のシリアライズが書き込みスキューを回避できるようになります。たとえば、初期状態、XおよびYレコード、X = -3、Y = 5、X + Y> 0、 RTS(X)= RTS(Y)= WTS(X)= WTS(Y)= 0。トランザクションT1のタイムスタンプはTTS1 = 1、トランザクションT2のタイムスタンプはTTS2 = 2です。画像.png ")その欠陥は次のとおりです。

  • 長いトランザクションのタイムスタンプが小さすぎるため、長いトランザクションは枯渇する傾向があり、更新されたデータが実行期間の後に読み取られ、アボートが発生する可能性が高くなります。
  • 読み取り操作でも書き込みが生成されます(RTSの書き込み)。

04

検証(OCC)に基づく同時実行制御

実行プロセス中、各トランザクションは独自の書き込み操作(トランザクション実行中に基本T / OがDBにデータを書き込む)と対応するRTS / WTSを維持し、独自の変更とデータベース内の既存の変更が送信されるかどうかを判断します。データが競合し、競合がない場合はDBに書き込みます。OCCは3つの段階に分かれています。

  • 読み取りおよび書き込みフェーズ:読み取りおよび書き込みフェーズ。トランザクションは、読み取り結果と今後の変更、およびRTSとWTSで書き込まれたレコードを維持します。
  • 検証フェーズ:トランザクションがデータベース内のデータと競合するかどうかを確認します。
  • 書き込みフェーズ:競合なしの書き込み、競合、中止、再起動。

読み取りおよび書き込みフェーズが終了し、検証フェーズに入るのは、トランザクションの準備を完了してコミットフェーズに入るのと同じです。検証フェーズに入る時間は、シーケンスするレコード行のタイムスタンプとして選択されます。トランザクションの開始時間が使用されない理由は、トランザクションの実行時間が長くなる可能性があり、後で開始するトランザクションが最初に送信される可能性があるため、トランザクションの競合の可能性が高くなります。タイムスタンプが小さいトランザクションは、トランザクション後にデータベースに書き込まれ、確実に中止されます。

検証プロセス

トランザクションT1とT2が2つだけあり、同じデータ行が変更されると仮定すると、T1のタイムスタンプ<T2のタイムスタンプ(つまり、検証の順序:T1 <T2、ユーザーの場合、T1はT2で最初に発生)状況:(1)T1は検証フェーズにあり、T2はまだ読み取りおよび書き込みフェーズにあります。この時点で、T1とT2で発生した読み取りと書き込みの間に矛盾がない限り、送信できます。

  • WS(T1)∩(RS(T2)∪WS(T2))= Ifの場合、T2とT1によって書き込まれたレコード間に競合がなく、検証を書き込むことができることを意味します。
  • それ以外の場合は、T2とT1の間に読み取り/書き込みの競合または書き込み/書き込みの競合があり、T1をロールバックする必要があります。読み取りと書き込みの競合:T2はT1が書き込まれる前のバージョンを読み取ります。T1がコミットした後、T1によって書き込まれたバージョンを読み取る可能性があります。書き込みと書き込みの競合:T2は古いバージョンに基づいて更新され、再度書き込まれる可能性があるため、T1の更新が失われます。

(2)T1は検証フェーズを完了し、サブミットが完了するまで書き込みフェーズに入ります。これは、すでに取り消すことができません。T1が書き込みフェーズに入る前のT2の読み取りと書き込みは、T1の操作と競合してはなりません(T1検証に合格したため)。T2がT1によってサブミットされる操作と競合する可能性があるため、T2が検証ステージに入ると、読み取り操作と書き込み操作が続行される場合があります。

  • WS(T1)∩RS(T2)=∅の場合、T2がT1によって書き込まれたレコードを読み取っていないことを意味し、検証はパスし、T2は書き込みを行うことができます。(WS(T2)を検証しないのはなぜですか?WS(T1)が送信されており、そのタイムスタンプがWS(T2)より小さいです。WS(T2)の前の部分と次の部分は、まだ読み取られていないため、競合してはなりません。 T1によって書き込まれたオブジェクトは書き込み可能であり、WS(T1)の書き込みを上書きしません)
  • それ以外の場合、T2とT1の間に読み取り/書き込みの競合と書き込み/書き込みの競合があり、T2をロールバックする必要があります。読み取りと書き込みの競合:T2はT1が書き込まれる前のバージョンを読み取ります。T1がコミットした後、T1によって書き込まれたバージョンを読み取る可能性があります。書き込みと書き込みの競合:T2は古いバージョンに基づいて更新され、再度書き込まれる可能性があるため、T1の更新が失われます。

05

MVCCに基づく同時実行制御

データベースは、レコードの複数の物理バージョンを維持します。トランザクションが書き込まれると、書き込まれたデータの新しいバージョンが作成され、読み取り要求は、トランザクション/ステートメントの先頭のスナップショット情報に基づいて、その時点ですでに存在する最新バージョンのデータを取得します。それがもたらす最も直接的な利点は次のとおりです。書き込みは読み取りをブロックせず、読み取りは書き込みをブロックせず、読み取り要求は競合(単一バージョンT / Oなど)または待機(単一バージョン2PLなど)によって失敗することはありません。データベース要求の場合、多くの場合、読み取り要求は書き込み要求よりも多くなります。ほとんどすべての主流のデータベースがこの最適化技術を使用しています。MVCCは、読み取りおよび書き込み要求の最適化テクノロジです。データベースの同時実行性の問題を完全には解決しません。完全な同時実行性制御機能を提供するには、前述のいくつかの同時実行性制御テクノロジと組み合わせる必要があります。同時実行制御テクノロジの一般的なタイプには、MV-2PL、MV-T / O、およびMV-OCCが含まれます。それらの特性は次のとおりです画像。.png ")MVCCには、考慮すべき2つの重要なポイントがあります。バージョンデータのリサイクル。マルチバージョンデータの保存方法は、次の2つのカテゴリに大別できます。(1)追加のみの方法。古いバージョンと新しいバージョンは、LSM-Treeベースのストレージエンジンなどの同じテーブルスペースに保存されます。(2)メインテーブルスペースデータの最新バージョンを記録します。前のイメージは、InnoDBのマルチバージョン情報がUNDOログに記録されるなど、他のテーブルスペースまたはデータセグメントに記録されます。マルチバージョンデータコレクションは、ガベージコレクション(GC)とも呼ばれ、読み取り要求によって取得される可能性はありません。レコードの古いバージョンでは、速やかに削除する必要があります。06

まとめ

この記事では、ロック(トランザクションの開始前に競合を防止する)、T / O(トランザクション実行中に競合を判断する)、および検証(トランザクションがコミットされたときに競合を検証する)に基づくトランザクションを、競合処理のタイミング(楽観)に基づいて紹介します。同時実行制御メカニズム。さまざまな実装がさまざまなワークロードに適しており、並行処理の競合が少ないワークロードは、より楽観的な並行処理制御方法に確かに適しています。MVCCは、読み取り専用トランザクションと読み取り/書き込みトランザクション間の相互ブロッキングの問題を解決し、トランザクションの同時読み取りを改善することができ、ほとんどの主流のデータベースシステムで採用されています。

サービスの推奨

元の記事を公開0件 ・いい ね0件 訪問数344

おすすめ

転載: blog.csdn.net/weixin_47143210/article/details/105652969