数据库分片和 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的主要内容,如果未能解决你的问题,请参考以下文章

mongodb基础学习11-复制集和分片结合使用

MongoDB:分片(简介 & 自动分片 & 片键)

数据库分片和 JPA

tcp分片和ip分片的区别

MongoDB分片群集(实现分片服务启用分片服务管理单点故障模拟)

实体框架和分片数据库