数据库分片和 Rails
Posted
技术标签:
【中文标题】数据库分片和 Rails【英文标题】:Database sharding and Rails 【发布时间】:2010-09-07 19:59:07 【问题描述】:在 Rails 中处理分片数据库的最佳方法是什么?分片应该在应用层、活动记录层、数据库驱动层、代理层还是其他什么地方处理?各有什么优缺点?
【问题讨论】:
【参考方案1】:FiveRuns 有一个名为 DataFabric 的 gem,它执行应用程序级分片和主/从复制。可能值得一试。
【讨论】:
【参考方案2】:我假设我们谈论的是水平分区而不是垂直分区 (here are the differences on Wikipedia)。
首先,在考虑水平分区之前,尽可能拉伸垂直分区。在 Rails 中很容易让不同的模型指向不同的机器,并且对于大多数 Rails 站点来说,这会让你走得更远。
对于水平分区,在理想情况下,这将在 Rails 中的应用层处理。但是,虽然这并不难,但在 Rails 中也不是微不足道的,而且当您需要它时,通常您的应用程序已经超出了可行的范围,因为您到处都有 ActiveRecord 调用。没有人,开发人员或管理人员,喜欢在你需要它之前就开始工作,因为每个人都宁愿处理用户现在将使用的功能,而不是在你的流量爆炸后多年可能不会发挥作用的分区。
ActiveRecord 层...据我所见并不容易。需要大量猴子修补到 Rails 内部。
在Spock,我们最终使用自定义 MySQL 代理 处理此问题,并将其在 SourceForge 上以Spock Proxy 开源。 ActiveRecord 认为它正在与一台 mysql 数据库机器交谈,而实际上它正在与代理交谈,然后代理与一个或多个 MySQL 数据库交谈,合并/排序结果,并将它们返回给 ActiveRecord。只需要对 Rails 代码进行少量更改。查看 Spock Proxy SourceForge 页面了解更多详细信息以及我们选择这条路线的原因。
【讨论】:
+1 用于在表级别拉伸垂直分区。使用 ActiveRecord,为了将“热”数据与其他数据隔离开来,将表拆分为具有较少列的几个表是相当轻松的。如果您使用的是 MySQL,这会产生很大的不同。【参考方案3】:对于像我这样没有听说过分片的人:
http://highscalability.com/unorthodox-approach-database-design-coming-shard
【讨论】:
【参考方案4】:将 Rails 连接到多个数据库并不是什么大问题——您只需为每个分片创建一个覆盖连接属性的 ActiveRecord 子类。如果您需要进行跨分片调用,这将变得非常简单。然后,当您需要在分片之间进行调用时,您只需编写一些代码。
我不喜欢 Hank 拆分 rails 实例的想法,因为除非你有一个大的共享库,否则在实例之间调用代码似乎很有挑战性。
此外,在开始分片之前,您应该考虑执行Masochism 之类的操作。
【讨论】:
【参考方案5】:为了让 rails 与复制环境一起工作,我建议使用 my_replication 插件,它有助于在运行时将数据库连接切换到其中一个从属服务器
https://github.com/minhnghivn/my_replication
【讨论】:
【参考方案6】:rails 6.1 提供了切换每个数据库连接的能力,因此我们可以进行水平分区。
分片在三层配置中声明如下:production:
primary:
database: my_primary_database
adapter: mysql2
primary_replica:
database: my_primary_database
adapter: mysql2
replica: true
primary_shard_one:
database: my_primary_shard_one
adapter: mysql2
primary_shard_one_replica:
database: my_primary_shard_one
adapter: mysql2
replica: true
然后通过分片键将模型与 connected_to API 连接
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
connects_to shards:
default: writing: :primary, reading: :primary_replica ,
shard_one: writing: :primary_shard_one, reading: :primary_shard_one_replica
end
然后模型可以通过 connected_to API 手动交换连接。如果使用分片,则必须同时传递角色和分片:
ActiveRecord::Base.connected_to(role: :writing, shard: :shard_one) do
@id = Person.create! # Creates a record in shard one
end
ActiveRecord::Base.connected_to(role: :writing, shard: :shard_one) do
Person.find(@id) # Can't find record, doesn't exist because it was created
# in the default shard
end
参考:
https://edgeguides.rubyonrails.org/active_record_multiple_databases.html#horizontal-sharding https://dev.to/ritikesh/multitenant-architecture-on-rails-6-1-27c7【讨论】:
【参考方案7】:在我看来,最简单的方法是在 rails 实例和 DB 分片之间保持 1:1。
【讨论】:
【参考方案8】:代理层更好,它可以支持所有程序语言。
例如:Apache ShardingSphere 的代理。
Apache ShardingSphere 有 2 种不同的产品,ShardingSphere-JDBC 用于应用层,仅适用于 Java 语言,ShardingSphere-Proxy 用于代理层,适用于所有程序语言。
仅供参考:https://shardingsphere.apache.org/document/current/en/user-manual/shardingsphere-proxy/
【讨论】:
【参考方案9】:取决于 Rails 版本。正如@Oshan 所说,较新的 rails 版本提供了对分片的支持。但是,如果您不能更新到较新的版本,您可以使用 octopus gem。 宝石链接 https://github.com/thiagopradi/octopus
【讨论】:
以上是关于数据库分片和 Rails的主要内容,如果未能解决你的问题,请参考以下文章