What's New inWhat's New in
MySQL 5.7 ReplicationMySQL 5.7 Replication
奥野 幹也
Twitter: @nippondanji
mikiya (dot) okuno (at) gmail (dot) com
@MySQL 5.7 新機能徹底攻略講座
免責事項
本プレゼンテーションにおいて示されている見解は、私
自身の見解であって、オラクル・コーポレーションの見
解を必ずしも反映したものではありません。ご了承くだ
さい。
自己紹介
●
MySQL サポートエンジニア
– 日々のしごと
● トラブルシューティング全般
● Q&A 回答
●
パフォーマンスチューニング
など
●
ライフワーク
– 自由なソフトウェアの普及
● オープンソースではない
● GPL 万歳!!
– 最近はまってる趣味はリカンベント(自転車)
●
ブログ
– 漢のコンピュータ道
– http://nippondanji.blogspot.com/
おかげさまで
新書籍発売と
相成りました。
ありがとうございます!
詳解 MySQL 5.7
止まらぬ進化に乗り遅れないためのテクニカルガイド
● MySQL 5.7 の新機能を網羅的に解説
– 175 の新機能
– WorkLog/Bug Id つき
– コンセプト、仕組み、使い方
●
新機能の理解に必要な前提知識
– 古いバージョンでも適用可能
– アーキテクチャを理解することで
本物の理解を
MySQL 5.7 の
新機能概要
MySQL 5.7 の数多くの新機能
●
実に 150 以上もの新機能が追加された!!
– MySQL 5.7 の新機能完全リスト
https://yakst.com/ja/posts/3037
– yoku0825++
●
レプリケーション関連
●
InnoDB 関連
● オプティマイザー関連
●
セキュリティ関連
●
パフォーマンススキーマ関連
● GIS 関連
● JSON 関連
etc etc...
レプリケーションの新機能
● マルチスレッドスレーブの改良
●
マルチソースレプリケーション
● 準同期レプリケーションの改良
– ロスレスレプリケーション
– パフォーマンスの改善
– ACK を返すスレーブ数の指定
● GTID の改良
– スレーブでの管理が効率化
– 再起動時の GTID 計算方法が効率化
● オンライン操作の拡充
– GTID 有効化
– CHAMGE MASTER の一部
– レプリケーションフィルター
オプティマイザの新機能
● EXPLAIN for CONNECTION
●
JSON EXPLAIN
● コストモデル
– JOIN の順序選択
– 統計情報の正確性
– コストの係数のユーザーによる設定
● GROUP BY
●
FROM 句のサブクエリ
● IN サブクエリ
●
UNION ALL
● ソート
● テンポラリテーブル
InnoDB の新機能
● 一般テーブルスペース
●
テンポラリテーブルの InnoDB 化
● バッファプールのオンラインリサイズ
● UNDO ログの自動トランケート
●
32/64KB ページのサポート
●
REDO ログフォーマットの改善
● バッファプールをダンプする割合の指定
●
ページ統合におけるページ充填率の指定
●
コピーしない ALTER TABLE 操作の増加
InnoDB の新機能 つづき
● 全文検索用プラガブルパーサーのサポート
– ngram あるいは MeCab による日本語の全文検索
● 全文検索の最適化
● 空間インデックスのサポート
● 透過的テーブル圧縮
●
透過的テーブルスペース暗号化
● ダブルライトが不要なとき自動的に無効化
● NUMA サポートの追加
●
InnoDB モニターの有効化方法変更
●
情報スキーマの改良
● デフォルト行フォーマットの指定
InnoDB の新機能
性能改善系
● テンポラリテーブルのための最適化
●
RO トランザクションの性能改善
● RW トランザクションの性能改善
– index->lock の競合改善( SX ロック)
● リードビュー作成の性能改善
●
trx_t のキャッシュ効率改善
● AHI のミューテックス競合改善
● ページクリーナーのマルチスレッド化
●
フラッシュアルゴリズムの改善
●
クラッシュリカバリの性能改善
● ログファイル書き込みの性能改善
●
インデックス作成の高速化
etc
セキュリティ関係の新機能
● パスワード期限の設定
●
ユーザーのロック、アンロック
● SET PASSWORD コマンドの仕様変更
● CREATE USER … IF NOT EXISTS
●
ログイン不可能なユーザーアカウント
●
SSL のセットアップが容易に
– キーファイルの自動生成
– mysql_ssl_rsa_setup
●
透過的テーブルスペース暗号化
●
デフォルトの状態がセキュアに
– test データベースの廃止
– 匿名ユーザーの廃止
– localhost 以外の root の廃止
レプリケーションの概要
バイナリログ リレーログストレージ
エンジン
ストレージ
エンジン
マスター
スレッド
スレーブ I/O
スレッド
スレーブ
SQL スレッド
5. バイナリログ送信
接続スレッド
クライアント
1. COMMIT
2.PREPARE
3.バ
イナ
リログ
更
新
6. 記録
7. 更新を適用
4.COMMIT
マスタースレッドの
改良
バイナリログに対する
グループコミットの調整
● binlog_group_commit_sync_delay
– バイナリログへの同期をする前に待つ時間(マイクロ秒)
– 溜めがあるほうが1回の同期に多くのトランザクションが含
まれる
– レスポンスをわずかに犠牲にすることで、スループットを
向上
● binlog_group_commit_sync_no_delay_count
– 1回の COMMIT に含まれる最大のトランザクション数
グループコミットなし
Tx1
PREPARE
binlog
write
COMMIT
binlog
fsync
時間
Tx2
PREPARE
binlog
write
COMMIT
binlog
fsync
Tx3
PREPARE
binlog
write
COMMIT
binlog
fsync
グループコミットあり
Tx1
PREPARE
binlog
write
COMMIT
時間
Tx2
PREPARE
binlog
write
COMMIT
binlog
fsync
Tx3
PREPARE
binlog
write
COMMIT
メモリ使用効率の改善
● MySQL 5.6 では、マスタースレッドがバイナリログからイベント
を読み取る度にメモリを malloc していた。
– イベントの送信が完了すると free
– 効率が悪い
● MySQL 5.7 ではバッファが十分な場合は使い回す
– バッファが足りない場合は realloc
– 定期的にサイズの見直しをすることでバッファの肥大化を
防止
Mutex 競合の改善
● MySQL 5.6 でバイナリログへのグループコミットが導入された
当初、マスターのクラッシュによってスレーブとの不整合が
起きるバグがあった
– MySQL 5.6.17 で改善
– バイナリログへの R/W が LOCK_log によって守られていた
– write だけでなく fsync についても LOCK_log で保護
● バイナリログへの書き込みとマスタースレッドが LOCK_log
を奪い合う
●
更新処理性能ダウン
● マスタースレッドのスループットダウン
GC 導入当初に生じた
データ整合性の問題
Tx1
マスター
Tx2
Tx3
Tx4
バイナリログ
Tx5
:
スレーブ
Tx1
Tx2
Tx3
リレーログ
:
バイナリログとクラッシュリカバリ
● 2相コミットが行われる条件
– sync_binlog=1
– innodb_support_xa = 1
– ionndb_flush_log_at_trx_commit =1
●
2相コミットの場合のリカバリ処理
– バイナリログの fsync が成功したかどうかでリカバリするか
どうかが決まる
●
バイナリログにトランザクションがあれば永続化
● バイナリログに無ければロールバック
MySQL 5.7 における
LOCK_log 競合の解消
● MySQL 5.6 ではデータ不整合を避けるため LOCK_log で守ら
れた処理が多くなっていた
– R/W, fsync
● MySQL 5.7 では Mutex を分割した
– マスタースレッドが参照するカウンタを追加
● fsync によって更新
●
マスタースレッドが参照
● LOCK_binlog_end_pos で保護
●
マスタースレッドが LOCK_log を取らなくなった
– LOCK_log はバイナリログへの write/fsync を保護
マルチスレッド
スレーブの改良
マルチスレッドスレーブ
( MTS )とは
● 読んで字のごとく、スレーブ側で複数のスレッドを使ってス
レーブのスループットを高める機能
– マスターが複数のスレッドで更新されるのに対し、スレー
ブは単一のスレッドによる更新では、更新性能に差が生じ
てしまう。
– 特に CPU コア数が多く、 IOPS の高いディスクを使ってい
る、 CPU バウンドな環境で顕著。
● MySQL 5.6 から実装
MySQL 5.6 における
MTS の制限
● 並列化の単位はデータベース
– 同じデータベース上の更新は並列化されない
– SQL スレッドが実行中のトランザクションと異なるデータ
ベースを更新するトランザクションは並列化可能
– 複数のデータベースにまたがったトランザクションは不整
合の原因に
– 効果は限定的
MySQL 5.7 の改良
LOGICAL_CLOCK 方式
● マスターで同じグループでコミットされたトランザクションを
スレーブで並列化する方式
●
同一データベースに対する更新を並列化
● スレーブで sync_binlog=1 のとき必須
オーバーラップした
トランザクション
● バイナリログと InnoDB は2相コミット
●
PREPARE → COMMIT の間に若干のタイムラグ
● 同時に PREPARE まで到達したトランザクションはロックの競
合がない
– 並列実行可能
●
バイナリログに追加情報
– last_committed と sequence_number
Tx1
Tx2
PREPARE:l1
PREPARE:l2
COMMIT:s1
オーバーラップ
COMMIT:s2
MTS の設定
[mysqld]
slave_parallel_workers = 64
slave_parallel_type = LOGICAL_CLOCK
slave_preserve_commit_order = 1
log_bin = mysql-bin
log_slave_updates = 1
マルチソース
レプリケーション
MySQL 5.6 ではスレーブが
もてるマスターはひとつだけ
マスター
スレーブ
スレーブ
マスター
マスター
スレーブ
OK
NG
MySQL 5.7 ではスレーブが
複数のマスターを参照可能
マスター
スレーブ
スレーブ
マスター
マスター
スレーブ
OK
OK!!
FOR CHANNEL 句の導入
● CHANNEL = スレーブが参照するマスター
– デフォルトの CHANNEL は空文字列
● CHANGE MASTER TO … FOR CHANNEL 'name'
● START SLAVE FOR CHANNEL 'name'
● STOP SLAVE FOR CHANNEL 'name'
● SHOW SLAVE STATTUS … FOR CHANNEL 'name'
● RESET SLAVE FOR CHANNEL 'name'
マルチソースレプリケーションの
注意事項
● マスター同士で競合する更新をしないようにすること
– 同じテーブルを更新しなければ問題なし
– 同じテーブルを更新する場合
● シャーディングのおまとめ
● 少なくとも SBR は使わない
●
同じ行を異なるマスターで挿入、更新、削除しない
●
あくまでもレプリケーションは非同期
– スレーブのデータはそれぞれのマスターと時差がある
– 同期したデータが参照できることは期待できない
準同期
レプリケーションの
改良
準同期レプリケーションの概要
バイナリログ リレーログストレージ
エンジン
ストレージ
エンジン
マスター
スレッド
スレーブ I/O
スレッド
スレーブ
SQL スレッド
5. バイナリログ送信
6. 記録
7-1. 更新を適用
接続スレッド
クライアント
1. COMMIT
3.バ
イナ
リログ
更
新
7-2a. ACK
7-2b. ACK
8. OK パケット
2.PREPARE
4.COMMIT
準同期がロスレスになった!!
● マスタークラッシュ時にスレーブを昇格すると、マスターから
参照可能だったデータが全てスレーブ上に存在する
●
MySQL 5.6 では、マスターから参照できたデータが、昇格後
のスレーブに存在しないケースがある
– rpl_semi_sync_master_wait_point = AFTER_SYNC
ロスのある更新処理のシナリオ
1. tx1 がデータ x を書き込む
2. データ x がバイナリログに書き込まれる
3. バイナリログがディスクへ同期される
4. データ x がストレージエンジンに COMMIT される
5. この時点でデータ x に対するロックが解除され、他のトラン
ザクションはデータ x を参照できるようになる
• tx2 がデータ x を参照した。
6. クライアントへの応答が停止され、 ACK 待ちの状態になる
7. データ x がスレーブへ転送される前にマスターがクラッシュ
する
8. スレーブのひとつを昇格
• 新たなマスターへ接続してもデータ x は見つからない
ACK を待つタイミングを変更
● ストレージエンジンへ COMMIT する前に ACK を待つ
●
rpl_semi_sync_master_wait_point = AFTER_SYNC
– MySQL 5.6 と同じ動作は AFTER_COMMIT
MySQL 5.6 の準同期マスター
Tx1
PREPARE
binlog
write
COMMIT
時間
Tx2
PREPARE
binlog
write
COMMIT
binlog
fsync
Tx3
PREPARE
binlog
write
COMMIT
ACK を待つ
MySQL 5.7 の準同期マスター
Tx1
PREPARE
binlog
write
COMMIT
時間
Tx2
PREPARE
binlog
write
COMMIT
binlog
fsync
Tx3
PREPARE
binlog
write
COMMIT
ACK を待つ
準同期レプリケーションの
パフォーマンスの改良
● MySQL 5.6 では、マスタースレッドがスレーブへのバイナリロ
グの送信と、 ACK の受信の両方を担っていた。
– ACK を受信するまで、次のイベントを送信することが出来
ない。
● MySQL 5.7 では、 ACK の送受信を行う専用のスレッドが作成
されるようになった。
– ACK スレッド
– performance_schema.threads テーブルで確認
– 並列化により、マスターの更新処理性能が改善
ACK を返すスレーブ数の指定
● rpl_semi_sync_master_wait_for_slave_count
– マスターが ACK を待つスレーブ数
– デフォルトは 1
● rpl_semi_sync_master_wait_no_slave
– スレーブ数が
rpl_semi_sync_master_wait_for_slave_count より少
なくなった場合の挙動
– ON → スレーブが復活するのを待つ(デフォルト)
– OFF → 即座に非同期モードに移行する
●
複数のスレーブがデータを持つことで冗長性を向上
GTID の改良
GTID とは
● Global Transaction Identifier の略
●
トランザクションに世界で固有の ID をつける仕組み
– UUID+ 連番
● UUID はサーバー初回起動時に自動生成
● auto.cnf に格納
– バイナリログに記録される
● サンプル
– 00018785-1111-1111-1111-111111111111:1-100
オンラインで GTID を有効化
• MySQL 5.6 ではオンラインで有効化できなかった
1. マスターへの更新を停止し、スレーブが追いつくのを待つ
2. マスターとスレーブを停止する
3. GTID 関係のオプションをマスターとスレーブ双方で有効
化する
4. マスターとスレーブを起動する。ただし、スレーブは --
skip-slave-start オプションをつける
5. スレーブ側で MASTER_AUTO_POSITION = 1 を指定し
て、 CHANGE MASTER コマンドを実行する
6. レプリケーションを開始する
オンラインで GTID を有効化
つづき
• MySQL 5.7 ではオンラインで有効化できるようになった
1. すべての SQL 文を GTID 互換にする
● SET GLOBAL enforce_gtid_consistency = WARN;
2. マスターとスレーブで GTID が生成されるようにする
• gtid_mode を変更
• OFF→OFF_PERMISSIVE→ON_PERMISSIVE→ON
● SHOW GLOBAL STATUS LIKE
'Ongoing_anonymous_transaction_count';
3. フルバックアップを取得する
4. GTID レプリケーションに切り替える
• STOP SLAVE;
● CHANGE MASTER TO MASTER_AUTO_POSITION = 1;
● START SLAVE;
無効化もオンラインで可能
昇格しないスレーブ上で
GTID の管理が効率化
● GTID はバイナリログに格納される
– スレーブ上では log_slave_updates = 1
– 昇格後には他のスレーブへバイナリログが転送される
– データサイズ大
●
MySQL 5.7 では GTID だけを格納するテーブルが追加
– mysql.gtid_executed
OK パケットに GTID
● OK パケット(処理が成功したときの応答パケット)に GTID を
含めることができるようになった。
– @@global.gtid_executed を参照する必要がなくなった
– 自分が COMMIT したトランザクションの GTID を確実に知るこ
とができる
●
マスターで更新をして、続く参照処理をスレーブで実行した
い
– レプリケーションは非同期なので、マスターの更新が伝搬
している保証はない
– スレーブ上で、マスター更新時の GTID を待てば良い
WAIT_UNTIL_SQL_THREAD
_AFTER_GTIDS
● SQL_THREAD_WAIT_AFTER_GTIDS
– SQL スレッドが停止している場合は NULL
– MySQL 5.6 から実装
●
WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS
– SQL スレッドの状態によらず特定の GTID が実行されるのを
待つ
– MySQL 5.7 で追加
再起動時の GTID 計算方法の変更
● MySQL サーバーは再起動時にバイナリログの GTID を調べ
て、 gtid_executed と gtid_purged を再計算する
●
MySQL 5.6 の計算方法
– gtid_executed
● 新しいほうからバイナリログをスキャン
● Previous_gtids_log_event +そのバイナリログに含まれる
GTID
– gtid_purged
● 古い方からバイナリログをスキャン
●
Previous_gtids_log_event あるいは最も古い GTID から削除
されたバイナリログに含まれる GTID を推定
– GTID が ON のときと OFF のときのバイナリログが混在してい
ると、スキャンするべきバイナリログの数が多くなるケース
がある
MySQL 5.7 では最新と最古の
バイナリログだけをスキャン
● gtid_executed
– 最新のバイナリログに Previous_gtids_log_event や GTID が無
ければ、 GTID は記録されていないと判断
● gtid_purged
– 最古のバイナリログに Previous_gtids_log_event や GTID が無
ければ、 GTID は削除されていないと判断
オンライン
レプリケーション
フィルター
レプリケーションフィルターの
変更をオンラインで実行可能に
● オプション
– --replicate-ignore-db
●
オンラインで変更
– CHANGE REPLICATION FILTER REPLICATE_IGNORE_DB
= (test, admin);
●
注意点
– フィルターは追加ではなく上書き
– 永続化はされないので、必要なら my.cnf も変更する必要
がある
レプリケーション用
パフォーマンス
スキーマ
パフォーマンススキーマから
ステータスの取得が可能に
テーブル名 説明
replication_applier_configuration SQL スレッドの設定を表示する
replication_applier_status SQL スレッドのステータスを表示する
replication_applier_status_by_coordinator コーディネータースレッドのステータスを表示
する
replication_applier_status_by_worker ワーカースレッドのステータスを表示する
replication_connection_configuration IO スレッドの設定を表示する
replication_connection_status IO スレッドのステータスを表示する
まとめ
MySQL 5.7 のレプリケーションは
超絶進化!!
● 機能性向上
– 既存のトポロジーの殻を打ち破ったマルチソース
– ロスレスになった準同期レプリケーション
●
性能向上
– LOGICAL_CLOCK モードのマルチスレッドスレーブ
– マスタースレッドの Mutex 競合解消
– 準同期レプリケーションの ACK スレッド
●
利便性向上
– フィルターの動的変更
– GTID の動的有効化
– パフォーマンススキーマ
による情報取得
もうこれは
使うしかない!!
Q&Aご静聴ありがとうございました。

What's New in MySQL 5.7 Replication