MySQL NDB Clusterでも、通常のMySQL同様にレプリケーションを組む事ができます。
MySQL NDB Clusterをマスターに、InnoDBエンジンを使用したMySQLをスレーブにした構成も、Oracle社ではサポートされています。
今回は、上記の構成での構築手順をご紹介します。
VM環境
HOST名 | IP | 用途 |
---|---|---|
mgm | 192.168.33.230 | 管理ノード |
data1 | 192.168.33.231 | データノード |
data2 | 192.168.33.232 | データノード |
sql1 | 192.168.33.233 | SQLノード |
sql2 | 192.168.33.234 | SQLノード |
slave | 192.168.33.235 | InnoDBスレーブ |
OS
CentOS 7.3
MySQL NDB Clusterバージョン
7.5.8
管理/データノードのデータディレクトリ
/var/lib/mysql-cluster
SQLノード/InnoDBスレーブのデータディレクトリ
/var/lib/mysql
以下のVagrantfileを使用することで上記環境が作成されます。
Vagrantfile一式
※多数のyumを実行しますので、Network通信にご注意ください。
vagrantについては説明を割愛しますので、公式をご確認ください。
MySQL NDB Cluster起動については以下を参考に行います。
21.2.5 Initial Startup of NDB Cluster
MySQL NDB Cluster、スレーブサーバの全ノードが正常に起動している事を前提とします。
マスター側のレプリケーション準備
SQLノードの/etc/my.cnfには以下の設定を追記します。
重要なのはndb_log_update_as_writeです。
MySQL NDB Clusterはそのアーキテクチャ上、UPDATEを”WRITE”としてバイナリログに書き込みますが、 InnoDBでは”WRITE”を解釈することができず、レプリケーションエラーとなります。
そのため、UPDATE操作はUPDATEとして書き出すように設定を行います。
1 2 3 4 5 6 |
server-id=141 log_bin ndbcluster ndb-connectstring=192.168.33.230 ndb_log_update_as_write = OFF |
※設定後はmysqldの再起動を実施
レプリケーションのためのユーザーを作成します。
もし、複数のSQLノードをマスターとする可能性がある場合は、全てのSQLノードにユーザーを作成してください。
1 2 |
mysql> CREATE USER rep@`192.168.33.235` IDENTIFIED BY 'password'; mysql> GRANT replication slave ON *.* to rep@`%`; |
マスターにテストデータを作成します。
いずれかのSQLノードで一度実行して下さい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
mysql> CREATE DATABASE test; mysql> DELIMITER // DROP PROCEDURE IF EXISTS test.ins; DROP TABLE IF EXISTS test.test; CREATE TABLE test.test(i INT PRIMARY KEY,v VARCHAR(1000)) ENGINE NDB; CREATE PROCEDURE test.ins(start_no int,end_no int) BEGIN WHILE start_no <= end_no do INSERT INTO test.test VALUES (start_no,concat('test',start_no)); set start_no = start_no + 1; END WHILE; END; // DELIMITER ; mysql> CALL test.ins(1,1000) |
マスター側でバックアップを取得
データ自体のバックアップは、MySQL NDB Clusterネイティブのバックアップを使用します。
以下は管理ノードで実行します。
1 2 3 4 5 6 7 8 |
# ndb_mgm -e "START BACKUP" Connected to Management Server at: localhost:1186 Waiting for completed, this may take several minutes Node 1: Backup 1 started FROM node 101 Node 1: Backup 1 started FROM node 101 completed StartGCP: 244130 StopGCP: 244133★ #Records: 3103 #LogRecords: 0 Data: 82972 bytes Log: 0 bytes |
後述するレプリケーションの開始のために、StopGCPの値が必要となりますので、
控えておいてください。
バックアップはデフォルトでは各データノードの<データディレクトリ>/BACKUP配下に出力されます。
出力されたバックアップはデータノードごとに水平分割されたデータが含まれています。
この事より、全データノード分のバックアップが必要です。
1 2 |
# ls /var/lib/mysql-cluster/BACKUP/ BACKUP-1 |
また、スレーブ側では一部の構造を変更する必要がありますので、メタデータのみのバックアップを、mysqldumpで取得します。
いずれかのSQLノードで実行します。
1 2 |
# mysqldump -uroot -p --no-data test > metadata.sql # sed -i 's/ENGINE=ndbcluster/ENGINE=innodb/g' metadata.sql |
データバックアップをInnoDBへリストアするための準備
MySQL NDB ClusterのネイティブバックアップはそのままInnoDBのテーブルにリストアすることはできません。
幾つかのリストア方法が考えられますが、ここではndb_restoreコマンドを使用して一度TSVに書き出した後、LOAD DATA INFILE文でデータをリストアする方法をご紹介します。
まずは、スレーブサーバに全てのバックアップを集約します。
バックアップファイルには、各データノードのNodeIdが付いているため、上書きされる心配はありません。
1 |
# scp -pr /var/lib/mysql-cluster/BACKUP 192.168.33.235:~/ |
スレーブサーバで以下のようにTSVファイルを作成します。
1 2 3 4 |
# cd ~/BACKUP # mkdir tab-files # ndb_restore -n 1 -b 1 --print-data --tab=$(pwd)/tab-files --append BACKUP-1 # ndb_restore -n 2 -b 1 --print-data --tab=$(pwd)/tab-files --append BACKUP-1 |
上記の操作により、tab-files配下にTSVが出力されます。
そして、もう一つ行わなければならない作業がバックアップ中の更新処理によって出力されたREDOログの適用です。
こちらは、ndb_restoreコマンドにより、SQLとして出力することができます。
1 2 3 4 |
# ndb_restore -n 1 -b 1 --print-sql-log BACKUP-1 \ | egrep '^INSERT|^DELETE|^UPDATE' >> dump-log.sql # ndb_restore -n 2 -b 1 --print-sql-log BACKUP-1 \ | egrep '^INSERT|^DELETE|^UPDATE' >> dump-log.sql |
※バックアップ中に更新がなかった場合は出力されません。
今回はデータ量も少ないため、こちらの操作は行いませんでした。
また、MySQL NDB Clusterにはmysql.ndb_apply_statusという、マスターからのレプリケーション操作を記録するためのテーブルがありますが、 このテーブルは管理ノードに接続した際に作成されるものであるため、InnoDBのスレーブには存在しません。
ですので、手動で作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
mysql> USE mysql mysql> CREATE TABLE `ndb_apply_status`( `server_id` int(10) unsigned NOT NULL, `epoch` bigint(20) unsigned NOT NULL, `log_name` varchar(255) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL, `start_pos` bigint(20) unsigned NOT NULL, `end_pos` bigint(20) unsigned NOT NULL, PRIMARY KEY(`server_id`) USING HASH ) ENGINE = innodb DEFAULT CHARSET = latin1 ; |
※ndb_apply_statusはもともとndbclusterエンジンですので、innodbに変更します。
スレーブの設定
以下のパラメータを追記します。
1 2 3 4 5 6 7 |
server-id=52 binlog_format=row skip_slave_start replicate_wild_ignore_table=mysql.ndb_index% slave_exec_mode = IDEMPOTENT secure_file_privs="" innodb_page_size=32K |
ndb_index%から始まるテーブルは、ndbclusterエンジンにおけるインデックスの統計情報が格納されますが、それ以外のエンジンを使用する場合は不要ですので除外します。
また、MySQL NDB Clusterでは通常エラーが発生するようなINSERT時のユニークキーの重複をエラーにせずに同じキーのデータを上書きするという動作となっていますので、スレーブでも追随する必要があります。
そのためslave_exec_mode=IDEMPOTENTを設定しなければなりません。
また、innodb-page-sizeを32Kにすることが推奨されます。
inndb_page_sizeはデータディレクトリの初期化時に指定する必要があります。
ndbclusterとinnodbで行の最大長が異なり、ndbclusterでは14K、innodbではデフォルトは8Kであるためサイズの大きい行のレプリケーション時にエラーとなる可能性があります。
ただし、innodb_page_sizeを変更するとテーブル圧縮が使用できなくなるため、ご注意ください。
スレーブ側でスキーマ作成
metadata.sqlをスレーブサーバに配置し、スキーマを作成します。
1 2 3 |
mysql> create database test; mysql> use test mysql> source metadata.sql |
スレーブサーバがInnoDBである場合、スレーブ側でのユニークキーや外部キーの使用はレプリケーションエラーの原因となりやすく、推奨されません。
そのため、スレーブでは一度メタデータをリストアした後、ユニークキー、外部キーを削除し、一意性やリレーションについては、マスター側で担保します。
そして必要に応じてインデックスの貼り直しを行います。
InnoDB側では実行されるクエリに合わせて、インデックス構成を変更してもよいでしょう。
外部キーに関連しますが、MySQL NDB ClusterとInnoDBのレプリケーションではon update/delete cascade はレプリケーションされないため、サポートされませんのでご注意ください。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# 外部キー確認 mysql> SELECT * FROM information_schema.INNODB_SYS_FOREIGN WHERE id like 'schema_name/%'; # ユニークキー確認 mysql> SELECT TABLE_SCHEMA,TABLE_NAME,INDEX_NAME,COLUMN_NAME,NON_UNIQUE FROM information_schema.statistics WHERE table_schema='test' and non_unique=0 and index_name != 'PRIMARY'; # 外部キー削除 mysql> ALTER TABLE <table_name> DROP FOREIGN KEY `<fk_name>`; # ユニークキー削除 mysql> ALTER TABLE <table_name> DROP INDEX <index_name>; # INDEX作成 mysql> ALTER TABLE <table_name> ADD INDEX <index_name>(<column_name>); |
リストアの実行
すでにスキーマはリストアしましたので、LOAD DATA IN FILEでデータをリストアします。
1 |
mysql> LOAD DATA INFILE '/var/lib/mysql-files/test.txt' INTO test.test; |
そして、バックアップ中にデータ更新があった場合は、SQLファイルを実行します。
1 2 |
mysql> USE test mysql> SOURCE dump-log.sql |
これでバックアップ時点までのデータが格納されたスレーブサーバができました。
以降、レプリケーションの設定を行います。
バイナリログのポジションを取得
スレーブサーバでレプリケーションを開始するためにはbinlogのpositionが必要です。
そのため、マスターにてバックアップを取得した時点のGCPを元にpositionを取得します。
なお、バックアップ以降全く更新がない場合は、以下SQLでポジションが表示されません。
ここではテストデータを再度投入します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
mysql> call test.ins(1001,1500); mysql> SET @stopgcp = 244133; mysql> SELECT SUBSTRING_INDEX(File, '/', -1) AS binlog_file, Position AS binlog_position FROM mysql.ndb_binlog_index WHERE gci > @stopgcp ORDER BY epoch ASC LIMIT 1; +-----------------+-----------------+ | binlog_file | binlog_position | +-----------------+-----------------+ | sql1-bin.000010 | 776099554 | +-----------------+-----------------+ |
スレーブでレプリケーションを開始
あとは通常のレプリケーション同様にCHANGE MASTERでマスターの情報を登録し、slaveを開始します。
1 2 3 4 5 6 7 8 |
mysql> change master to master_host = "192.168.33.233" ,master_user = "rep" ,master_password = "password" ,master_port = 3306 ,master_log_file = "sql1-bin.000010" ,master_log_pos = 776099554 ; |
1 |
mysql> start slave; |
レプリケーションの正常性確認
正常にレプリケーションされる事をご確認ください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
mysql> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.33.233 Master_User: rep Master_Port: 3306 Connect_Retry: 60 Master_Log_File: sql1-bin.000010 Read_Master_Log_Pos: 776109980 ・・・略 aster_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: ・・・略 |
以上でレプリケーション環境の作成ができました。
ndbclusterエンジンが不得手とするJOINの高速化、バックアップ用DB等、InnoDBによるスレーブの用途は多岐に渡ります。
MySQL NDB Clusterでのレプリケーションでお困りの際にはぜひご検討ください。