多租户
可信(或缺乏可信)是阻碍软件即服务(SaaS)采用的头号因素。可以证明,数据是任何业务中最重要的资产——有关产品、客户、员工、供应商等的数据。当然,数据是 SaaS 的核心。SaaS 应用程序为客户提供了对数据的集中式、基于网络的访问,开销比使用本地安装的应用程序时更少。但是,为了利用 SaaS 的好处,组织必须放弃对自己数据的一定程度的控制,相信 SaaS 供应商会保护数据的安全,远离窥探。
为了赢得这种信任,未来 SaaS 架构师的最高优先事项之一是创建一个既强大又安全的 SaaS 数据体系结构,以满足那些担心将重要业务数据控制权移交给第三方的租户或客户的需求,既可以高效运行,同时也能经济高效的管理和维护。
每个正在运行的 PostgreSQL 服务器实例都管理着一个或多个数据库。因此,在组织 SQL 对象(“数据库对象”)的层次中,数据库位于最顶层。在一个 Redrock Postgres 的实例中,角色和表空间都是数据库级别的对象,每个数据库都有自己独立的数据体系结构(包括角色、用户、模式和对象权限相关信息),各个数据库的数据是完全隔离的。
下面是一个 Redrock Postgres 的实例,里面有 3 个模板数据库(template0
,template1
和tenant_base
)和 3 个租户数据库。
计算资源和应用程序代码通常在服务器上的所有租户之间共享,但每个租户都有自己的数据集,这些数据集与属于所有其他租户的数据在逻辑上保持隔离。元数据将每个数据库与正确的租户关联,数据库安全可防止任何租户意外或恶意访问其他租户的数据。
为每个租户提供自己的数据库,可以轻松扩展应用程序的数据模型以满足各个租户的私有需求,在发生故障时从备份中恢复租户的数据也是一个相对简单的过程。通过 Redrock Postgres 的多租户能力,应用程序可以轻松实现 SaaS 模式的部署。
许多客户重视数据安全。例如,银行或医疗记录管理等领域的客户通常有非常强的数据隔离要求,他们甚至都不会考虑不为每个租户提供自己的单独数据库的应用程序。
CREATE DATABASE
实际上通过拷贝一个已有数据库进行工作。默认情况下,它拷贝名为template1
的标准系统数据库。所以该数据库是创建新数据库的“模板”。如果你为template1
数据库增加对象,这些对象将被拷贝到后续创建的用户数据库中。 这种行为允许对数据库中标准对象集合的站点本地修改。例如,如果你把过程语言PL/Scheme安装到template1
中,那么你在创建用户数据库后不需要额外的操作就可以使用该语言。
系统里还有名为template0
的第二个标准系统数据库。这个数据库包含和template1
初始内容一样的数据,也就是说,只包含你的 PostgreSQL 版本预定义的标准对象。在数据库实例被初始化之后,不应该对template0
做任何修改。通过指示CREATE DATABASE
使用template0
取代template1
进行拷贝,你可以创建一个“纯净的”用户数据库,它不会包含任何template1
中的站点本地附加物。 这一点在恢复一个pg_dump
转储时非常方便:转储脚本应该在一个纯净的数据库中恢复以确保我们重建被转储数据库的正确内容,而不和任何现在可能已经被加入到template1
中的附加物相冲突。
另一个从template0
而不是template1
复制的常见原因是,可以在复制template0
时指定新的编码和区域设置,而一个template1
的副本必须使用和它相同的设置。这是因为的template1
可能包含编码相关或区域相关的数据,而template0
中没有。
要通过拷贝template0
来创建一个数据库,使用:SQL 环境中的
CREATE DATABASE dbname TEMPLATE template0;
或者shell中的
createdb -T template0 dbname
可以创建额外的模板数据库,并且实际上可以通过将实例中任意数据库指定为CREATE DATABASE
的模板来从该数据库拷贝。不过,我们必需明白,这个功能并不是设计作为一般性的“COPY DATABASE
”功能。主要的限制是当源数据库被拷贝时,不能有其他会话连接到它。如果在CREATE DATABASE
开始时存在任何其它连接,那么该命令将会失败。在拷贝操作期间,到源数据库的新连接将被阻止。
对于每一个数据库在pg_database
中存在两个有用的标志:datistemplate
和datallowconn
列。datistemplate
可以被设置来指示该数据库是不是要作为CREATE DATABASE
的模板。如果设置了这个标志,那么该数据库可以被任何有 CREATEDB
权限的用户克隆;如果没有被设置,那么只有超级用户和该数据库的拥有者可以克隆它。如果datallowconn
为假,那么将不允许与该数据库建立任何新的连接(但已有的会话不会因为把该标志设置为假而被中止)。template0
通常被标记为datallowconn = false
来阻止对它的修改。template0
和template1
通常总是被标记为datistemplate = true
。
除了
template1
是CREATE DATABASE
的默认源数据库名之外,template1
和template0
没有任何特殊的状态。例如,我们可以删除template1
然后从template0
重新创建它而不会有任何不良效果。如果我们不小心在template1
中增加了一堆垃圾,那么我们就会建议做这样的操作(要删除template1
,它必须有pg_database.datistemplate = false
)。当数据库实例被初始化时,也会创建
postgres
数据库。这个数据库用于做为用户和应用连接的默认数据库。它只是template1
的一个拷贝,需要时可以删除并重建。
我们可以使用一个数据库作为管理数据库,比如:postgres
。在管理数据库中,创建一个表,用于存储租户数据库的相关信息:
CREATE TABLE IF NOT EXISTS tenant_database (
tenantname name,
dboid oid,
dbtemplate oid,
dbowner name,
dbapassword text
);
其中表tenant_database
包括的列如下:
名称 | 描述 |
---|---|
tenantname |
租户的名称 |
dboid |
租户数据库的编号 |
dbtemplate |
租户数据库创建时使用的模板 |
dbowner |
租户数据库的拥有者 |
dbapassword |
租户数据库的拥有者的密码 |
在我们创建新的租户数据库,修改和删除一个租户数据库的时候,更新表tenant_database
中对应的租户数据库的信息。