有一个应用程序,许多公司发布信息。每家公司的数据都是自包含的 - 没有数据重叠。
表现方面,是否更好:
具有持久连接的基于Web的应用程序。
我的想法:
答案 0 :(得分:15)
我建议在PostgreSQL邮件列表中搜索有关多租户设计的信息。那里有很多讨论,答案归结为“它取决于”。在保证隔离,性能和可维护性之间存在各方面的权衡。
一种常见的方法是使用单个数据库,但每个客户使用一个schema(命名空间),每个模式中具有相同的表结构,以及所有数据中相同的数据的共享或公共模式。 PostgreSQL模式就像一个MySQL“数据库”,您可以跨不同的模式进行查询,但默认情况下它们是隔离的。通过单独架构中的客户数据,您可以使用search_path
设置,通常是ALTER USER
customername SET search_path = 'customerschema, sharedschema'
,以确保每位客户都能看到他们的数据,只看到他们的数据。
为了获得额外的保护,您应该REVOKE
ALL FROM SCHEMA customerschema FROM public
然后GRANT
ALL ON SCHEMA customerschema TO thecustomer
这样他们就是唯一一个可以访问它的人,对他们每个人都做同样的事情。表。然后,您的连接池可以使用对任何客户架构具有无 GRANT
访问权限的固定用户帐户登录,但有权SET ROLE
成为任何客户。 (通过向NOINHERIT设置每个客户角色的成员资格来实现这一点,因此必须通过SET ROLE
明确声明权利)。该连接应立即SET ROLE
给它当前正在运营的客户。这样可以避免为每个客户建立新连接的开销,同时保持对程序员错误的强大保护,从而导致访问错误的客户数据。只要池在将连接交给下一个客户端之前执行DISCARD ALL
和/或RESET ROLE
,这将为您提供非常强大的隔离,而不会让每个用户的个别连接受挫。
如果您的Web应用程序环境内置了一个不错的连接池(比如说,您使用的是持久连接的PHP),那么真的需要放置一个good connection pool无论如何,在Pg和Web服务器之间就位,因为与后端的连接太多会损害您的性能。 PgBouncer和PgPool-II是最佳选择,在联系切换期间,您可以轻松地为您执行DISCARD ALL
和RESET ROLE
。
这种方法的主要缺点是维护许多表的开销,因为为每个客户克隆了基本的非共享表集。随着客户数量的增长,它会加起来,在autovacuum运行期间要检查的表的数量开始变得昂贵,并且根据数据库中的表总数进行扩展的任何操作都会减慢。如果您考虑在同一个数据库中拥有数千或数万个客户,那么这就更成问题了,但我强烈建议您在提交之前使用虚拟数据进行一些缩放测试它。
理想的方法可能是具有自动行级安全性控制元组可见性的单个表,但不幸的是PostgreSQL还没有。由于SEPostgreSQL工作添加了合适的基础架构和API,它看起来还在路上,但它不在9.1中。