Rails Multibase and Models
Rails 6.1 предлагает возможность использования одновременно нескольких баз данных. Для чего?
Rails 6.1 предлагает возможность использования одновременно нескольких баз данных. Для чего? Во первых можно распределить нагрузку и использовать одну из баз только для чтения, другую только на запись, например для админки. Конечно можно использовать разные типы баз данных в одном приложении. Это открывает еще больше возможностей, например для объединения или миграции данных из разных версий приложения.
Первое с чего начинается настройка - config/database.yml
default: &default
adapter: sqlite3
pool: <%= ENV.fetch('RAILS_MAX_THREADS') { 5 } %>
timeout: 5000
development:
primary:
adapter: postgresql
encoding: unicode
host: 127.0.0.1
port: 5432
username: postgres
password: po$tgr$s
pool: <%= ENV.fetch('RAILS_PG_MAX_THREADS') { 5 } %>
database: primary_database
primary_replica:
adapater: postgresql
encoding: unicode
host: 127.0.0.1
port: 5432
username: replica_readonly
password: p@$tgr$s
pool: 5
database: primary_database
replica: true
secondary:
adapter: mysql2
pool: <%= ENV.fetch('RAILS_MY_MAX_THREADS') { 5 } %>
encoding: utf8
username: root
password: r@@t
host: 127.0.0.1
port: 3306
database: secondary_database
migration_paths: db/secondary_migrate
lite:
adapter: sqlite3
pool: <%= ENV.fetch('RAILS_LT_MAX_THREADS') { 5 } %>
database: db/development-lite.sqlite3
migration_paths: db/lite_migrate
timeout: 5000
test:
<<: *default
database: db/test.sqlite3
Для каждого типа данных потребуется установить отдельные пакеты
bundle add sqlite3
bundle add pg
bundle add mysql2
gem 'sqlite3', '~> 1.4'
gem 'pg', '>= 0.18', '< 2.0'
gem 'mysql2', '~> 0.5.3'
Реплицированные базы данных, конечно, должны быть одинаковыми. Пользователь для записи и чтения должен быть разным. Для реплики надо установить replica: true
.
Для хранения миграций для каждой базы отдельно используется migration_paths
. Миграции для отдельных баз должны сохранятся в отдельных директориях с префиксом, соответствующим имени подключения. Необходимо указать в конфигурации путь к миграциям.
primary:
adapter: postgresql
database: primary_database
migration_path: db/primary_migration
Для использования разных баз требуется создать отдельный абстрактный класс для каждой базы, который будет основной моделей:
class PrimaryRecord < ActiveRecord::Base
self.abstract_class = true
connect_to database: { writing: :primary, reading: :primary }
end
Для ApplicationRecord
это может быть
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
connect_to database: { writing: :primary, reading: :primary_replica}
end
Это важно, чтобы подключение к базе определено в одной модели и затем наследовалось остальными. Клиент баз данных имеют ограничения количество одновременных подключений и если подключение производить в каждой модели/классе, то лимит будет быстро исчерпан.
После создания конфигурации станут доступны дополнительные команды миграции:
# rails db:<cmd>:<database>
rails db:create:primary
rails db:migrate:primary
rails db:migrate:seconadry
rails db:migrate:lite
# ...
Для генератора миграций указывается --database=
rails g migration Post title:string text:text --database=primary
Если абстрактного класса нет, он также будет создан. Можно указать доп. --parent=
, если абстрактный класс уже существует и его имя не соответствует правилам именования.
Для использования реплики только для чтения надо включить автоматическое переключение. В зависимости от HTTP команды будет выбираться необходимая база. Когда приложение получает POST
, PUT
, DELETE
, PATCH
запрос то выбирается база для записи, а для GET
или HEAD
реплика.
config.active_record.database_selector = { delay: 2.seconds }
config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
Использование нескольких баз данных в приложение это очень мощная возможность, возможность взглянуть на Rails приложение по новому.