MySQLにおけるトランザクションの永続性実装原理の詳細な説明

MySQLにおけるトランザクションの永続性実装原理の詳細な説明

序文

データベース トランザクションに関して言えば、トランザクションの ACID 特性、分離レベル、解決される問題 (ダーティ リード、非反復読み取り、ファントム リード) など、トランザクションに関連する多くの知識が誰の頭にもすぐに浮かびますが、これらのトランザクション特性がどのように実装されているか、また 4 つの分離レベルがなぜあるのかを実際に理解している人はほとんどいないでしょう。

前回の記事では、MySQL におけるトランザクション分離の実装原則について学びました。今日は、引き続き MySQL 永続性の実装原則についてお話ししましょう。

もちろん、MySQL は広範かつ奥深いため、この記事で省略される部分があることは避けられません。批判や訂正は大歓迎です。

例示する

MySQL のトランザクション実装ロジックはエンジン層にあり、すべてのエンジンがトランザクションをサポートしているわけではありません。次の手順は InnoDB エンジンに基づいています。

InnoDB のデータの読み取りと書き込みの原理

先に進む前に、InnoDB がデータを読み書きする方法を理解する必要があります。データベースのデータはディスクに保存され、ディスク I/O のコストが非常に高いこともわかっています。データの読み取りまたは書き込みのたびにディスクにアクセスする必要がある場合、データベースの効率は非常に低くなります。この問題を解決するために、InnoDB はデータベース データにアクセスするためのバッファーとしてバッファー プールを提供します。

バッファ プールはメモリ内に配置され、ディスク上のいくつかのデータ ページのマッピングが含まれています。データの読み取りが必要な場合、InnoDB はまずバッファ プールからデータを読み取ろうとします。データを読み取れない場合は、ディスクから読み取ってバッファ プールに格納します。データを書き込む場合は、まずバッファ プール ページに書き込み、そのページをダーティとしてマークし、特別なフラッシュ リストに格納します。これらの変更されたデータ ページは、将来のある時点でディスクにフラッシュされます (このプロセスはダーティ フラッシュと呼ばれ、他のバックグラウンド スレッドが担当します)。次の図に示すように:

この設計の利点は、大量のディスク I/O をメモリの読み取りと書き込みに変換し、ページに対する複数の変更を 1 つの I/O 操作にマージ (ダーティになったページ全体をフラッシュ) することで、読み取りおよび書き込み操作ごとにディスクにアクセスする必要がなくなり、データベースのパフォーマンスが大幅に向上することです。

持続性の定義

永続性とは、トランザクションがコミットされると、データベースへの変更が永続的になり、その後の操作や障害がこのトランザクションの変更に影響を与えないことを意味します。

前回の紹介から、InnoDB はバッファ プールを使用して読み取りと書き込みのパフォーマンスを向上させることがわかりました。ただし、バッファ プールはメモリ内にあり、揮発性です。トランザクションがコミットされた後に MySQL が突然クラッシュし、その時点でバッファ プール内の変更されたデータがディスクに更新されていない場合、データは失われ、トランザクションの永続性は保証されません。

この問題を解決するために、InnoDB はデータ変更の永続性を実現する REDO ログを導入しました。データが変更されると、InnoDB はバッファー プール内のデータを変更するだけでなく、その操作を REDO ログに記録し、対応するページよりも前に (通常はトランザクションがコミットされたときに) REDO ログがディスクに書き込まれるようにします。これは WAL と呼ばれることがよくあります。 MySQL が突然クラッシュし、データがディスクにフラッシュバックされていない場合、再起動後、MySQL はディスクに書き込まれた REDO ログを使用して、ディスクにフラッシュされていないデータ ページを回復します。

実装原則: redo ログ

パフォーマンスを向上させるために、データ ページと同様に、REDO ログも 2 つの部分で構成されます。1 つは揮発性のメモリ内のログ バッファーで、もう 1 つは永続的なディスク上の REDO ログ ファイルです。 REDO ログは、データベース内の物理ページの状態を記録する物理ログです。

