MySQL5.7 並列レプリケーションの原理と実装

MySQL5.7 並列レプリケーションの原理と実装

データ操作とメンテナンスに少しでも知識のある人なら、MySQL 5.5 以前では再生に単一の SQL スレッドが使用されていることを知っています。マスター QPS がわずかに高い場合、遅延が発生します。5.6 はライブラリベースの並列再生メカニズムです。複数のライブラリがある場合にのみ、レプリケーションが有利になります。5.7 はグループベースの並列再生です。同じグループ内のトランザクションを並列で再生して、遅延の問題を解決できます。

MySQL 5.7 並列レプリケーション時代

周知のとおり、MySQLのレプリケーション遅延は、これまで批判されてきた問題の1つです。しかし、Inside Junの過去2回のブログ(1、2)では、MySQL 5.7バージョンがすでに「本物の」並列レプリケーション機能をサポートしており、正式には強化マルチスレッドスレーブ(略してMTS)と呼ばれていることが言及されています。そのため、レプリケーション遅延問題は大幅に改善されました。Inside Junが作業しているNetEaseの電子商取引アプリケーションでも、数時間の遅延の問題は完全に解消されました。しかし、歴史に記録されるに値するこの「素晴らしい」機能をまだ理解していない友人が多いことに気づいたので、皆さんと共有することにしました。つまり、バージョン 5.7 以降では、レプリケーション遅延の問題は発生しなくなります。

MySQL 5.6 並列レプリケーション アーキテクチャ

MySQL バージョン 5.6 もいわゆる並列レプリケーションをサポートしているのは事実ですが、その並列性はスキーマ、つまりライブラリのみに基づいています。ユーザーの MySQL データベース インスタンスに複数のスキーマがある場合、スレーブ レプリケーションの速度が大幅に向上します。 MySQL 5.6 並列レプリケーションのアーキテクチャは次のとおりです。

上図の赤枠部分が並列レプリケーションを実現するための鍵となります。 MySQL 5.6 より前は、スレーブ サーバーに I/O スレッドと SQL スレッドの 2 つのスレッドがありました。 I/O スレッドはバイナリ ログ (より正確にはバイナリ ログ イベント) を受信する役割を担い、SQL スレッドはバイナリ ログを再生します。 MySQL バージョン 5.6 で並列レプリケーション機能が有効になっている場合、SQL スレッドはコーディネーター スレッドになり、主に次の 2 つの部分を担当します。

  • 並列実行が可能と判断された場合、トランザクションのバイナリログがワーカースレッドで実行されるように選択される。
  • 操作が DDL またはクロススキーマ トランザクション操作であるなど、並列実行が不可能であると判断された場合は、現在のログを実行する前に、すべてのワーカー スレッドが完了するまで待機します。

つまり、コーディネーター スレッドはワーカー スレッドにログを送信するだけでなく、ログ自体を再生することもできますが、並列化できるすべての操作はワーカー スレッドによって配信されます。コーディネーター スレッドとワーカーは、典型的なプロデューサー モデルとコンシューマー モデルです。

上記の仕組みはスキーマベースの並列レプリケーションを実装していますが、2 つの問題があります。まず、並列レプリケーションにより、後から実行されるトランザクションが先に完了してしまう可能性があるため、クラッシュセーフ機能の実装が困難です。次に、クラッシュが発生した場合、この部分の処理ロジックが比較的複雑になります。コードの観点から見ると、5.6 ではこの問題を解決するために Low-Water-Mark タグが導入されています。設計の観点からは、ログのべき等性を利用してこの問題を解決したいと考えています。ただし、5.6 のバイナリ ログ再生ではべき等性を実現できません。もう 1 つの重要な問題は、この設計の並列レプリケーション効果がそれほど高くないことです。ユーザー インスタンスにライブラリが 1 つしかない場合、並列再生は実現できず、パフォーマンスは元のシングル スレッドのものよりもさらに悪くなる可能性があります。複数のテーブルを持つ複数のデータベースよりも、複数のテーブルを持つ単一のデータベースのほうが一般的なシナリオです。

MySQL 5.7 グループコミットに基づく並列レプリケーション

MySQL 5.7 は真の並列レプリケーションと言えます。その主な理由は、スレーブ サーバーの再生がホストと一致していること、つまりスレーブ サーバーがマスター サーバーと同じ並列実行を再生することです。

MySQL 5.7 の並列レプリケーションの考え方はシンプルで理解しやすいものです。簡単に言うと、グループによって送信されたすべてのトランザクションは、トランザクションの準備フェーズに入っているため、並列で再生できます。つまり、トランザクション間に競合はありません (そうでなければ送信は不可能です)。

