节点
Citus是一个PostgreSQL扩展,它允许数据库服务器(即节点)在一个Shared Nothing的架构中彼此协调。这些节点形成了一个集群,使得PostgreSQL能够比一台计算机使用更多的CPU内核来存储更多的数据,同时还允许通过向集群添加更多节点来扩展数据库。
协调节点与数据节点
每个集群都有一个起协调作用的特殊节点(其他节点称为数据节点)。应用程序将它们的查询发送到协调节点,协调节点将查询转发给相关的数据节点并汇总结果。
对于每个查询,协调节点要么将其路由到单个数据节点,要么在多个数据节点上并行执行,具体取决于所需的数据是驻留在单个节点还是多个节点上。协调节点通过查询其元数据表来做到这一点,这些特定Citus系统表跟踪DNS名称和数据节点的运行状况,以及节点间的数据分布。
分布式数据
表类型
在Citus集群中有三种类型的表,每一种用于不同的作用。
1. 分布表
第一种类型是最常见的分布式表。这些表看起来是SQL语句的普通表,但是是跨数据节点的水平分区(即,分片)。
Citus在整个集群中不仅运行DML语句,而且运行DDL语句,因此更改分布式表的模式会串联起来,以在各个数据节点之间更新表的所有分片。
Citus使用算法分片来将行分配给分片,这意味着分配是确定的,在一般场景中是基于称为分布列的特定表列的值,集群管理员在分发表时必须指定此列。
2. 参考表
参考表是一种分布式表,它的全部内容集中在一个分片中,在每个数据节点上复制该内容。因此,对任何数据节点的查询都可以在本地访问参考表,无需从另一个节点请求行而带来的网络开销。参考表没有分布列,因为不需要区分每行的不同切分。
参考表通常很小,用于存储与在任何数据节点上运行的查询相关的数据,例如,订单状态或产品类别等枚举值等。
当与参考表交互时,我们自动对事务执行两阶段提交(2PC)。Citus确保数据始终处于一致的状态,无论当前是在编写、修改还是删除它。
3. 本地表
应用程序连接和交互的协调节点是一个安装了Citus扩展的普通PostgreSQL数据库。因此,我们可以创建普通的表并选择不对它们进行切分。这对于不参与连接查询的小型管理表非常有用,比如,用于应用程序登录和身份验证的users表。
创建标准的PostgreSQL表很容易,因为它是默认的,在运行CREATE TABLE后即可得到。在几乎所有的Citus部署中,我们都能看到标准的PostgreSQL表与分布式表和参考表共存。实际上,Citus本身就是使用本地表保存集群元数据的。
分片
1. 分片定义
协调节点上的pg_dist_shard元数据表包含系统中每个分布式表的每个分片的信息。每一行匹配一个shardid和一个Hash空间中的整数范围(shardminvalue, shardmaxvalue):
SELECT * from pg_dist_shard;
logicalrelid | shardid | shardstorage | shardminvalue | shardmaxvalue
---------------+---------+--------------+---------------+---------------
github_events | 102026 | t | 268435456 | 402653183
github_events | 102027 | t | 402653184 | 536870911
github_events | 102028 | t | 536870912 | 671088639
github_events | 102029 | t | 671088640 | 805306367
(4 rows)
如果协调节点希望确定哪个分片包含github_events行,那么它将Hash该行中的分布列的值,并检查哪个shard的范围包含该Hash值。
2. 分片位置
假设要查询的行与分片102027相关联,那么应该将行读写到一个数据节点中名为github_events_102027的表中。具体是哪个数据节点,这完全由元数据表决定,分片到数据节点的映射称为分片位置。
Citus将协调节点上查询重写为引用特定表(如github_events_102027)的片段,并在对应的数据节点上运行这些片段:
SELECT
shardid,
node.nodename,
node.nodeport
FROM pg_dist_placement placement
JOIN pg_dist_node node
ON placement.groupid = node.groupid
AND node.noderole = 'primary'::noderole
WHERE shardid = 102027;
┌─────────┬───────────┬──────────┐
│ shardid │ nodename │ nodeport │
├─────────┼───────────┼──────────┤
│ 102027 │ localhost │ 5433 │
└─────────┴───────────┴──────────┘
在表跨集群分布时,每个表的分片数量是可配置的。分片数量的最佳选择取决于具体的使用场景。
3. 分片备份
Citus允许复制分片以防止数据丢失。有两种复制模式:Citus复制和流复制。前者创建额外的备份分片位置,更新其中任何一个分片都需要对所有分片运行查询。后者效率更高,它利用PostgreSQL的流复制将每个节点的整个数据库备份到一个关注者数据库中,无需涉及Citus元数据表。
协调定位
由于可以根据需要将分片及其副本放在指定节点上,因此我们可以将包含相关表的相关行的分片放在相同的节点上。通过这种方式,它们之间的连接查询可以在避免网络传输的情况下,获得尽可能多的信息,只需在单个Citus节点内执行即可。
比如,有一个业务数据为存储、产品和购买的数据库。如果所有三个表都包含一个store_id列,并且是按store_id列分布的,那么单个store_id的所有查询可以在单个数据节点上高效地运行,无论查询涉及到这些表的任何组合,都可以高效的完成。
并行查询
跨多个节点查询允许同时运行更多查询,并通过向集群中添加新节点来提高处理速度。另外,将单个查询分割成多个片段同样可以增强处理能力,实现了最大的并行性,即,CPU核心的利用率。
查询的结果仍然需要通过协调器节点传递回去,因此,协调节点还承担了合并返回结果集的工作。当最终结果是紧凑的,比如,计数和统计之类的聚合函数时,加速效果最为明显。