データベースの負荷分散の方法の1つレプリケーションという方法があります。マスターDBへの変更をスレーブDBに同期するようにしておいて、書き込みのクエリはマスターDBへ、読み取りのクエリはスレーブDBへと振り分けることで負荷を分散しようというやり方です。

最初にこの方法を知った時は最強じゃんとか思ったんですが、そんな魔法のようなものではなくよく考えてうまく使う必要があります。例えばマスターの更新がスレーブに反映されるのにはタイムラグがあるので、マスターを更新した直後にスレーブを参照してデータがない、とか。まあとにかく色々工夫が必要です。

と、ここまで書いておいてなんですが、今日の記事ではレプリケーションの実践について書くわけではありません。もっとライトな「Railsでデータベースの接続先を変えるためのgemを紹介する」という話です。

いくつかのgemがありましたが、僕が選んだのはシンプルに使えそうだったpostamtというgemです。

sauspiel/postamt

有名なのはこっちかも?使った当時は導入に手間どってしまったのでパスしました。

tchandy/octopus

postamtの導入

インストール

1# Gemfile
2gem 'postamt'
1$ bundle install

database.ymlの設定

database.ymlファイルにスレーブの情報を追加します。スレーブは複数でもよいです。。データベースの名前やユーザー名などを一緒にしておけばhostを書き換えるだけでOKです。

 1development:
 2  adapter: mysql2
 3  host: db-master
 4  database: hoge
 5  user: hoge
 6  password: hoge
 7  pool: 5
 8  timeout: 5000
 9  slave1:
10    host: db-slave1
11  slave2:
12    host: db-slave2

ローカルでの動作確認でレプリケーション構成を作るのが面倒なときは、参照するDBは同じにしたまま読み取り専用のユーザーを作っておくことでシミュレート可能です。

postamtの使い方

アクション単位で分ける

READMEから転載w

 1class UserController < ApplicationController
 2  use_db_connection :slave, for: ['User'], only: [:search]
 3
 4  def search
 5    # SELECTs here are sent to slave
 6    # User#save and User.create would be sent to master anyways.
 7    # Everything in a transaction block too.
 8    @users = User.where(...) # sent to slave
 9    @something_else = SomethingElse.first # sent to master
10  end
11
12  def create
13    @user = User.new(params[:user])
14    @user.save! # sent to master
15  end
16
17  def invoice
18    transaction do
19      @user = User.where(...) # sent to master
20      @invoices = Invoice.create(...) # sent to master
21    end
22  end
23end

モデルのデフォルトを指定する

1class User < ActiveRecord::Base
2  # ...
3  self.default_connection = :slave1
4end
5
6User.where(...) # slave1が使われる

DBを指定して実行する

1Postamt.on(:master) do
2  User.where(...) # masterが使われる
3end