MySQL 5.6 のライブラリベースの並列レプリケーションとの互換性を保つために、5.7 では新しい変数 slave-parallel-type が導入されました。設定可能な値は次のとおりです。

  • DATABASE: デフォルト値、ライブラリベースの並列レプリケーション
  • LOGICAL_CLOCK: グループコミットに基づく並列レプリケーション

並列レプリケーションのGTIDサポート

トランザクションがグループ内にあるかどうかを知る方法は別の問題です。元の MySQL ではそのような情報が提供されないからです。 MySQL 5.7 では、グループコミット情報を GTID に保存する設計になっています。では、ユーザーが GTID 機能を有効にしない場合、つまりパラメータ gtid_mode を OFF に設定した場合はどうなるでしょうか?そのため、MySQL 5.7 では、次のような Anonymous_Gtid と呼ばれるバイナリ ログ イベント タイプが導入されました。

mysql> 'mysql-bin.000006' の BINLOG イベントを表示します。
 +------------------+-----+----------------+-----------+-------------+-----------------------------------------------+
 | ログ名 | 位置 | イベント タイプ | サーバー ID | ログ終了位置 | 情報 |
 +------------------+-----+----------------+-----------+-------------+-----------------------------------------------+
 | mysql-bin.000006 | 4 | Format_desc | 88 | 123 | サーバーバージョン: 5.7.7-rc-debug-log、Binlog バージョン: 4 |
 | mysql-bin.000006 | 123 | 前のgtids | 88 | 194 | f11232f7-ff07-11e4-8fbb-00ff55e152c6:1-2 |
 | mysql-bin.000006 | 194 | Anonymous_Gtid | 88 | 259 | @@SESSION.GTID_NEXT= 'ANONYMOUS' に設定 |
 | mysql-bin.000006 | 259 | クエリ | 88 | 330 | 開始 |
 | mysql-bin.000006 | 330 | テーブルマップ | 88 | 373 | テーブル ID: 108 (aaa.t) |
 | mysql-bin.000006 | 373 | Write_rows | 88 | 413 | table_id: 108 フラグ: STMT_END_F |
 .....

つまり、MySQL 5.7 では、GTID が有効になっていない場合でも、各トランザクションの開始前に Anonymous_Gtid が存在し、この GTID にグループコミット情報が含まれます。

論理クロック

ただし、上記の SHOW BINLOG EVENTS を通じて、グループ送信に関する情報は見つかりませんでした。ただし、mysqlbinlog ツールを使用すると、ユーザーはグループによって送信された内部情報を見つけることができます。

# mysqlbinlog mysql-bin.0000006 | grep last_committed
#150520 14:23:11 サーバー ID 88 end_log_pos 259 CRC32 0x4ead9ad6 GTID last_committed=0 シーケンス番号=1
#150520 14:23:11 サーバー ID 88 end_log_pos 1483 CRC32 0xdf94bc85 GTID last_committed=0 シーケンス番号=2
#150520 14:23:11 サーバー ID 88 end_log_pos 2708 CRC32 0x0914697b GTID last_committed=0 シーケンス番号=3
#150520 14:23:11 サーバー ID 88 end_log_pos 3934 CRC32 0xd9cb4a43 GTID last_committed=0 シーケンス番号=4
#150520 14:23:11 サーバー ID 88 end_log_pos 5159 CRC32 0x06a6f531 GTID last_committed=0 シーケンス番号=5
#150520 14:23:11 サーバー ID 88 end_log_pos 6386 CRC32 0xd6cae930 GTID last_committed=0 シーケンス番号=6
#150520 14:23:11 サーバー ID 88 end_log_pos 7610 CRC32 0xa1ea531c GTID last_committed=6 シーケンス番号=7
...

元のバイナリログの内容と比較すると、last_committed とsequence_number が増えていることがわかります。last_committed は、トランザクションがコミットされたときにコミットされた最後のトランザクションの番号を示します。トランザクションの last_committed が同じ場合、これらのトランザクションはグループになっており、並列で再生できることを意味します。たとえば、last_committed が 0 のトランザクションが 6 つある場合、グループコミット中に 6 つのトランザクションがコミットされ、これらの 6 つのトランザクションはスレーブ上で並列に再生できることを意味します。

上記の last_committed と sequence_number は、いわゆる LOGICAL_CLOCK を表します。まず、ソースコード内の LOGICAL_CLOCK の定義を見てみましょう。

