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. データベースをインストールする1) yum -y install mysql-server (...

Bootstrap 3.0 学習ノートのページレイアウト

今回はレイアウトを中心に学習しますが、これは基本的なHTMLタグのほとんどにも存在するため、比較的簡...

Debian 9 システムに MySQL データベースをインストールする方法

序文タイトルを見ると、誰もが「Debian 9 に MySQL をインストールするにはどうすればいい...

Mysql 8.0 のインストールとパスワードのリセットの問題

Mysql 8.0 のインストールの問題とパスワードのリセット1: MySqlをダウンロードする公式...

React Router V6 のアップデート

目次ReactRouterV6 の変更1. <Switch> が <Routes&...

MySQLクエリで大文字と小文字を区別しない問題を解決する方法

質問最近、SSH フレームワークを使用して実用的なプロジェクトを完了していたときに、長い間悩まされて...

Windows での MySQL 8.0.15 の詳細なインストールと使用のチュートリアル

この記事では、MySQL 8.0.15の詳細なインストールと使用方法のチュートリアルを参考までに紹介...

MySQL外部キーの3つの関係例の詳細な説明

この記事では、例を使用して、MySQL 外部キーの 3 つの関係について説明します。ご参考までに、詳...

MySQL ストレージエンジンの簡単な紹介

1. MySQL アーキテクチャストレージ エンジンを紹介する前に、まずは MySQL アーキテクチ...

Docker で MySQL マスター スレーブ レプリケーションを実装するためのサンプル コード

目次1. 概要1. 原則2. 実装3. スレーブインスタンスを作成する4. マスタースレーブ構成要約...

Unix/Linux システムにおける nobody ユーザーと nologin の詳細な紹介

Unix/Linux システムの nobody ユーザーとは何ですか? 1. Windows システ...

Vue+elementuiはドロップダウンテーブルの複数選択と検索機能を実現します

この記事では、ドロップダウンテーブルの複数選択と検索を実現するためのvue+elementuiの具体...

JavaScriptはスクロールバーの位置を取得し、ページをアンカーポイントまでスライドします。

序文この記事は、私が最近仕事で遭遇した問題を記録したものです。アプリネイティブとフロントエンドのh5...

HTML+CSSで充電水滴融合特殊効果コードを実現

目次序文:成し遂げる:要約:まず効果を見てみましょう: 序文:このアイデアは、Bilibili のア...

Linuxで新しいユーザーを作成し、指定されたディレクトリへの権限を付与する

1 ユーザーを作成し、ユーザーのルートパスとパスワードを指定します useradd -d /home...