データが変更されると、InnoDB はバッファ プール内のデータを変更するだけでなく、その操作を REDO ログ バッファに記録します。トランザクションがコミットされると、REDO ログ バッファはディスクにフラッシュされ、REDO ログ ファイルに記録されます。 MySQL がクラッシュした場合は、再起動時に REDO ログ ファイルのデータを読み取ってデータベースを復元できます。この方法では、トランザクションが送信されるたびにデータをリアルタイムでフラッシュする必要がなくなります。

執筆プロセス

注記:

  • まずバッファ プールを変更し、次に REDO ログ バッファを書き込みます。
  • 再実行ログは、データ ページの前にディスクに書き戻されます。トランザクションがコミットされると、再実行ログ バッファーが再実行ログ ファイルに書き込まれます。書き込みが成功した場合にのみコミットが成功し (書き込みをトリガーする他のシナリオもありますが、ここでは詳しく説明しません)、バッファー プールのデータは、その後の何らかの時点でバックグラウンド スレッドによってディスクに書き込まれます。
  • ダーティ データをフラッシュする場合、対応する REDO ログ (いわゆる WAL (先行書き込みログ)) がディスクに書き込まれていることを確認する必要があります。そうしないと、データが失われる可能性があります。

利点

トランザクションがコミットされるとき、REDO ログに書き込むと、ログを直接フラッシュするよりも 3 つの主な利点があります。

フラッシュはランダム I/O ですが、REDO ログの書き込みはシーケンシャル I/O です。シーケンシャル I/O はランダム I/O よりもはるかに高速であるため、必要ありません。
ダーティ フラッシュはデータ ページ単位で行われます。ページがわずかに変更された場合でも、ページ全体を書き込む必要があります。REDO ログには実際に変更された部分のみが含まれ、データ量は非常に小さいため、無効な IO が大幅に削減されます。
データをフラッシュする場合、多くのデータ ページをフラッシュする必要がある場合があり、アトミック性は保証されません (たとえば、データの一部のみが書き込まれると失敗が発生します)。ただし、REDO ログ バッファは、セクターのサイズである 512 バイトでログ ブロックを REDO ログ ファイルに書き込みます。セクターは書き込みの最小単位であるため、書き込みが成功することが保証されます。

最初に REDO ログを書き込む必要がありますか、それとも最初にデータを変更する必要がありますか?

DML 操作には、データの変更と REDO ログの記録が含まれる場合があります。それらはどのような順序で実行されますか?インターネット上の記事の中には、まずデータを変更し、その後で REDO ログを記録するべきだと書いてあるものもありますが、一方で、まず REDO ログを記録し、その後でデータを変更するべきだと書いてあるものもあります。では、実際のところはどうなのでしょうか?

まず、上記の説明から、トランザクションがコミットされたときに redo ログ バッファが redo ログ ファイルに書き込まれ、フラッシュはその後のいつか行われることがわかります。したがって、最初に redo ログが記録され、後でデータ ページが変更されることは確かです (もちろん、WAL ログが最初に書き込まれます)。

次の質問は、最初に REDO ログ バッファを書き込むか、最初にバッファ プールを変更するかです。この問題を理解するには、まず InnoDB での DML の実行プロセスを理解する必要があります。 DML の実行プロセスには、データの変更、ロック、ロック解除、REDO ログの記録、UNDO ログの記録が含まれ、これらにも原子性を保証する必要があります。InnoDB は、MTR (ミニトランザクション) を使用して、DML 操作の原子性を保証します。

まず、MTR の定義を見てみましょう。

InnoDB 処理の内部フェーズ。DML 操作中に内部データ構造に物理レベルで変更を加える場合。ミニトランザクション (mtr) にはロールバックの概念がなく、1 つのトランザクション内で複数のミニトランザクションが発生する可能性があります。ミニトランザクションは、クラッシュ回復中に使用される redo ログに情報を書き込みます。ミニトランザクションは、バックグラウンド スレッドによるパージ処理中など、通常のトランザクションのコンテキスト外で発生することもあります。https://dev.mysql.com/doc/refman/8.0/en/glossary.html を参照してください。

