この記事は最終更新から5年以上経過しています。内容が古くなっている可能性があります。
はじめに
2019年07月22日にリリースされた MySQL8.0.17 で、新しく「CLONE」機能が実装されました。
リリースノート
公式リファレンスマニュアル
同機能は、これまでのMySQLの運用方法(特にバックアップ)を大きく変える可能性があり、MySQLユーザからの反響も多いです。そこで、本ブログでも様々な観点から同機能について調査してみました。
1. 機能の概要
「CLONE」機能を端的に言えば、「既存のMySQLの全データを手軽にコピーする機能」です。ここでいう”全データ”とは、InnoDBのスキーマ、テーブル、テーブルスペース、データディクショナリのメタデータを一式含んだ、物理スナップショットのことを示しています。
コピーしたデータはそのままローカルに保存することもできますし、他のサーバに転送すれば全く同じMySQLを複製(クローン)することもできます。
2. 使い方
※ 以下で紹介するコマンドは、MySQL8.0.17時点のものです
CLONE機能を使用する場合は、まずMySQL8.0.17(もしくはそれ以降のバージョン)をインストールします。今回は dbdeployerを使って環境を構築します。このツールについては、過去のブログも参照してください。
|
$ dbdeployer unpack ./mysql-8.0.17-linux-glibc2.12-x86_64.tar.xz $ dbdeployer deploy multiple 8.0.17 --gtid --enable-general-log ... $ ls multi_msb_8_0_17/ clear_all n1 n2 n3 node1 node2 node3 restart_all sbdescription.json send_kill_all start_all status_all stop_all test_sb_all use_all |
次に、CLONE plugin をインストールする必要があります。
|
$ multi_msb_8_0_17/use_all -e "INSTALL PLUGIN clone SONAME 'mysql_clone.so'" # server: 1 # server: 2 # server: 3 $ multi_msb_8_0_17/use_all -e "SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'clone'" # server: 1 PLUGIN_NAME PLUGIN_STATUS clone ACTIVE # server: 2 PLUGIN_NAME PLUGIN_STATUS clone ACTIVE # server: 3 PLUGIN_NAME PLUGIN_STATUS clone ACTIVE |
さらに、sysbenchを使ってテストデータを生成します。こちらも過去のブログで取り上げています。
–table-size=1000000(100万行)の時、テーブルあたり240MBくらいのデータサイズです。今回は sbtest と sbtest2 のデータベースに、それぞれ 10テーブル / 5テーブル ずつ作成します。
※ 以下のコマンドは node1 が127.0.0.1の25718ポートで稼働している前提です(情報はuseコマンドで確認できます)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
$ curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh | sudo bash $ sudo yum -y install sysbench $ multi_msb_8_0_17/node1/use -u root -e "CREATE DATABASE sbtest" $ multi_msb_8_0_17/node1/use -u root -e "CREATE DATABASE sbtest2" $ sysbench --db-driver=mysql --mysql-host=127.0.0.1 --mysql-port=25718 \ --mysql-user=root --mysql-password=msandbox --mysql-db=sbtest \ --tables=10 --table-size=1000000 oltp_read_write \ prepare $ sysbench --db-driver=mysql --mysql-host=127.0.0.1 --mysql-port=25718 \ --mysql-user=root --mysql-password=msandbox --mysql-db=sbtest2 \ --tables=5 --table-size=1000000 oltp_read_write \ prepare $ ls -lh multi_msb_8_0_17/node1/data/sbtest/ | grep sbtest1 -rw-r----- 1 takahashi takahashi 240M 8月 27 11:30 sbtest1.ibd -rw-r----- 1 takahashi takahashi 240M 8月 27 11:38 sbtest10.ibd |
最後に動作検証のため、sbtest2上にMyISAMテーブルを作成します。
|
$ multi_msb_8_0_17/node1/use -e "CREATE TABLE sbtest2.my_test (id int) ENGINE = MyISAM" $ multi_msb_8_0_17/node1/use -e "INSERT INTO sbtest2.my_test VALUES (1),(2),(3)" |
2-1. バックアップ
参照マニュアル
まずはローカルにCLONEを作成してみましょう。コマンドは非常にシンプルです。
※ rootユーザ以外で実行する場合は、BACKUP_ADMIN権限を付与する必要があります
※ 保存先に指定したディレクトリが既に存在している場合、エラーとなります
※ mysqldの実行ユーザ(mysqlユーザ)が保存先ディレクトリへの書き込み権限を持っている必要があります
|
$ mkdir /tmp/cloned_data/ $ chmod 777 /tmp/cloned_data/ ### dbdeployerを使用している場合 $ sudo chown -R mysql:mysql /tmp/cloned_data/ $ time multi_msb_8_0_17/node1/use -u root -e "CLONE LOCAL DATA DIRECTORY '/tmp/cloned_data/first_clone/' " real 0m27.096s user 0m0.009s sys 0m0.011s |
これで /tmp/cloned_data/ の下にクローンデータが作成されました。実行時間も約27秒とそれほど長くありません。
|
$ ls -lh /tmp/cloned_data/first_clone/ 合計 169M drwxr-x--- 2 takahashi takahashi 89 8月 27 16:18 #clone -rw-r----- 1 takahashi takahashi 5.4K 8月 27 16:18 ib_buffer_pool -rw-r----- 1 takahashi takahashi 48M 8月 27 16:18 ib_logfile0 -rw-r----- 1 takahashi takahashi 48M 8月 27 16:18 ib_logfile1 -rw-r----- 1 takahashi takahashi 12M 8月 27 16:18 ibdata1 drwxr-x--- 2 takahashi takahashi 6 8月 27 16:18 mysql -rw-r----- 1 takahashi takahashi 23M 8月 27 16:18 mysql.ibd drwxr-x--- 2 takahashi takahashi 197 8月 27 16:18 sbtest drwxr-x--- 2 takahashi takahashi 101 8月 27 16:18 sbtest2 drwxr-x--- 2 takahashi takahashi 28 8月 27 16:18 sys -rw-r----- 1 takahashi takahashi 11M 8月 27 16:18 undo_001 -rw-r----- 1 takahashi takahashi 11M 8月 27 16:18 undo_002 |
このディレクトリを datadir に指定することで、簡単に同じデータを持ったMySQL(=クローン)を作ることができます。dbdeployer の node2 で試してみましょう。
|
$ multi_msb_8_0_17/node2/stop $ vi multi_msb_8_0_17/node2/my.sandbox.cnf 以下のように書き換え datadir = .../multi_msb_8_0_17/node2/data ↓ datadir = /tmp/cloned_data/first_clone/ $ multi_msb_8_0_17/node2/start ... sandbox server started |
node1のデータがリストアされていることを確認します。なお、仕様上はMyISAMテーブルは対象外となるはずですが、my_testテーブルがリストアされていました。しかし、テーブル自体は空になっていたので、どうやらメタデータのみ含まれているようです。
|
$ multi_msb_8_0_17/node2/use -u root -e "SHOW TABLES FROM sbtest2" +-------------------+ | Tables_in_sbtest2 | +-------------------+ | my_test | | sbtest1 | | sbtest2 | | sbtest3 | | sbtest4 | | sbtest5 | +-------------------+ $ multi_msb_8_0_17/node2/use -u root -e "SELECT * FROM sbtest2.my_test" → empty |
2-2. スレーブ追加
参照マニュアル
CLONE機能を使えば、手軽にレプリケーションスレーブを用意することもできます。
実際に、node1のデータを使ってnode3をスレーブとして設定してみましょう。
まずはnode1でレプリケーション用ユーザとCLONE用ユーザを作成します。どちらもnode3からアクセスできるよう接続元ホストを指定してください(dbdeployerの場合 127.0.0.1 になります)。
|
$ multi_msb_8_0_17/node1/use -u root -e "CREATE USER repl_user@127.0.0.1 IDENTIFIED BY 'replpass'" $ multi_msb_8_0_17/node1/use -u root -e "GRANT REPLICATION SLAVE ON *.* TO repl_user@127.0.0.1" $ multi_msb_8_0_17/node1/use -u root -e "CREATE USER clone_user@127.0.0.1 IDENTIFIED BY 'clonepass'" $ multi_msb_8_0_17/node1/use -u root -e "GRANT BACKUP_ADMIN ON *.* TO clone_user@127.0.0.1" |
次にスレーブとなるnode3側から、CLONEコマンドを実行します。この時、node1への接続情報をつけることで、node1からネットワーク経由で直接データを受け取ることができます(dbdeployerの場合はローカル上で完結します)。
また、別サーバからCLONEデータを受け取る場合は、先に clone_valid_donor_list 変数にサーバ情報を登録しておく必要があります。
※ root ユーザ以外で実施する場合は、CLONE_ADMIN権限が必要となります
|
$ multi_msb_8_0_17/node3/use -u root -e "SET GLOBAL clone_valid_donor_list = '127.0.0.1:25718' " $ time multi_msb_8_0_17/node3/use -u root -e "CLONE INSTANCE FROM clone_user@127.0.0.1:25718 IDENTIFIED BY 'clonepass' " real 0m48.270s user 0m0.011s sys 0m0.009s |
およそ48秒ほどで処理は完了しました。
GTIDレプリケーションを利用している場合は、この後に START SLAVE … MASTER_AUTO_POSITION=1 ; を実行するだけでレプリケーションが開始されます。
※ MySQL8.0のデフォルト認証プラグインである「caching_sha2_password」の仕様上、SSL通信を有効にする必要があります
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
$ multi_msb_8_0_17/node3/use -u root node3 [localhost:25720] {root} ((none)) > CHANGE MASTER TO MASTER_HOST="127.0.0.1", MASTER_PORT=25718, MASTER_AUTO_POSITION = 1, MASTER_SSL = 1, GET_MASTER_PUBLIC_KEY = 1, MASTER_PUBLIC_KEY_PATH='..(略)../multi_msb_8_0_17/node1/data/server-key.pem'; node3 [localhost:25720] {root} ((none)) > START SLAVE USER="repl_user" PASSWORD="replpass"; node3 [localhost:25720] {root} ((none)) > SHOW SLAVE STATUS\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 127.0.0.1 Master_User: repl_user Master_Port: 25718 Connect_Retry: 60 Master_Log_File: Read_Master_Log_Pos: 4 Relay_Log_File: mysql-relay.000001 Relay_Log_Pos: 4 Relay_Master_Log_File: Slave_IO_Running: Yes Slave_SQL_Running: Yes |
正常にレプリケーションが動作することを確認します。
|
$ multi_msb_8_0_17/node1/use -u root -e "CREATE TABLE sbtest2.repl_test (id int)" $ multi_msb_8_0_17/node3/use -u root -e "SHOW TABLES FROM sbtest2" +-------------------+ | Tables_in_sbtest2 | +-------------------+ | my_test | | repl_test | | sbtest1 | | sbtest2 | | sbtest3 | | sbtest4 | | sbtest5 | +-------------------+ $ multi_msb_8_0_17/node3/use -u root -e "STOP SLAVE" |
ちなみに、非GTIDレプリケーションを利用する場合は、CLONEデータのリストア後に performance_schema.clone_status テーブルを参照すれば、レプリケーションを開始すべきバイナリログポジションの情報を確認できます。
|
$ multi_msb_8_0_17/node3/use -u root -e "SELECT BINLOG_FILE, BINLOG_POSITION FROM performance_schema.clone_status" +------------------+-----------------+ | BINLOG_FILE | BINLOG_POSITION | +------------------+-----------------+ | mysql-bin.000003 | 906346956 | +------------------+-----------------+ |
2-3. Group Replication
参照マニュアル
参照マニュアル2
CLONE機能は Group Replication でも利用することができます。具体的には、Clusterに新規追加するノードに対して既存データをリストアする方法がより効率的になります(※)。これは、Galera ClusterのSST機能と同じイメージです。
※ これまではmysqldumpで取得したフルバックアップをリストアするなど時間がかかっていました
まずは検証のため、dbdeployerで Group Replication のテスト環境を作成してみましょう。
ただし、Single Primaryモードの場合 node2とnode3 両方で super_read_only が有効になっているため、rootユーザであってもINSTALL PLUGINコマンドが実行できません。
そこで、今回は –my-cnf-options を使用して、my.cnf(my.sandbox.cnf)に “plugin-load-add=mysql_clone.so” を追記する方法を採用します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
$ dbdeployer deploy --topology=group replication 8.0.17 --single-primary --my-cnf-options "plugin-load-add=mysql_clone.so" ... # Node 1 # select * from performance_schema.replication_group_members +---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | +---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+ | group_replication_applier | 00022718-1111-1111-1111-111111111111 | 127.0.0.1 | 22718 | ONLINE | PRIMARY | 8.0.17 | | group_replication_applier | 00022719-2222-2222-2222-222222222222 | 127.0.0.1 | 22719 | ONLINE | SECONDARY | 8.0.17 | | group_replication_applier | 00022720-3333-3333-3333-333333333333 | 127.0.0.1 | 22720 | ONLINE | SECONDARY | 8.0.17 | +---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+ # Node 2 # select * from performance_schema.replication_group_members ... $ group_sp_msb_8_0_17/use_all -e "SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'clone' " # server: 1 PLUGIN_NAME PLUGIN_STATUS clone ACTIVE # server: 2 PLUGIN_NAME PLUGIN_STATUS clone ACTIVE # server: 3 PLUGIN_NAME PLUGIN_STATUS clone ACTIVE |
node1(PRIMARY)に対して、sysbenchでテストデータをロードします。各種オプションは上でやったものと同じです。
|
$ group_sp_msb_8_0_17/node1/use -u root -e "CREATE DATABASE sbtest" $ group_sp_msb_8_0_17/node1/use -u root -e "CREATE DATABASE sbtest2" $ sysbench --db-driver=mysql --mysql-host=127.0.0.1 --mysql-port=22718 \ --mysql-user=root --mysql-password=msandbox --mysql-db=sbtest \ --tables=10 --table-size=1000000 oltp_read_write \ prepare $ sysbench --db-driver=mysql --mysql-host=127.0.0.1 --mysql-port=22718 \ --mysql-user=root --mysql-password=msandbox --mysql-db=sbtest2 \ --tables=5 --table-size=1000000 oltp_read_write \ prepare |
クラスタから node3 を切り離し、データを削除します。
|
$ group_sp_msb_8_0_17/node3/use -u root -e "STOP GROUP_REPLICATION" $ group_sp_msb_8_0_17/node3/use -u root -e "SET GLOBAL super_read_only=OFF" $ group_sp_msb_8_0_17/node3/use -u root -e "DROP DATABASE sbtest" $ group_sp_msb_8_0_17/node3/use -u root -e "DROP DATABASE sbtest2" $ group_sp_msb_8_0_17/node1/use -u root -e "SELECT * FROM performance_schema.replication_group_members" +---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | +---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+ | group_replication_applier | 00022718-1111-1111-1111-111111111111 | 127.0.0.1 | 22718 | ONLINE | PRIMARY | 8.0.17 | | group_replication_applier | 00022719-2222-2222-2222-222222222222 | 127.0.0.1 | 22719 | ONLINE | SECONDARY | 8.0.17 | +---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+ |
レプリケーションの時と同じようにDONORとなるnode1からCLONEデータを受け取ります。この時、レプリケーション用ユーザ(兼 CLONE用ユーザ)を作成するのを忘れないでください。
|
$ group_sp_msb_8_0_17/node1/use -u root -e "CREATE USER repl_user@'127.0.0.1' IDENTIFIED BY 'replpass' " $ group_sp_msb_8_0_17/node1/use -u root -e "GRANT REPLICATION SLAVE, BACKUP_ADMIN ON *.* TO repl_user@'127.0.0.1' " $ group_sp_msb_8_0_17/node3/use -u root -e "SET GLOBAL clone_valid_donor_list = '127.0.0.1:22718' " $ group_sp_msb_8_0_17/node3/use -u root -e "CLONE INSTANCE FROM repl_user@127.0.0.1:22718 IDENTIFIED BY 'replpass' " |
その後、CHANGE MASTERコマンドを実行してから、GROUP REPLICATIONを開始します。
|
$ group_sp_msb_8_0_17/node3/use -u root node3 [localhost:22720] {root} ((none)) > CHANGE MASTER TO MASTER_USER='repl_user', MASTER_PASSWORD='replpass' FOR CHANNEL 'group_replication_recovery'; node3 [localhost:22720] {root} ((none)) > START GROUP_REPLICATION; Query OK, 0 rows affected (3.61 sec) node3 [localhost:22720] {root} ((none)) > SELECT * FROM performance_schema.replication_group_members; +---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | +---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+ | group_replication_applier | 00022718-1111-1111-1111-111111111111 | 127.0.0.1 | 22718 | ONLINE | PRIMARY | 8.0.17 | | group_replication_applier | 00022719-2222-2222-2222-222222222222 | 127.0.0.1 | 22719 | ONLINE | SECONDARY | 8.0.17 | | group_replication_applier | 00022720-3333-3333-3333-333333333333 | 127.0.0.1 | 22720 | ONLINE | SECONDARY | 8.0.17 | +---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+ 3 rows in set (0.01 sec) |
この手順を使えば、簡単にGroup Replicationのノード追加を行うことができます。
MySQL Shell 8.0.17 のリリース情報によれば、MySQL Shell でも同バージョンからCLONE機能に対応しているようなので、MySQL InnoDB Clusterにおけるノードの運用・管理もかなり楽になるのではないでしょうか。
3. CLONE関連のパラメータ変数
CLONE機能の実装に伴い、新しいパラメータ変数が追加されています。マニュアルに記載された内容を以下の表にまとめました。
参考マニュアル
まとめ
以上、CLONE機能について簡単に見てきました。実際に使ってみた感想としては、コマンドの内容も分かりやすく、今後のMySQL運用の面ではかなり便利な機能だと思います。
今回は検証しきれませんでしたが、次回は以下のような内容についても調査したいと考えています。
- MySQL InnoDB ClusterにおけるCLONE機能の利用
- CLONE機能を使用するうえでのデメリット(制限)
- リモートCLONEが内部的に実行しているコマンド(具体的なデータ転送手段)
- CLONEと従来のバックアップツールの比較
→ こちらの記事に続きます