Rails6.0 여러 데이터베이스 사용
여러 개의 데이터베이스, 예를 들어 프로젝트 규모가 커질 때 축소하기 쉽고 연결 수를 늘릴 수 있다는 장점
본고는 Rails 응용 프로그램에서 두 개의 데이터베이스와 데이터베이스 Replica를 사용하는 방법을 시도할 것이다
생성된 소스 코드가 GiitHub에 공개됨
다중 데이터베이스
여러 개의 데이터베이스는 한 응용 프로그램에서 여러 개의 데이터베이스로 연결되어 데이터 읽기와 쓰기를 하는 구조이다
데이터베이스 A와 데이터베이스 B 두 개의 DB가 있을 때, Rails는 호출된 모델에 따라 연결된 데이터베이스를 전환할 수 있다
primary/replica 데이터베이스
데이터베이스에 읽기 전용 리플리카(복제)를 미리 준비하고 요구에 따라primary와 리플리카의 구조를 전환합니다
데이터베이스에 대한 액세스가 많아지면 쓰기 및 읽기 DB로 데이터를 분할하여 액세스 로드를 분산할 수 있습니다.
Rails에서 POST, PUT, PATCH, DELETE 요청은primary로 자동으로 전환되며, 최근 쓰기가 없으면 GET, HEAD 요청은 자동으로 Replica로 전환됩니다
데이터베이스 설정
다음 데이터베이스를 만들 때
config/database.yml
:default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password:
host: localhost
port: 3306
development:
common:
<<: *default
database: rails_app_common_development
migrations_paths: db/common_migrate
common_replica:
<<: *default
database: rails_app_common_development
replica: true
school:
<<: *default
database: rails_app_school_development
migrations_paths: db/school_migrate
school_replica:
<<: *default
database: rails_app_school_development
replica: true
primary 데이터베이스migrations_paths
에서 이전 파일의 저장 위치를 지정했습니다Replica에서 지정
replica: true
이 설정을 사용하여 데이터베이스 만들기$ bin/rails db:create
모델 추상 클래스 생성하기
호출된 모델을 통해 연결된 데이터베이스 전환
common 데이터베이스에 연결된 모델 기초 추상 클래스를 만들고 데이터베이스 연결 목적지의 설정을 설명합니다
app/models/common_base.rb
class CommonBase < ApplicationRecord
self.abstract_class = true
connects_to database: { writing: :common, reading: :common_replica }
end
Application RecordCommonBase
를 계승하여 클래스를 만들었습니다. connects_to
쓸 때의 DB와 읽을 때의 DB를 지정했습니다.school 데이터베이스에 연결된 모델의 추상 클래스도 마찬가지로 생성
app/models/school_base.rb
class SchoolBase < ApplicationRecord
self.abstract_class = true
connects_to database: { writing: :school, reading: :school_replica }
end
새 모델 생성 시 CommonBase
또는 SchoolBase
상속이렇게 하면 모델을 통해 데이터베이스의 연결 위치를 전환할 수 있다
모델 생성하기
common 데이터베이스에
Userモデル
를 만들 때우선generate 모델 명령으로 모델 파일과 이전 파일을 만듭니다
$ bin/rails g model user name:string school:references --database common
Running via Spring preloader in process 54763
invoke active_record
create db/common_migrate/20201030135726_create_users.rb
create app/models/user.rb
invoke test_unit
create test/models/user_test.rb
create test/fixtures/users.yml
마이그레이션 파일은 db/common_migrate
디렉토리에 생성--database
에 연결된 데이터베이스, 데이터베이스를 지정합니다.yml 설정migrations_paths
에서 제작school 데이터베이스에서 모델을 만들고 싶을 때 지정
--database school
이제 자기 조절을 해볼게요.# 全てのマイグレーションファイルを適用する場合
$ bin/rails db:migrate
# commonデータベースのマイグレーションファイルのみを適用する場合
$ bin/rails db:migrate:common
모델 파일 최종 수정생성 시 계승
ApplicationRecord
하였으나 User모델은common 데이터베이스를 사용하고자 계승CommonBase
으로 변경하였습니다.- class User < ApplicationRecord
+ class User < CommonBase
end
이렇게 하면common 데이터베이스에서 User 모델을 읽고 쓸 수 있습니다요구에 따라primary/replica가 전환되었는지 확인하십시오
리플리카 준비를 통해 POST, PUT,DELETE,PATCH의 요청은primary에 기록되고GET,HEAD 요청은 리플리카에서 읽습니다
이를 확인하려면 arproxy를 사용하여 조회 로그에 데이터베이스 연결 상황을 표시하십시오
arproxy 설정
Gemfile
에 gem arproxy
bundle install
추가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
요청 시 데이터베이스 연결 확인
curl에서 요청을 보내고 로그를 보면 writing인지 reading인지 확인할 수 있습니다
먼저 해본다users_controller
index
$ curl localhost:3000/users
show
$ curl localhost:3000/users/1
create
$ curl -X POST -H 'Content-Type: application/json' -d '{"name": "saito", "school_id": 1}' localhost:3000/users
update
$ curl -X PUT -H 'Content-Type: application/json' -d '{"name": "saito(updated)"}' localhost:3000/users/5
destroy
$ curl -X DELETE http://localhost:3000/users/5
index, show 동작의 경우reading,create,update,destroy 동작의 경우writing,primary/replica가 전환 중임을 알 수 있습니다
JOIN의 행동을 확인합니다.
같은 데이터베이스 테이블 간에 JOIN
students 테이블을 grade 테이블에서 JOIN일 때 같은 데이터베이스이기 때문에 JOIN이
Grade.joins(:students).where(name: 'grade1')
SQL 릴리즈SELECT `grades`.*
FROM `grades`
INNER JOIN `students` ON `students`.`grade_id` = `grades`.`id`
WHERE `grades`.`name` = 'grade1
서로 다른 데이터베이스의 표 사이에는 JOIN이 있을 수 없습니다.
사용자 테이블에 학생표 JOIN을 넣으려면 데이터베이스가 다르기 때문에 JOIN을 사용할 수 없습니다
User.joins(:students).where(name: 'ogawa')
오류 발생ActiveRecord::StatementInvalid (Mysql2::Error: Table 'rails_app_common_development.students' doesn't exist)
끝말
Rails6.1부터 지원되는 미리 지정된 자르기 기능 기대
참고 자료
Reference
이 문제에 관하여(Rails6.0 여러 데이터베이스 사용), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/youichiro/articles/8a1379e7693882d5f1a2텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)