在“ table_name_prefix”中指定架构可以吗?

时间:2019-05-14 21:25:48

标签: ruby-on-rails postgresql activerecord

TL; DR:可以在table_name_prefix中指定架构吗?

我们有一个大型的Rails应用程序,它不是传统的多租户应用程序。我们有一百个客户,全部由一个应用程序支持,并且这个数字每年增长不会超过1-2个。当前,每个客户端都有自己的Postgresql数据库。

我们正在解决一些基础结构问题,即拥有这么多不同的数据库...最紧急的是,在同时处理许多客户端数据时,同时存在大量数据库连接。

该应用程序甚至对客户都不可见,因此许多传统的多租户网站理念在这里并不适用。

  • 每个租户都有一个独特的Postgres数据库,在 database.yml。
  • 每个数据库都有一个以租户命名的架构。
  • 我们有一个针对每个租户的模型,代码明显不同。
  • 每个模型都使用建立连接选择不同的数据库和模式。
  • 每个模型都使用具有客户唯一名称的不同table_name_prefix

每个租户的表差异很大。没有希望或渴望使客户正常化。不会动态配置客户端-它始终是带有迁移的新代码版本。

我们打算将每个客户端模式移动到一个数据库中,因此需要更少的不同连接池。我们当前在数据库,架构和表名称中拥有的唯一名称意味着没有名称冲突的可能性。

我们查看了Apartment的宝石,并确定它不适合我们的工作。

我们可以将所有一百个模式添加到schema_search_path中,以便所有客户端可以共享同一连接池,并且仍然可以找到其模式。我们认为,这将使数据库连接数减少一百倍。但是我们对此有些不安。我还没有讨论过多少。也许这行得通,也许没有性能损失查找表。

通过在table_name_prefix中添加模式,我们找到了一个看似有希望的非常简单的解决方案。我们已经将其设置为:

def self.table_name_prefix
  'client99_'
end

通过在Rails 4(当前版本)和Rails 5源代码中进行试验和查看,可以指定模式(“ tenant_99”)以及传统的表前缀(“ client99”):

def self.table_name_prefix
  'tenant_99.client99_'
end

在进行更改之前,查询如下所示:

SELECT COUNT(*) FROM "client99_products"

之后,它们根据需要包含架构:

SELECT COUNT(*) FROM "tenant_99.client99_products"

这似乎可以满足我们的需求,没有任何缺点。我在Interwebs上搜索了鼓励或劝阻这种做法的人,但没有找到任何提及的方式。

因此,通过所有这些,以下是我尚未找到明确答案的问题:

  • 是否担心在schema_search_path中列出太多的架构?
  • 可以在table_name_prefix中放入模式名称吗?

1 个答案:

答案 0 :(得分:1)

以相反的顺序解决您的问题:

  • 是否可以在table_name_prefix中添加架构名称?

只要名称是唯一的(内部和外部),此操作就没有问题。

  • 是否担心在schema_search_path中列出太多的架构?

答案可能是,任何不完全合格的请求(仅按名称请求一个表)都必须按照schema_search_path中列出的顺序搜索每个模式,如果它被缓存在内存中,则几乎没有罚款;在磁盘上搜索所有模式将很慢(与列表中的位置成比例。) 确保首先列出最活跃的模式。

完全合格的请求应该不超过单独的数据库解决方案。

假设您的所有呼叫均完全合格,则该技术应尽可能提供连接池的全部优点。

请记住,通过在通信过程中利用“间隙”,连接池只会最大程度地减少建立连接和断开连接的开销。

例如:

  • 您有四个客户端,其中三个正在不断发出请求,即使有缓冲池,您仍将有四个与服务器的连接。

  • 当您有四个客户端,每个客户端利用四分之一的资源并通过单个连接池进行共享时,优势就体现出来了。

基础数据库(不包括连接开销)的利用率将保持不变,无论是使用单个数据库进行池化还是使用单独的连接连接到单独的数据库。

将数据库组合到一个数据库中的缺点/优点是:不可能将单个数据库移到另一台服务器上以实现PostgreSQL负载平衡方法之外的负载平衡目的。