見出し画像

Rails6.0のmultiple databaseを使ってみた

Railsアプリケーションのデータベースに置いて、冗長化・負荷軽減・高速化などの目的で複数データベース対応を行うことも少なくはありません。

これまで、データベースの切り替え・書き込みや読み込みの違いによる切り替えにはswitch_pointやestablish_connectionを使用していました。

このようなこともあって、先日リリースされたRails6では、複数データベース対応がサポートされました。

そこで、従来の switch_point / establish_connection から Rails6 の multiple database に実装を置き換えてみました。

multiple databaseの設定

まずはdatabase.ymlを2段落から3段落に書き換えます。replicaとして使用する場合には replica: true を付け加えます。また他のデータベースとして、anotherを追加しました。

# database.yml

production:
 main:
   <<: *default
 main_replica:
   <<: *default
   host: <%= ENV['DB_HOST_REPLICA'] %>
   replica: true
 another:
   <<: *another
   migrations_paths: db/another_migrate
 another_replica:
   <<: *another
   host: <%= ENV['ANOTHER_DB_HOST_REPLICA'] %>
   replica: true

次に各モデルで上記の設定を反映させます。writingは更新系、readingは参照系を表しています。他のデータベースを読み込む設定は、別途、抽象クラスを作成し、こちらを子モデルに継承させます。

# application_record.rb

class ApplicationRecord < ActiveRecord::Base
 self.abstract_class = true

 connects_to database: { writing: :main, reading: :main_replica }
end
# another_base.rb

class AnotherBase < ApplicationRecord
 self.abstract_class = true

 connects_to database: { writing: :another, reading: :another_replica }
end
 
# hoge.rb
 
class Hoge < AnotherBase
end

これだけでは、自動でコネクションの切り替えが行われません。自動切り替えを有効にするには、アプリケーションの設定ファイルに以下の行を追加する必要があります。

# production.rb

config.active_record.database_selector = { delay: 2.seconds } # 2秒以内であれば、自分が書き込んだものを読み取る
config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session

これで複数データベース対応は終わりです。

接続状況をログで確認する

複数データベース対応を行ったものの、現在実行中のクエリがどちらのデータベースに接続しているかが分からず、不安になりました。そこでActiveRecordのクエリログに接続状況を表示するようにしました。

ログの出力にはarproxyを使用します。

# config/initializers/arproxy.rb

if Rails.env.development? || Rails.env.test?
 require 'multiple_database_connection_logger'
 Arproxy.configure do |config|
   config.adapter = 'mysql2'
   config.use MultipleDatabaseConnectionLogger
 end
 Arproxy.enable!
end

# lib/multiple_database_connection_logger.rb

class MultipleDatabaseConnectionLogger < Arproxy::Base
 def execute(sql, name = nil)
  role = ActiveRecord::Base.current_role
  name = "#{name} [#{role}]"
  super(sql, name)
 end
end

これでクエリログに [writing] または [reading] が出力されるようになります。

まとめ

複数データベース対応を switch_point や establish_connection から Rails6 のmultiple database に置き換えを行いました。 

またクエリログに接続中のデータベース状況を出力するようにしました。

サードパーティのgemを用いるより、公式の機能を用いたほうが安心できますね。

参考

https://railsguides.jp/active_record_multiple_databases.html

https://tech.raksul.com/2018/08/03/rails_switch_point/





この記事が気に入ったらサポートをしてみませんか?