この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
こんにちは。KBMJの本多です。
今回はActsAsReadonlyableを用いて、DBへのアクセスの負荷分散を行う方法を紹介します。実際にWEBサービスを運用する場合、WEBサーバー及びDBサーバーが複数台稼働している事があると思います。
今回のケースは以下のサーバー構成という前提で話を進めさせていただきます。
・WEBサーバー(Ruby on Rails)x2台
・DBサーバー(MySQL)x2台
DBサーバーはMySQLの一方向レプリケーションを採用しているため、Master(以下DB1)とSlave(以下DB2)という構成です。
基本的にRailsは1つのDBに対してのみアクセスを行うため、処理の流れは以下のようになります。
WEBx2 <= (SQL) => DB1 <= (レプリケーション) => DB2
この構成で、とある「処理の重いデータ抽出処理」を行う機能を追加した際に、
WEBサーバーやDB1に負荷がかかったため、「この重い処理に関してのみ、DB2へSQLを投げる事は出来ないか?」
と言う要望を受けて、今回のプラグインを使用しました。
1、ActsAsReadonlyableのインストール
railsのrootディレクトリで以下を実行します
ruby script/plugin install svn://rubyforge.org/var/svn/acts-as-with-ro/trunk/vendor/plugins/acts_as_readonlyable
2、ActsAsReadonlyableで接続するDBの設定
config/database.ymlにて以下のようにDB2の情報を追加
production:
database: rails_project_production
host:(DB1のIPアドレス)
(略)
slave:
database: rails_project_production
host: :(DB2のIPアドレス)
(略)
3、slave接続用のModel作成
今回は限定的な処理のみslaveに接続させるため、専用のmodelを作成する事にしました。
元となるmodelが
item.rb(テーブル名、items)
となっている物に対して、以下のslave用modelを作成しました。
slave_item.rb
class SlaveItem < ActiveRecord::Base
set_table_name “items”
acts_as_readonlyable [“slave”]
end
4、重い処理のSQLを3で作成したmodelを使って実行
Item.find_by_sql(重い処理) ↓
SlaveItem.find_by_sql(重い処理)
以上で修正作業は完了です。
これにより、重いSQLに関してのみDB2へ問い合わせが行われ、
DB1の負荷を軽減する事ができるようになります。
また、誤ってSlaveItem経由でアップデート処理等をかけてしまった場合は
DB1へアクセスされるため、もしもの時の予防にもなります。
もちろん、重いSQLの改善も非常に大事ですが、ある程度限界が見えている場合は、
今回のような視点を変えた対処法を取ってみるのはどうでしょうか?
GOOD RAILS!!