負荷を見ているとやはりというか、DBの負荷が大量でWEBサーバは余裕がありそうでした。
なのでDBのインスタンスを増やしてレプリケーションすることにしました。バックアップ体制も整うことですし。
(0)レプリケーションってなんなのか
DBの負荷分散、あるいはバックアップとしてDBのサーバをもう一つ追加します。追加したDBのほうをSlaveと以下表記します。SlaveからMasterのバイナリログを見て同期を取ります。
更新はMasterのDBを使いますが、参照はSlaveのほうを見る事にすれば負荷が分散されます。
(1)Slave用のサーバを用意する
Slave用のサーバを用意しました。通常のサーバ用意するのと同じです。(2)Masterのmy.cnfを修正
Masterの/etc/my.cntの[mysqld]の項目に以下の2つを追加[mysqld]
log-bin
server-id=1
log-bin
server-id=1
server-idの値は適当に1でいいでしょう。
(3)replユーザを作成する
SlaveサーバからMasterのバイナリログを見るためのユーザを作成します。Master側のDBから
mysql > GRANT REPLICATION SLAVE ON *.* TO repl@SlaveのIPアドレス IDENTIFIED BY 'パスワード';
(4)データベースのバックアップ
tarファイルを作るほうがいいんでしょうが、失敗したので普通にdumpしました。・一旦書き込みをロックします。
mysql > FLUSH TABLES WITH READ LOCK;
・dumpを取ります。
mysqldump -u root --password=パスワード -x --databases DB名 > /home/admin/dump.sql
・マスターのバイナリログの位置を確認する
mysql > SHOW MASTER STATUS;
+-------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| XXX | YYY | | |
+-------------------+----------+--------------+------------------+
+-------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| XXX | YYY | | |
+-------------------+----------+--------------+------------------+
(5)ファイル移動
SCPでdumpファイルをSlaveサーバへ移動させますscp /home/admin/dump.sql root@SlaveのIPアドレス:/home/admin
(6)Slaveにてdumpの展開
mysql -u root DB名 < /home/admin/dump.sql
(7)Slaveのmy.confを修正
文字コードなどもMasterと合わせてます。先ほど作成したreplユーザの情報を登録します。
[mysqld]
server-id=2
replicate-do-db=DB名
master-host=マスターのホスト名
master-user=repl
master-password=password
server-id=2
replicate-do-db=DB名
master-host=マスターのホスト名
master-user=repl
master-password=password
(8)バイナリログの位置をSlaveに登録
(4)で確認した値が必要になります。mysql>
CHANGE MASTER TO
MASTER_HOST='MasterのIPアドレス',
MASTER_USER='repl',
MASTER_PASSWORD='password',
MASTER_PORT=3306,
MASTER_LOG_FILE='XXX',
MASTER_LOG_POS=YYY;
CHANGE MASTER TO
MASTER_HOST='MasterのIPアドレス',
MASTER_USER='repl',
MASTER_PASSWORD='password',
MASTER_PORT=3306,
MASTER_LOG_FILE='XXX',
MASTER_LOG_POS=YYY;
(9)お互いのmysqldを再起動する
service mysqld restart
(10)レプリケーション開始
Slave側でmysql> START SLAVE;
(11)レプリケーションの状態を確認
show slave status\G;
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
この2つがYESでないと正常でないのでサービスを開始できません。
サーバ構成が間違っている場合(テーブルが足りないなど)Slave_SQL_Running:Noになってました。
またMaster,Slaveどちらかのみmysqldの再起動をするとSlave_IO_Running: Noになります。お互いに再起動しておきましょう。
スレーブをリセットするには
reset slave;
大丈夫そうならサービスを再開します。
Master側で
UNLOCK TABLES;
(12)CakePHPからSlaveサーバを見るためのユーザ作成
CakePHPkからSlaveDBを見るためのユーザを作成します。
cakeusr@"%"にしておかないと別IPアドレスからアクセスできません。
またSlaveではselect権限だけにしておきます。
Slave側で
mysql > GRANT SELECT ON *.* TO cakeusr@"%" IDENTIFIED BY 'password';
mysql > FLUSH PRIVILEGES;
mysql > FLUSH PRIVILEGES;
(13)CakePHP対応
database.phpにslaveサーバ情報を追加する。 var $slave = array(
'driver' => 'mysql',
'persistent' => false,
'host' => 'SlaveのIPアドレス',
'login' => 'cakeusr',
'password' => 'password',
'database' => 'DB名',
'prefix' => '',
'encoding' => 'UTF-8',
);
'driver' => 'mysql',
'persistent' => false,
'host' => 'SlaveのIPアドレス',
'login' => 'cakeusr',
'password' => 'password',
'database' => 'DB名',
'prefix' => '',
'encoding' => 'UTF-8',
);
またModelクラスで適宜
$this->useDbConfig = 'slave';
とすればSlaveサーバが使われます。
app_modelにメソッド作っておくのが自然でしょうかね。