MTR は短いアトミック操作であり、それ自体がアトミックであるためロールバックできません。データ ページへの変更は MTR を経由する必要があります。MTR は、DML 操作によって発生したデータ ページへの変更を REDO ログに記録します。

MTR プロセスを簡単に見てみましょう。

  • MTRが初期化されると、mtr_bufのコピーが初期化されます。
  • データが変更されると、メモリ バッファー プール内のページが変更され、REDO ログ レコードが生成され、mtr_buf に保存されます。
  • mtr_commit 関数を実行して MTR をコミットすると、mtr_buf 内の redo ログ レコードが redo ログ バッファに更新され、ダーティ ページが後続のフラッシュのためにフラッシュ リストに追加されます。ログ バッファーでは、496 バイトのログ レコードが受信されるたびに、このログ レコードのグループが 12 バイトのブロック ヘッダーと 4 バイトのブロック テーラーでラップされ、512 バイトのログ ブロックになります。これは、ディスクにフラッシュするときに 512 バイトを揃えるのに便利です。

このことから、InnoDB はまずバッファ プールを変更し、次に REDO ログ バッファを書き込むことがわかります。

データの回復プロセス

いずれの場合でも、InnoDB は起動時にリカバリ操作を実行しようとします。リカバリ プロセス中は、REDO ログが必要であり、binlog が有効になっている場合は、binlog と UNDO ログも必要です。データはバイナリログに書き込まれているが、REDO ログがディスクにフラッシュされる前にデータベースがクラッシュした可能性があります (トランザクションは InnoDB エンジンの機能であり、変更されたデータがコミットされない可能性がありますが、バイナリログは MySQL サービス レイヤーの機能であり、変更されたデータが記録されます)。このとき、コミットされていないトランザクションがあるかどうかを判断し、コミットされていないトランザクションをロールバックまたはコミットするために、REDO ログ、バイナリログ、および UNDO ログが必要です。

以下は、REDO ログのみを使用してデータを復元するプロセスの簡単な説明です。

  • InnoDB を起動するときに、最新のチェックポイントの場所を見つけ、チェックポイント LSN を使用して、ログ回復用の LSN より大きい REDO ログを見つけます。
  • 途中でリカバリに失敗しても影響はありません。再度リカバリする場合は、最後に正常に保存されたチェックポイントの位置からリカバリを続行できます。

回復プロセス: 障害回復は、分析、やり直し、元に戻すの 3 つの段階で構成されます。分析フェーズのタスクは、チェックポイントとログの情報を使用して、後続の Redo フェーズと Undo フェーズの操作範囲を確認し、ログを通じてチェックポイントに記録されたダーティ ページ セット情報を修正し、関係する最小の LSN 位置を次の Redo の開始位置 RedoLSN として使用することです。同時に、チェックポイントに記録されたアクティブなトランザクション セット (コミットされていないトランザクション) は、Undo プロセスのロールバック オブジェクトとして修正されます。Redo ステージは、分析によって取得された RedoLSN から開始され、ログ内のすべての Redo コンテンツを再生します。これにはコミットされていないトランザクションも含まれることに注意してください。最後に、Undo ステージは、Undo 情報を使用して、コミットされていないすべてのトランザクションをロールバックします。ロールバックする必要があるすべての変更は、ログの PrevLSN を通じて順番に見つけることができます。詳細については、http://catkang.github.io/2019/01/16/crash-recovery.html を参照してください。

LSNとは何ですか?

LSN はログ シーケンス番号とも呼ばれ、単調に増加する 64 ビットの符号なし整数です。 REDO ログとデータ ページの両方に LSN が格納されており、これをデータ回復の基礎として使用できます。 LSN が大きいほど、参照されたログ レコードによって記述された変更が後で発生したことを示します。

チェックポイントとは何ですか?

