データベースの負荷分散の方法の1つレプリケーションという方法があります。マスターDBへの変更をスレーブDBに同期するようにしておいて、書き込みのクエリはマスターDBへ、読み取りのクエリはスレーブDBへと振り分けることで負荷を分散しようというやり方です。
最初にこの方法を知った時は最強じゃんとか思ったんですが、そんな魔法のようなものではなくよく考えてうまく使う必要があります。例えばマスターの更新がスレーブに反映されるのにはタイムラグがあるので、マスターを更新した直後にスレーブを参照してデータがない、とか。まあとにかく色々工夫が必要です。
と、ここまで書いておいてなんですが、今日の記事ではレプリケーションの実践について書くわけではありません。もっとライトな「Railsでデータベースの接続先を変えるためのgemを紹介する」という話です。
いくつかのgemがありましたが、僕が選んだのはシンプルに使えそうだったpostamtというgemです。
有名なのはこっちかも?使った当時は導入に手間どってしまったのでパスしました。
postamtの導入
インストール
# Gemfile
gem 'postamt'
$ bundle install
database.ymlの設定
database.yml
ファイルにスレーブの情報を追加します。スレーブは複数でもよいです。。データベースの名前やユーザー名などを一緒にしておけばhost
を書き換えるだけでOKです。
development:
adapter: mysql2
host: db-master
database: hoge
user: hoge
password: hoge
pool: 5
timeout: 5000
slave1:
host: db-slave1
slave2:
host: db-slave2
ローカルでの動作確認でレプリケーション構成を作るのが面倒なときは、参照するDBは同じにしたまま読み取り専用のユーザーを作っておくことでシミュレート可能です。
postamtの使い方
アクション単位で分ける
READMEから転載w
class UserController < ApplicationController
use_db_connection :slave, for: ['User'], only: [:search]
def search
# SELECTs here are sent to slave
# User#save and User.create would be sent to master anyways.
# Everything in a transaction block too.
@users = User.where(...) # sent to slave
@something_else = SomethingElse.first # sent to master
end
def create
@user = User.new(params[:user])
@user.save! # sent to master
end
def invoice
transaction do
@user = User.where(...) # sent to master
@invoices = Invoice.create(...) # sent to master
end
end
end
モデルのデフォルトを指定する
class User < ActiveRecord::Base
# ...
self.default_connection = :slave1
end
User.where(...) # slave1が使われる
DBを指定して実行する
Postamt.on(:master) do
User.where(...) # masterが使われる
end