クラス Logical_clock
 {
 プライベート:
 int64 状態;
 /*
 オフセットは実際の「絶対時間」値から減算されます。
 レプリケーションイベントのログ記録。つまり、イベントは論理的に保持されます
 「相対」形式のタイムスタンプ。意味があるのは
 現在のバイナリログのコンテキスト。
 メンバーはバイナリ ログのローテーションごとに更新 (増加) されます。
 */
 int64 オフセット;
 ......

状態は自動的に増加する値です。バイナリログがローテーションされるたびにオフセットが更新され、ローテーション時の状態値が記録されます。実際、状態とオフセットはグローバルカウント値を記録し、バイナリログは現在のファイルの相対値のみを保存します。 LOGICAL_CLOCK を使用するシナリオは次のとおりです。

クラス MYSQL_BIN_LOG: パブリック TC_LOG
 {
 ...
 公共:
 /* コミットされたトランザクションのタイムスタンプ */
 論理クロック最大コミットトランザクション;
 /* 「準備された」トランザクションのタイムスタンプ */
 論理クロックトランザクションカウンター;
 ...

MYSQL_BIN_LOG クラスに 2 つの Logical_clock 変数が定義されていることがわかります。

  • max_committed_transaction: 最後のグループコミットのlogical_clockを記録します。これは、上記のmysqlbinlogのlast_committedを表します。
  • transaction_counter: 現在のグループ送信の各トランザクションの logcial_clock を記録します。これは、上記の mysqlbinlog のシーケンス番号を表します。

並列レプリケーションテスト

次の図は、MTS を有効にした後のスレーブ サーバーの QPS を示しています。テスト ツールは、sysbench の単一テーブル フル更新テストです。テスト結果によると、パフォーマンスは 16 スレッド以下で最高になり、スレーブの QPS は 25,000 を超える可能性があります。並列実行スレッドの数をさらに 32 に増やしても、それ以上の改善は得られません。元のシングルスレッド再生の QPS はわずか 4000 程度であり、MySQL 5.7 MTS によってもたらされたパフォーマンスの向上が示されています。ただし、テストは単一のテーブルで行われるため、MySQL 5.6 の MTS メカニズムはまったく無力です。

マイスク

MySQL 5.7 並列レプリケーション

並列レプリケーションの構成とチューニング

マスター情報リポジトリ

MTS 機能を有効にした後、必ずパラメータ master_info_repostitory を TABLE に設定してください。これにより、パフォーマンスが 50% ~ 80% 向上します。これは、並列レプリケーションを有効にすると、meta-master.info ファイルの更新が大幅に増加し、リソースの競合も増加するためです。 InnoSQL の以前のバージョンでは、master.info ファイルの更新頻度を制御したり、更新されないようにしたりするためのパラメータが追加されました。このファイルの更新は不要であるため、master-info.log ファイルに基づくリカバリ自体は信頼できません。 MySQL 5.7 では、このオーバーヘッドを削減するために、master_info_repository を TABLE に設定することを Insider は推奨しています。

スレーブ並列ワーカー

slave_parallel_workers を 0 に設定すると、MySQL 5.7 は元のシングルスレッド レプリケーションに退化します。ただし、slave_parallel_workers を 1 に設定すると、SQL スレッド機能はコーディネーター スレッドに変換されますが、再生用のワーカー スレッドは 1 つだけとなり、これもシングルスレッド レプリケーションになります。ただし、これら 2 つのパフォーマンスにはいくつかの違いがあります。コーディネーター スレッドの転送が 1 回多いため、slave_parallel_workers=1 のパフォーマンスは 0 のパフォーマンスよりも悪くなります。Inside のテストでは、次の図に示すように、依然として 20% のパフォーマンス低下が見られます。

マイスク
​​​​​​MySQL 5.7 並列レプリケーション​​​​​​

これにより、別の問題が発生します。ホストの負荷が大きくない場合、グループ送信の効率は低くなります。各グループで送信されるトランザクションは 1 つだけになる可能性が非常に高くなります。スレーブで再生する場合、並列レプリケーションが有効になっているにもかかわらず、パフォーマンスは元のシングルスレッドのパフォーマンスよりも悪くなり、遅延が増加します。賢い友人の皆さん、これを最適化することを考えたことはありますか?

強化されたマルチスレッドスレーブ構成

ここまで述べてきましたが、拡張マルチスレッド スレーブを有効にするのは実際には非常に簡単です。次の設定に従うだけです。

# 奴隷
スレーブ並列タイプ=LOGICAL_CLOCK
スレーブ並列ワーカー = 16
マスター情報リポジトリ=テーブル
リレーログ情報リポジトリ=テーブル
リレーログリカバリ=オン

並列レプリケーション監視

レプリケーションの監視は引き続き SHOW SLAVE STATUS\G で実行できますが、MySQL 5.7 では performance_schema アーキテクチャの下に次のメタデータ テーブルが追加され、ユーザーはより詳細にレプリケーションを監視できるようになりました。

mysql> 'replication%' のようなテーブルを表示します。
 +---------------------------------------------+
 | パフォーマンス スキーマ内のテーブル (レプリケーション %) |
 +---------------------------------------------+
 | レプリケーション アプライア構成 |
 | レプリケーション アプライア ステータス |
 | コーディネータによるレプリケーション アプライアのステータス |
 | ワーカーによるレプリケーション アプライアのステータス |
 | レプリケーション接続構成 |
 | レプリケーション接続ステータス |
 | レプリケーショングループメンバー統計 |
 | レプリケーション グループ メンバー |
 +---------------------------------------------+
 セット内の行数は 8 です (0.00 秒)

要約する

MySQL 5.7 で導入された拡張マルチスレッド スレーブは、何十年もの間 MySQL を悩ませてきたレプリケーション遅延の問題を解決します。これは、無知な PostgreSQL ユーザーに、MySQL に対する以前の印象にとらわれないように再度気づかせるものです。物理レプリケーションは、必ずしも論理レプリケーションよりも優れているわけではありません。MySQL 5.7 の MTS は、遅延の問題を完全に解決できます。

参照:

- http://www.ttlsa.com/mysql/mysql-5-7-enhanced-multi-thread-salve/

- http://moguhu.com/article/detail?articleId=129

- https://www.codercto.com/a/63073.html

- https://dev.mysql.com/doc/refman/5.7/en/replication-options-replica.html#sysvar_slave_preserve_commit_order

MySQL 5.7 並列レプリケーションの原理と実装に関するこの記事はこれで終わりです。MySQL 5.7 並列レプリケーションに関するより関連性の高いコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • MySQL マスタースレーブレプリケーションと読み取り書き込み分離の詳細な説明
  • MySQL マスタースレーブレプリケーション切断の一般的な修復方法
  • MySQL レプリケーション問題の 3 つのパラメータの分析
  • MySql マスタースレーブレプリケーションメカニズムの包括的な分析
  • MySQL シリーズ 13 MySQL レプリケーション

<<:  ウェブデザインと制作に関する科学的原則と提案の要約

>>:  Vueコンポーネント通信のさまざまな方法の詳細な説明

推薦する

Linux で MySQL データベースのインポートおよびエクスポート コマンドを実装する方法

1. mysqldump コマンドを使用してデータベースをエクスポートします (このコマンドのパスで...

Linux 上の Nginx に複数のバージョンの PHP をインストールする

サーバーの LNPM 環境をインストールして構成する場合、複数のバージョンの PHP の共存を考慮す...

HTML ページジャンプコード

次のコードを index.html などのデフォルトのホームページ ファイルとして保存し、ルート デ...

TCP 3 回目のハンドシェイク データ転送プロセス図

RFC793 ドキュメントの SYN フラグを持つプロセス パケットはデータを伝送できません。つま...

Reactは複雑な検索フォームの展開と折りたたみ機能を実装します

時間に余裕を持って、過去を忘れましょう。前のセクションでは、[検索] フォームとクエリおよびリセット...

Linux における効果的なユーザー グループと初期ユーザー グループの実装

まず、/etc/group ファイルを確認します。 [root@localhost /]# cat ...

数千万データを持つMySQLテーブルを最適化する実践記録

序文まずここで説明させてください。インターネット上では、Alibaba では 500 万のデータを異...

Reactマウスの複数選択機能の設定方法

一般的に、リストには選択機能があり、単一選択、二重選択、複数選択が非常に一般的です。カスタム ループ...

MySQLの高可用性と高パフォーマンスのクラスタを構築する方法

目次MySQL NDB Clusterとはクラスター構築のための準備作業クラスターのデプロイを開始す...

CSS 複数 3 列適応レイアウト実装の詳細な説明

序文従来のWEBレイアウトに沿うため、すべてヘッダーとフッターモードの左・中央・右レイアウトで書かれ...

MySQL の低速クエリの最適化: 理論と実践からの制限の利点

多くの場合、クエリの結果は最大で 1 つのデータ レコードになることが予想されます。この場合、制限 ...

MySQLユーザーと権限管理の詳細な説明

この記事では、例を使用して MySQL ユーザーと権限の管理について説明します。ご参考までに、詳細は...

nginx クッキーの有効期間に関する議論の要約

訪問するたびにブラウザにCookieが生成されますが、 Cookieの存在はユーザーにとって良いこと...

MySQL 8.0.18 インストール構成の最適化チュートリアル

MySQLのインストール、設定、最適化は参考用です。具体的な内容は次のとおりです。 MySQL ダウ...

レスポンシブなアコーディオン効果を実現するための CSS3 の詳細な説明

最近、外国人が CSS3 を使用してアコーディオン効果を実現しているビデオを見たので、自分で学習した...