有一个在 Heroku 中运行的 Rails 5 应用程序;它有两个 DB,一个 Primary 和一个 Follower(只读),follower 是 Primary 的副本。在某些应用领域,我们使用关注者来获取数据。以前,rails 不支持 Multi DB,因此我们使用 Gem Octopus。然而,他们将其置于维护模式,因为 Rails 6 支持多数据库。
我们使用不同的方式通过章鱼访问关注者数据库,例如:
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
class SetupController < ApplicationController
around_action :select_follower
def select_follower(&block)
Octopus.using(ENV['FOLLOWER_DB'], &block)
end
def method1
// enter code here
end
end
@customer = Customer.using(FOLLOWER_DB).find(params[:id])
Octopus.using(:master) do
SidekiqWorker.perform_async(param1, param2)
end
运行良好,已经运行了 5 年多。
最近,我们将 Rails 应用程序从 Rails 5 迁移到 Rails 6,并用多数据库设置替换了 octopus。
数据库.yml
production:
primary:
<<: *default
url: <%= ENV['DATABASE_URL'] %>
secondary:
<<: *default
url: <%= ENV['FOLLOWER_DATABASE_URL'] %>
migrations_paths: db/secondary_migrate
应用程序/模型/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
connects_to database: { writing: :primary, reading: :primary }
end
应用程序/模型/ secondary_application_record.rb
class SecondaryApplicationRecord < ActiveRecord::Base
self.abstract_class = true
connects_to database: { writing: :secondary, reading: :secondary }
end
然后,当我们尝试访问关注者时,就像我们对章鱼所做的那样,就像
class DashboardController < ApplicationController
around_action :select_secondary_db
def select_secondary_db(&block)
SecondaryApplicationRecord.connected_to(role: :reading, &block)
end
def method1
// enter code here
end
end
或
SecondaryApplicationRecord.connected_to(role: :reading) do
Customer.find_by_id(params[:id])
end
在所有这些新方式中,日志显示查询在主数据库中运行,没有任何内容通过跟随者/辅助数据库运行。小学始终存在的情况可能是什么?
我同意@engineersmnky,你的问题是继承问题之一。
我认为你不需要水平分片。只需使用文档中讨论的上下文切换:
ActiveRecord::Base.connected_to(role: :reading) do
Customer.find_by_id(params[:id])
end
我个人从未见过辅助抽象类的单独实现。这可以工作如果你总是希望
Customer
从关注者那里阅读:
class Customer < SecondaryApplicationRecord
end
但是,如果该 id 刚刚写入主节点而追随者尚未写入,则这可能会出现问题。
请注意,Rails 可以提供智能上下文感知切换,因此您可能会进行超出需要的微调:
如果应用程序收到 POST、PUT、DELETE 或 PATCH 请求,应用程序将自动写入写入器数据库。在写入后的指定时间内,应用程序将从主数据库读取。对于 GET 或 HEAD 请求,应用程序将从副本中读取,除非最近有写入。
如果您的
Customer.find_by_id(params[:id])
位于控制器 GET
操作(如 index
)中,则 Rails 会自动从 :reading
跟随器读取(如果写入后已过了指定时间)。
当不在控制器中工作时,我的团队只是根据需要使用手动上下文切换。