PostgreSQL对大量数据库的性能如何?


9

我们有一个Web应用程序,该Web应用程序的体系结构要求将任何注册用户(实际上是一家公司)与其他用户隔离开,即,我将使用相同的数据模型运行相同的Webapp,但为每个客户使用不同的数据集。

因此,我们确实考虑过在Postgres中为每个客户创建一个不同的数据库。该解决方案可以扩展到10-20K个数据库吗?多好?

有谁对此有更好的解决方案?

提前致谢。

Answers:


10

在低端,它基本上可以归结为“您可以绝对地说您没有共享数据吗?” 与mysql不同,数据库是postgresql中的绝对约束。你不能SELECT zip_code FROM common.city_zip WHERE city=...,如果你去与不同的数据库中(至少在没有dblink)。

如果您有任何共享数据,则postgresql的“ schema”与mysql称为“ database”相似。你可以CREATE SCHEMA clienta; CREATE TABLE clienta.customer (...);。您将为每个客户端创建一个架构,该客户端的用户将在其搜索路径中首先拥有其架构,并且将授予权限,以便客户端A的用户可以访问clienta和和public架构(及其表)。

您的问题将是,在#个客户端的高端,每个表都存储为一个文件,因此,无论您为每个客户端使用一个数据库,每个客户端使用一个架构还是${client}_customer为表名使用诸如此类的名称,即使每个客户端只有一个表(每个连接加上一个filedescriptor),也可能遇到 10k客户端的filedescriptor限制。当然,您可以使用sysctl快速调整内核的最大文件描述符数量,但是如果您第一次设置的过低,则每个进程的限制(ulimit)将要求重新启动postgresql。

另一种方法是使用“一个大表”和一个客户列来标识该行属于哪个客户(理想情况下,如果每个客户只有一个用户,则按用户名,这会使很多东西变得更容易)。通过完全不授予客户端对该表的任何访问权限,您可以创建特定于客户端的视图(或用于session_user标识当前客户端)。但是,无法直接通过视图进行更新。您将需要定义用于在表上插入/更新/删除的函数(每个客户端一组功能,或者使用session_user),并具有SECURITY DEFINER以特殊用户身份执行并具有在表上插入/更新/删除权限的函数(注意:session_user用于因usercurrent_user 是基于当前上下文,并且在SECURITY DEFINER函数中,该用户始终是定义该函数的用户)。

从性能角度来看,除了fd问题之外,老实说,我不知道在PostgreSQL中使用10000个数据库会发生什么,而在其中有一个包含10000个客户端数据的大表。正确的索引设计应防止大表被缓慢查询。

我会说我在这里为每个客户端使用了单独的数据库(我们添加服务器以保持系统的可用性,根据需要将客户端数据库转移到新服务器上,因此我们永远不会在一台服务器上使用1万个数据库)。我不得不从备份中恢复单个客户端的数据以进行调试或由于用户错误而定期恢复,这在“一个大表”设计上绝对是一场噩梦。同样,如果您打算将定制产品出售给客户,那么“一个大表”设计可能最终使您无法定制数据模型。


嗨,DerfK。由于您所说的原因,我无法使用“一张大桌子”方法。即使今天,每个用户的数据模型都是相同的,我们也不能保证它们将始终相同。另外,我也不了解PSQL中的绝对数据库限制(因为我们确实有一些共享数据)。我想我已经离开了架构和表命名方法。根据您的经验,管理这么多数据库(即使在不同的服务器中)有多困难?
卡洛斯

@Eduardo我遇到的最大困难是确保当每个人都需要更改数据模型时,它就完成了。总有一天,我们将采用Rails系统之类的东西来管理对数据模型的更改,直到那时我有了一个脚本,该脚本在客户端之间循环并在每个数据库上执行相同的命令。由于我们根本不共享数据,因此其他一切都很容易。如果您使用一个具有多个架构的数据库,则仍可以一次使用pg_dump -n(一定也要转储您的通用架构!)列出架构来转储一个客户端架构:psql -E然后\dn
DerfK 2011年

@Eduardo没有为您不正确的功能设计。如果是这样的话,我的汽车将是一艘潜水艇,可以击退熊,并且能够飞向月球。有许多可靠的数据库设计模式,它们使您从一个大表开始,并根据需要添加其他功能。关键是要问自己今天需要什么,以及根据增长预测,您的运维团队将能够提供哪些支持。
耶利米·佩斯卡

@DerfK,您今天使用的Web堆栈是什么?
卡洛斯,

@耶利米,你有一个要点。您有多租户应用程序的经验吗?
卡洛斯,

3

如果没有有关您的应用程序的更多详细信息,很难说您将从此设置中获得任何额外的安全性。如果每个客户端都连接到Web应用程序,并且从Web应用程序到数据库都有一个共享用户,则您没有以与使用单个整体数据库不同的方式隔离数据。通过正确参数化的存储过程访问数据,将为您提供所需的隔离级别,而不会在任何数量的服务器上管理10,000多个数据库而带来管理上的麻烦。

我个人已经在单个数据库服务器上运行了类似的设置,所使用的只是参数化存储过程命中单个数据库。如果可以保证对数据库的唯一访问是通过存储过程,那么就不会有将数据混合到结果中的危险。

如果您确实想继续进行设计,这是我的主要担心:

  1. 用完ulimit -n主机OS上打开的文件描述符()
  2. 调整10,000多个数据库以适应不同的查询模式
  3. 管理具有不同安全性问题的10,000多个数据库(备份和可能的还原,如果服务器发生故障,您是否真的要还原10,000多个数据库?)
  4. 在10,000多个数据库中推出更改

备份和还原客户端数据有多困难?使用存储过程或模式更容易做到这一点吗?如您所述,应用程序设计仅使用一个共享用户来连接数据库。最初,多数据库方法是出于管理考虑而不是安全性考虑的。
卡洛斯,

参数化的存储过程只能防止SQL注入。如果这些过程之一执行SELECT * WHERE clientId = 3,则可能会导致安全漏洞。
mikerobi 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.