その他
    ホーム 技術発信 DoRuby ActsAsReadonlyableで負荷分散 - DBの問い合わせ処理(SELECT文)のみをslave用のDBに振り分ける方法の紹介

    ActsAsReadonlyableで負荷分散 - DBの問い合わせ処理(SELECT文)のみをslave用のDBに振り分ける方法の紹介

    この記事はアピリッツの技術ブログ「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!!