チェックポイントは保存ポイントを表し、このポイント (ログ LSN < チェックポイント LSN) より前のデータ ページへのすべての変更がディスク ファイルに書き込まれています。 InnoDB は、各ディスク フラッシュ後にチェックポイントを記録し、チェックポイント LSN に最新の redo ログ LSN を記録します。これは、データを復元するときに開始点を決定するのに便利です。

上記は、MySQL におけるトランザクションの永続性の実装原理の詳細な説明です。MySQL トランザクションの永続性の詳細については、123WORDPRESS.COM の他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • MySQLにおけるトランザクション分離レベルの実装原理の詳細な説明
  • MySQLトランザクションを実行するための構文とプロセスの詳細な説明
  • mysql と oracle のデフォルトのトランザクション分離レベルの説明
  • MySQL トランザクション自動コミット自動コミット操作
  • トランザクションとロックを表示するための MySQL の一般的なステートメント
  • MySQL マスタースレーブ同期、トランザクションロールバックの実装原理
  • MySQLデータベースのトランザクションとロックの詳細な分析
  • Mysql トランザクションで Update を実行するとテーブルがロックされますか?
  • PHP+MySQL 分散トランザクションとソリューションに関する深い理解
  • MySQL は ACID トランザクションをどのように実装しますか?
  • MySQL が大規模トランザクションを避けるべき理由とその解決方法

<<:  ウェブページ要素の完全な分析

>>:  Vueは大画面ページのスクリーン適応を実現します

推薦する

MySQLクエリ最適化: 100万件のデータに対するテーブル最適化ソリューション

1. 2つのクエリエンジン(myIsamエンジン)のクエリ速度InnoDB はテーブル内の特定の行数...

Oracle Rownum 書き込みに似た MySQL の詳細な例

Rownum は、Oracle での独自の書き込み方法です。Oracle では、rownum を使用...

MySQL エラー番号 1129 の解決方法

SQLyog が MySQL に接続する際にエラー番号 1129 が発生します: mysql エラー...

HTML テーブルタグチュートリアル (13): 内部境界スタイル属性ルール

RULES を使用すると、テーブルの内部境界のスタイルを制御できます。基本的な構文<TABLE...

マウスを傾けた状態でのフリップナビゲーションの問題に関する研究

この記事では、マウス フリップナビゲーションの制作についてまだ疑問を持っている友人の役に立つことを期...

VMware Workstation のダウンロードとインストールの詳細なチュートリアル

仮想マシンは非常に便利なテストソフトウェアです。ハードウェアに損傷を与えることなく、さまざまなテスト...

MySQLの半同期の詳細な説明

目次序文MySQL マスタースレーブレプリケーションMySQL でサポートされているレプリケーション...

MySql 8.0 と対応するドライバー パッケージの一致に関する注意事項

MySql 8.0 対応ドライバパッケージのマッチングMySql データベースをバージョン 8.0 ...

MySQL の NULL 値に関する体験談と分析チュートリアルシリーズ

目次1. テストデータ2. ヌル値による不便3. スペース、空の値、null をどのように判断すれば...

Linux の一般的な Java プログラム起動スクリプトのコード例

シェルを起動する頻度は非常に低いですが。 。 。しかし、書くたびに、多くの jar ファイル パスを...

CSS3 のフィルタプロパティの使用に関する詳細な説明

最近、イントラネットポータルを修正していたときに、フィルターを使用する必要がある箇所に遭遇しました。...

超シンプルな QPS 統計手法 (推奨)

過去 N 秒間の QPS 値の統計 (1 秒あたりの選択、挿入などを含む) mysql> se...

vue3 カスタムディレクティブの詳細

目次1. カスタム指示の登録1.1. グローバルカスタム指示1.2. ローカルカスタム指示2. カス...

Docker は Python Flask+ nginx+uwsgi コンテナを構築します

Nginxをインストールするまずcentosイメージをプルしますdocker pull centos...

Nginx での SSL 証明書のインストールと展開手順の概要

目次問題の説明:インストール手順1. 準備2. サーバーにリモート接続する3. 証明書と秘密鍵ファイ...