MySQLでスレーブ作る

作ることになったので、試してみてつまづいた点とか整理しておく。
なお、レプリケーションそのものの設定手順については、とみぞーノートさんが素晴らしいのでそちらを参照。

今回はお試しなので同じサーバ内にMaster-Slave構成を作る。 同じサーバ内なので以下のものがかぶらないように注意する。

  • datadir
  • log
  • pid
  • socket
  • port  

既にMasterが稼働している状態からSlaveを作る所からはじめる。なお、ソースをコンパイルしてインストールしたので初期状態はだいたい以下のような感じ。

  • datadir => /usr/local/mysql/data
  • log => datadir内
  • pid => datadir内
  • socket => /tmp/mysql.sock
  • port => 3306

これらを、Masterは/var/mysql以下に、Slaveは/var/mysql_slave以下に変更してかぶらないようにする。また、せっかくなのでオペミスを防ぐためにそれぞれ出力先フォルダも変える。(portをのぞく)

Masterの作業

まずはもろもろを準備する。
スレーブの同期を開始するときに、保存しているバイナリログのどこまで行っているかを教えてあげるので、先に確認しておく。

mysql> FLUSH TABLES WITH READ LOCK;
mysql> SHOW MASTER STATUS;
+-----------------+----------+--------------+------------------+
| File            | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-----------------+----------+--------------+------------------+
| mysql-bin.000002 |   528208 |              |                  |
+-----------------+----------+--------------+------------------+
1 row in set (0.01 sec)
mysql> UNLOCK TABLES;

本番稼働しているものの場合は、ここでバックアップをとってロックを解除したらよい。
今回はdatadirもかえたいので、サーバを落として作業する。

$ df -h /tmp
   #=> バックアップ用の空き容量を見ておく
$ ps ax | grep mysql
   #=> 生きてるプロセスを確認
$ /usr/local/mysql/support-files/mysql.server stop
$ ps ax | grep mysql
  #=> プロセスが停止していることを確認
$ mysqldump -u root -p  --all-databases > /tmp/mysql_`date +%Y%m%d%H%M%S`.dump

ディレクトリ、cnfファイルを準備する。
Masterは以下のようにする。

  • datadir => /usr/local/mysql/data
  • log => /var/mysql/logs
  • pid => /var/mysql/run/mysql.master.pid
  • socket => /var/mysql/socket/mysql.master.sock
  • port => 3306 (変更なし)
$ mkdir /var/mysql /var/mysql/data /var/mysql/logs /var/mysql/run /var/mysql/socket 
$ cp -R /usr/local/mysql/data /var/mysql/data
$ mv /var/mysql/datadir/error.log /var/mysql/logs
   #=> エラーログ名は環境ごとで名前違うかも
$ cp /etc/my.cnf /etc/my_master.cnf

my_master.cnf

datadirを変更すると”mysql.plugin doesn't exist”とおこられるので、plugin-dirも併せて変更しておく。エラーログ名やpid名は、起動しているホスト名が入っていたりするので、その辺りは運用にあわせる。

レプリケーションをする場合は、起動インスタンスを識別するためのserver-idと、同期に使用するバイナリログの設定をしておく必要がある。

[mysqld]
port    = 3306
plugin_dir= /usr/local/mysql/lib/plugin
socket    = /var/mysql/socket/mysql.sock
pid-file  = /var/mysql/run/mysql.master.pid
datadir   = /var/mysql/data
log-error = /var/mysql/logs/error.log

# for replication
server-id  = 1
log-bin=mysql-bin

# innodb
innodb_data_home_dir = /var/mysql/data
innodb_log_group_home_dir = /var/mysql/data

ここまで来たら、Masterを起動する。 起動するときは、mysqld_safeに--defaults-fileオプションをつけて、cnfファイルを指定した状態で起動する。 mysql.serverで起動するとデフォルトはmysqlユーザになっているが、mysqld_safeで起動するとログインユーザかオプションで指定したユーザになるので、うまく立ちあがらない場合は、dataディレクトリの権限とかを確認する。

$ mysqld_safe --defaults-file=/etc/my_master.cnf
$ ps ax | grep mysql

Masterに接続してみる。

$ mysql  -u root -p -S /var/mysql/socket/mysql.sock
mysql> show databases;
   #=>  ちゃんとDBがコピーできてるか見る

動いているのを確認したら、Master側でSlave用のDB参照ユーザを作る。 GRANTの権限も専用のREPLICATION SLAVEになっている。

  mysql> GRANT  REPLICATION SLAVE ON *.* TO repl@localhost IDENTIFIED BY 'password';
  Query OK, 0 rows affected (0.00 sec)
  mysql> select user, host  from user;
  +-----------+---------------+
  | user      | host          |
  +-----------+---------------+
  | root      | 127.0.0.1     |
  | root      | ::1           |
  | repl      | localhost     |
  | root      | localhost     |
  +-----------+---------------+
  4 rows in set (0.00 sec)

Master側の作業はこれで一通り。

Slaveの作業

ここまで来たらスレーブを作る。
事前にできる作業も多いので、データ同期までの作業は先にやっておいてもよいかもしれない。

まずはSlave用のディレクトリを作る。

$ mkdir /var/mysql_slave /var/mysql_slave/data
$ /usr/local/mysql/scripts/mysql_install_db --datadir=/var/mysql_slave/data --basedir=/usr/local/mysql
$ mkdir /var/mysql_slave/run /var/mysql_slave/socket /var/mysql_slave/logs
$ cp /etc/my.cnf /etc/my_slave.cnf

できたのでcnfファイルを準備する

my_slave.cnf

ポートとserver-idを変えて、各ディレクトリをslave用に指定する。

[mysqld]
port    = 3307
plugin_dir= /usr/local/mysql/lib/plugin
socket    = /var/mysql_slave/socketl/mysql.sock
pid-file  = /var/mysql_slave/run/mysql.slave.pid
datadir   = /var/mysql_slave/data
log-error = /var/mysql_slave/logs/error.log

# for replication
server-id  = 2
log-bin=mysql-bin

# innodb
innodb_data_home_dir = /var/mysql_slave/data
innodb_log_group_home_dir = /var/mysql_slave/data

あとは、Slaveを起動してデータを入れる。

$ mysqld_safe --defaults-file=/etc/my_slave.cnf
$ ps ax | grep mysql
$ mysql -u root  -p -S /var/mysql_slave/socket/mysql.sock < /tmp/mysql_datetime.dump
$ mysql  -u root -p -S /var/mysql/socket/mysql.sock
mysql> show databases;

ちゃんとデータ入っているところまで行ったら、Masterがどれかを教えて、バイナリの位置を指定して同期を開始する。

  mysql> CHANGE MASTER TO
          MASTER_HOST='localhost',
          MASTER_USER='repl',
          MASTER_PASSWORD='password',
          MASTER_LOG_FILE='mysql-bin.000002',
          MASTER_LOG_POS=528208;
  mysql> START SLAVE;

ちゃんと同期しているかどうかは、Slave_IO_Running,Slave_SQL_Runningが'yes'になっていることを確認する。

  mysql> SHOW SLAVE STATUS\G

苦労した設定で、Masterの更新がSlaveに同期されているのをみると興奮する。

エキスパートのためのMySQL[運用+管理]トラブルシューティングガイド

エキスパートのためのMySQL[運用+管理]トラブルシューティングガイド

Webエンジニアのための データベース技術[実践]入門 (Software Design plus)

Webエンジニアのための データベース技術[実践]入門 (Software Design plus)