いこーよ の GW の負荷対策として MySQL のレプリケーションを使いマスタースレーブ構成にしてみました。
一番悩んだのがマスタースレーブ構成のためにどのライブリを使うか。 次のような理由から seamless_database_pool をフォークして使うことにしました。
- アプリ起動時にスレーブが落ちていても動く。 ただし、この場合は途中からスレーブが動きだしてもスレーブにはつながらない。
- アプリ起動中にスレーブが落ちても動く。
- 途中でスレーブが復帰すればまたスレーブにつながるようになる。
- マスターをスレーブに含めることも、含めないこともできる。
- マスター、および各スレーブの接続ウエイト指定ができる。
フォークする理由は次のとおりです。
- geokit-rails が UnsupportedAdapter 例外を投げることの対策。
- 毎回セッション使わないようにする。 Rails 3 Slave Databases: Compare Octopus to SDP を参照。
- デバッグ時にマスターにつないでいるのか、スレーブにつないでいるのかわからないので、接続先をログ出力する。
以下、セットアップ手順を書きていきます。
マスターとスレーブ両方にレプリケーション用のアカウントを作成します。
mysql -uroot
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO repl@'%' IDENTIFIED BY 'password';
AWS のセキュリティグループがあるので repl@'%' でよし。
マスターの my.cnf を編集します。
sudo vi /etc/mysql/my.cnf
[mysqld] server-id = 10 log_bin = /var/log/mysql/mysql-bin.log
で MySQL を再起動。 sudo service mysql restart
スレーブの my.cnf を編集します。
sudo vi /etc/mysql/my.cnf
server-id = 11 log_bin = /var/log/mysql/mysql-bin.log relay_log = /var/log/mysql/mysql-relay-bin.log log_slave_updates = 1 read_only = 1 slave_load_tmpdir = /var/tmp
slave_load_tmpdir はマシンを再起動してもファイルが消えないディレクトリにしておかないと問題があるようです。
で MySQL を再起動。 sudo service mysql restart
スレーブで次のようにしてマスターを指定します。
mysql -uroot
CHANGE MASTER TO MASTER_HOST='ec2-123-123-123-123.ap-northeast-1.compute.amazonaws.com', MASTER_USER='repl', MASTER_PASSWORD='password'; show slave status\G
マスターからデータをスレーブに投入します。
mysqldump -uroot --single-transaction --all-databases --master-data=1 | ssh -C deployer@ec2-54-248-109-31.ap-northeast-1.compute.amazonaws.com mysql -uroot
スレーブでレプリケーションを開始します。
mysql -uroot
start slave; show slave status\G
Rails で seamless_database_pool を使うようにします。
application_controller.rb でデフォルトでマスターを使うようにします。
class ApplicationController < ActionController::Base include SeamlessDatabasePool::ControllerFilter use_database_pool :all => :master # 個別にスレーブを使うように指定する。
スレーブを参照したいコントローラで次のように書きます。 アクション毎に指定できます。
class FacilitiesController < ApplicationController use_database_pool [:index, :show, :map_xhr] => :persistent
application_controller.rb で全てスレーブ参照にしても更新系の SQL はちゃんとマスターにいくのですが、 レプリケーションの遅延があった場合よくあるアップデートして show にリダイレクで古い情報を表示してしまう問題と、 ごく一部のアクションが全クエリーのほとんどをしめるという理由からデフォルトマスターで、個々にスレーブを使うように指定する方針にしました。
おかげさまで、今回の GW の瞬間的なピークは New Relic で 3,092rpm を記録し、 Google Analytics リアルタイムのアクディブユーザで 1,900 を越えました。 AWS のオートスケールでアプリサーバも1台から5台まで自動的にスケールしました。
いこーよ のご利用ありがとうございました。
最後に、弊社ではシステムエンジニア、プログラマ、インフラエンジニアなどを募集しています。 おきがるにお問い合わせください。