03. citusdb 节点和表
节点-Nodes
Citus 是一个 PostgreSQL 扩展,它允许普通数据库服务器(称为节点)以“无共享”架构彼此协调。这些节点形成一个集群,使 PostgreSQL 能够比在单台计算机上容纳更多的数据并使用更多的 CPU 核。这种体系结构还允许数据库通过简单地向集群添加更多节点来扩展。
协调器 Coordinator 和工作器 Workers
每个集群都有一个称为协调器(coordinator)的特殊节点(其他节点称为工作器 workers)。应用程序将查询发送到协调节点,协调节点将查询转发给相关的 workers 并累积结果。
对于每个查询,协调器要么将其路由到单个工作节点,要么根据所需数据是存在于单个节点还是多个节点,将其并行化到多个工作节点。协调器知道如何通过查询其元数据表来实现这一点。这些特定于 Citus 的表跟踪工作节点的 DNS 名称和健康状况,以及跨节点的数据分布。有关更多信息,请参见我们的 Citus 表和视图。
分布式数据
表类型
集群中有三种表类型,每种表都以不同方式存储在节点中,并且用于不同的目的。
Citus 集群中有三种类型的表,每种表用于不同的目的。
类型 1: 分布式表 Distributed Tables
第一种类型(也是最常见的)是分布式表。这些似乎是 SQL 语句的普通表,但是在工作节点之间进行水平分区。
这里的表行存储在 worker 上的 table_1001、table_1002 等表中。组件工作表称为分片(shards)。
Citus 不仅在整个集群中运行 SQL 语句,而且在整个集群中运行 DDL 语句,因此更改分布式表的模式会级联以跨 worker 更新所有表的分片。
若要了解如何创建分布式表,请参阅创建和修改分布式对象(DDL)。
分布列
Citus 使用分片算法将行分配到分片。 基于表列(称为分布列)的值执行分配,此分配具有确定性。 群集管理员在分布表时必须指定此列。 做出正确的选择,这一点对于性能和功能有重要影响。
类型 2: 引用表 Reference Tables
引用表是一种分布式表,其全部内容集中在一个分片上,并在每个工作者上复制。因此,对任何工作者的查询都可以在本地访问引用信息,而不需要从另一个节点请求行的网络开销。引用表没有分布列,因为不需要区分每行的单独分片。
引用表通常很小,用于存储与在任何工作节点上运行的查询相关的数据。例如,订单状态或产品类别等枚举值。
当与引用表交互时,我们自动对事务执行两阶段提交(2PC)。这意味着 Citus 确保数据始终处于一致的状态,无论您是在编写、修改还是删除数据。
类型 3: 本地表 Local Tables
在使用 Citus 时,连接并交互的协调节点是安装了 Citus 扩展的常规 PostgreSQL 数据库。因此,您可以创建普通表并选择不对其进行分片。这对于不参与联接查询的小型管理表非常有用。一个例子是用于应用程序登录和身份验证的用户表。
创建标准 PostgreSQL 表很容易,因为它是默认的。这是运行 CREATE TABLE 时得到的结果。在几乎每个 Citus 部署中,我们都会看到标准 PostgreSQL 表与分布式表和引用表共存。实际上,如前所述,Citus 本身使用本地表来保存集群元数据。
分片-Shards
前一节将分片描述为在工作节点内的一个较小的表中包含分布式表的一个行子集。本节将更详细地介绍技术细节。
协调器上的 pg_dist_shard 元数据表包含系统中每个分布式表的每个分片的一行。该行与散列空间(shardminvalue,shardmaxvalue)中的一系列整数匹配:
1 | SELECT * from pg_dist_shard; |
如果协调节点希望确定哪个分片包含一行 github_events,它将散列行中分发列的值,并检查哪个分片的范围包含散列值。(定义范围是为了使散列函数的图像是它们不相交的联合。)
分片放置
假设分片 102027 与所讨论的行相关联。这意味着该行应该被读取或写入到一个 worker 中名为 github_events_102027 的表中。哪个 workers?这完全由元数据表决定,而将 Shard 映射到 worker 称为 Shard 位置。
加入一些元数据表给了我们答案。这些是协调程序用于路由查询的查找类型。它将查询重写为引用特定表(如 github_events_102027)的片段,并在适当的 worker 上运行这些片段。
1 | SELECT |
在我们的 github_events 示例中有四个分片。在表在集群中分发时,每个表的分片数是可配置的。分片计数的最佳选择取决于您的用例,请参阅分片计数。
最后请注意,Citus 允许使用 PostgreSQL 流复制复制分片,以防止数据丢失。将每个节点的整个数据库备份到跟随者数据库的流复制。这是透明的,不需要 Citus 元数据表的参与。
同一地点
因为可以根据需要将分片放置在节点上,所以将包含相关表的相关行的分片放置在同一个节点上是有意义的。这样,它们之间的连接查询可以避免通过网络发送同样多的信息,并且可以在单个 Citus 节点内执行。
一个例子是包含商店、产品和采购的数据库。如果所有三个表都包含一个 store _ id 列,并通过这个列进行分布,那么限制在单个存储上的所有查询都可以在单个工作节点上高效运行。即使查询涉及这些表的任何组合,也是如此。
有关此概念的完整解释和示例,请参见表共定位。
查询执行
在执行多分片查询时,Citus 必须平衡并行性带来的收益和数据库连接的开销(网络延迟和工作节点资源使用)。为了在数据库工作负载中配置 Citus 的查询执行以获得最佳结果,这有助于理解 Citus 如何管理和保存协调节点和工作节点之间的数据库连接。
Citus 将每个传入的多分片查询会话转换为称为任务的每个分片查询。它对任务进行排队,并在能够获得到相关工作节点的连接后运行它们。
协调器节点为每个会话都有一个连接池。每个查询(如图中的 SELECT * FROM foo)最多只能为每个工作者的任务同时打开 citus.max_adaptuer_executive_pool_size(integer)连接。该设置可在会话级别进行配置,用于优先级管理。
在同一个连接上顺序执行短任务比并行为它们建立新连接更快。另一方面,长时间运行的任务受益于更直接的并行性。
为了平衡短任务和长任务的需求,Citus 使用 citus.executive_slow_start_time (整数)。该设置指定多分片查询中任务的连接尝试之间的延迟。当查询首次对任务进行排队时,任务只能获取一个连接。在存在挂起连接的每个间隔结束时,Citus 增加将打开的同时连接的数量。通过将 GUC 设置为 0,可以完全禁用缓慢启动行为。
当任务使用连接完成时,会话池将保持连接处于打开状态,以便以后使用。缓存连接可以避免在协调器和辅助器之间重新建立连接的开销。但是,为了限制 worker 中的空闲连接资源使用,每个池一次打开的空闲连接数不会超过 citus.max_cached_conns_per_worker (整数)。
最后,设置 citus.max_share_pool_size (整数)作为一个自动防故障装置,它限制了所有任务之间每个工作人员的总连接数。
有关调优这些参数以匹配工作负载的建议,请参见连接管理。