扩展设计

来自 PostgreSQL Wiki
跳转到导航跳转到搜索

这是讨论 PostgreSQL 扩展设计的备忘录。


引言

基本原则

  • 最大化 PostgreSQL 的好处:尽可能多地利用现有的特性和生态系统,例如强大的 SQL、基于严格一致性的 ACID、各种索引类型、可扩展性和客户端驱动程序。这将使内置的横向扩展模式有别于其他横向扩展 DBMS。
  • 重视应用程序透明性:尽量不对应用程序的逻辑数据模型、应用程序逻辑和查询进行修改,或者仅进行少量修改。例如,最好允许用户使用 ALTER TABLE 或用户自定义函数指定表分布方式,而不是强制在 CREATE TABLE 中使用特殊关键字。
  • 学习:由于现在已经有多种横向扩展 DBMS,最好向它们学习,吸收优点,追求最佳效果。不要拘泥于旧的机制。当然,最好是发明 PostgreSQL 的特有优点。

<参考文献>

目标工作负载

<问题>

  • Q1:我们希望处理哪些工作负载?
  • Q2:我们希望首先关注哪项工作负载?
  • OLTP(主要是多租户 OLTP 自定义应用程序)
  • 分析(具有 MPP 并行性)
  • 混合(HTAP)

[Oracle]

  • Oracle 分片是 OLTP 应用程序的可伸缩性、可用性和地理分布功能,可在离散的 Oracle 数据库池中分发并复制数据。

[MySQL 集群]

  • MySQL 集群在多地理区域中的不同集群之间具有内置的复制功能。具有数据局部感知的无共享架构使其成为在商用硬件和全球分布式云基础设施上运行的完美选择。
  • DSS 应用程序(数据市集、分析):受限(超过 3TB 大小的 OLTP 数据集的联接操作)
  • 打包应用程序:受限(应主要为主键访问)

[CockroachDB]

  • CockroachDB 在 2ms 或更短的时间内返回单行读取,在 4ms 或更短的时间内进行单行写入,并支持多种 SQL 和运算调优实践来优化查询性能。但是,CockroachDB 尚不适合进行繁重的分析/OLAP。

[YugabyteDB]

  • YugabyteDB 是一个高性能的云原生分布式 SQL 数据库,旨在支持所有 PostgreSQL 功能。它最适合需要绝对数据正确性且需要以下一项或多项功能的云原生 OLTP(即实时、业务关键型)应用程序:可伸缩性、对故障的高容忍度、全球分布的部署。YugabyteDB 不适用于需要完整特设分析的传统在线分析处理 (OLAP) 用例。

[Greenplum]

  • Greenplum 数据库是一个大规模并行处理 (MPP) 数据库服务器,其架构专为管理大规模分析数据仓库和商业智能工作负载而设计。


分布式架构

<问题>

  • 问题 1:我们要采用哪些横向扩展架构?如果我们希望有多个架构,那么优先级是什么?

根据 2018 年 PGCon 开发者非正式会议和其他先前的讨论,我们希望首先采用无共享架构。这并不意味着排除整合共享磁盘架构的可能性。Oracle Database 和 IBM Db2 提供无共享和共享磁盘架构作为独立的功能。PostgreSQL 同时拥有两者也不应该有什么问题。

  • 无共享
  • 共享磁盘
  • 基于计算和存储分离的新架构:例如,Amazon Aurora 在数据库服务器后有一个智能的多租户横向扩展存储服务,并且将重做处理推送到存储服务中,并由数据库服务器消除数据库页面写入,包括检查点。

<参考文献>

要学习的其他 DBMS

设计考虑中提到了以下 DBMS。这个 Wiki 页面上引用了其大部分文档。

<OLTP DBMS>

<分析 DBMS>

<OLTP 和分析 DBMS>

当我们想要探索其他想法的时候,可能会参考(但现在还没有)以下 DBMS

  • MemSQL
  • VoltDB
  • Vertica
  • Snowflake


服务器角色

  • 最小化单一争用点。
  • 消除单一故障点。
  • 最小化服务器角色的数目以简化管理。
  • 某些节点需要管理节点信息、系统目录和序列。

<问题>

  • Q1:我们是否应该有一个中央管理节点?
  • Q2:我们是否允许客户端连接到任何节点并运行任何 SQL 语句?
  • Q3:基于分区键、服务器负载和节点属性(主/备,诸如区域/AZ/机架之类的邻近性)等信息,我们是否有一个组件来进行连接路由?

[Oracle]

  • 分片 - 独立的实体 Oracle 数据库,它们托管着分片数据库的一个子集
  • 分片目录 - 一个支持自动化分片部署,对分片数据库进行集中管理,以及执行多分片查询的 Oracle 数据库
    • 通过连接到分片目录,执行分片数据库中的所有 DDL。
    • 分片目录还在分片数据库中包含所有已复制表的主副本。分片目录使用物化视图在所有分片中自动复制对已复制表的更改。
    • 分片目录数据库还充当查询协调器,用于处理多分片查询和未指定分区键的查询。
  • 分片导程 - 网络侦听器,基于分区键实现高性能连接路由
  • 连接池 - 在运行时,充当分片导程,按照合并连接路由数据库请求

[MySQL 集群]

  • 管理节点 - 为整个集群提供管理服务,包括其他节点的启动、关机、备份以及配置数据。
  • 数据节点 - 存储和复制数据。
  • SQL 节点 - 是一个 MySQL Server (mysqld) 实例,它接受客户端连接和 SQL 语句。

[Spanner]

  • Spanner 部署称为 universe。
  • Spanner 被组织为一组区域,每个区域基本上类似于 Bigtable 服务器部署。
    • 区域是管理部署的单位。
    • 该区域集也是可以跨其复制数据的区域集。
    • 随着新数据中心投入使用和旧数据中心关闭,可以分别向正在运行的系统中添加区域或从中删除区域。
    • 区域也是物理隔离的单位:例如,在同一数据中心内,可以将不同的应用程序数据分区到不同服务器集内,因此在一个数据中心内可能存在一个或多个区域。
  • 每个区域有一个区域主服务器和一百到几千个 SpanServer。
    • 区域主服务器将数据分配给 SpanServer。
    • SpanServer 向客户端提供数据。在底部,每个 SpanServer 负责一个数据结构(称为片)的 100 到 1000 个实例。
    • 每个区域的位置代理都由客户端用来查找分配用于提供自己数据的 SpanServer。
  • 宇宙主服务器和放置驱动器目前是单例。
    • 宇宙主服务器基本是一个控制台,用于显示所有区域的状态信息,以便进行交互式调试。
    • 放置驱动器处理以分钟为单位的数据跨区域自动移动。放置驱动器会定期与 SpanServer 通信,以查找需要移动的数据,以便满足更新的复制约束或平衡负载。

[CockroachDB]

  • 所有节点的行为都是对称的,因此开发人员可以向任何节点发送请求(这意味着 CockroachDB 与负载均衡器配合效果良好)。
  • 无论哪个节点接收请求,它都会充当“网关节点”,因为其他层会处理请求。
  • 如果节点收到无法直接提供服务的读取或写入请求,它只需找到可处理该请求的节点,并与其通信。

[YugabyteDB]

  • YugabyteDB 集群包含两个分布式服务 - YB-TServer 服务和 YB-Master 服务。由于 YB-Master 服务扮演集群元数据管理器的角色,因此它应首先启动,然后是 YB-TServer 服务。
  • YB-Master
    • 协调全宇宙范围的管理操作
      • 处理 DDL 语句,如 CREATE TABLE、ALTER TABLE、DROP TABLE 请求
      • 创建表的备份
      • YB-Master 执行这些操作,并且可以保证该操作将传播到所有片,而无论托管这些片的 YB-TServer 的状态如何。这是至关重要的,因为当其中一项宇宙范围的操作正在进行过程中,YB-TServer 出现故障不会影响该操作的结果,因为它无法将其应用于某些片。
    • 存储系统元数据
      • 每个 YB-Master 都存储系统元数据,包括关于名称空间、表、角色、特权以及片分配给 YB-TServer 的信息。
      • 这些系统记录还使用 Raft 进行跨 YB-Master 复制以实现冗余。
    • 是 YB-TServer 平板分配的权威来源
      • YB-Master 存储了所有平板及其当前托管的 YB-TServer。平板到托管 YB-TServer 的映射由客户端(例如 YugabyteDB 查询层)查询。
      • 使用 YugabyteDB 智能客户端的应用程序能够高效地检索数据。智能客户端向 YB-Master 查询平板到 YB-TServer 的映射并将其缓存。通过这样做,智能客户端可以直接与正确的 YB-TServer 通信以处理各种查询,而无需产生额外的网络跳数。
    • 协调后台操作
      • 数据放置和负载平衡:YB-Master leader 对 YB-TServer 中的平板进行初始放置(在 CREATE TABLE 时间),以确保遵循任何用户定义的数据放置约束和实现均匀负载。此外,在 Universe 的生命周期中,随着节点的添加、故障或停用,它会继续自动平衡负载和执行数据放置约束。
      • leader 平衡:除了确保由每个 YB-TServer 服务的平板数量在 Universe 中得到平衡之外,YB-Master 还确保每个节点在合格节点之间具有对称数量的平板对等 leader。
      • 在 YB-TServer 故障扩展后重新复制数据:YB-Master 从所有 YB-TServer 接收心跳,并跟踪其正常运行时间。它检测到任何 YB-TServer 是否已故障,并跟踪 YB-TServer 保持故障状态的时间间隔。如果故障的时间持续超过阈值,它会找到新的 YB-TServer,将故障 YB-TServer 的平板数据重新复制到该 YB-TServer。重新复制由 YB-Master leader 以受控方式发起,以不影响 Universe 的前台操作。
  • YB-TServer
    • 从应用程序的角度来看,这是一个无状态层,客户端可以在适当的端口连接到任何(一个或多个)YB-TServer,以针对 YugabyteDB 集群执行操作。
    • 处理 DML 语句。
    • 执行最终用户请求的实际 I/O。

[Azure Synapse]

  • 计算与存储分开,这使你可以独立于系统中的数据来扩展计算。
  • 控制节点 - 应用程序连接到控制节点并向其发出 T-SQL 命令,该控制节点是 Synapse SQL 的单一入口点。控制节点运行 MPP 引擎,该引擎针对并行处理优化查询,然后将操作传递给计算节点以并行完成其工作。
  • 计算节点 - 计算节点将所有用户数据存储在 Azure 存储中并运行并行查询。计算节点的数量为 1 到 60,由 Synapse SQL 的服务级别确定。

[Greenplum]

  • 主节点 - 主节点是 Greenplum Database 系统的入口点。它是数据库服务器进程,接受客户端连接,并对系统用户发出的 SQL 命令进行处理。
    • 用户通过使用与 PostgreSQL 兼容的客户端程序(例如 psql 或 ODBC)通过主节点连接至 Greenplum Database。
    • 主节点协调系统中其他数据库实例(称为段)的工作负载,这些段负责数据处理和存储。
    • 主节点维护系统目录(一组包含 Greenplum Database 系统自身元数据的系统表),但是主节点不包含任何用户数据。数据仅驻留在段中。
  • 段 - 段是数据存储和大部分查询处理发生的地方。用户定义的表及其索引分布在可用段中;每个段都包含一个数据的部分。
    • 段实例是服务于段的数据库服务器进程。
    • 段无法接受客户端连接。
    • 段通过互连互相通信,并与主节点通信。

[Citus]

  • 每个集群都有一个称为协调器的特殊节点,其他节点称为工作程序或数据节点。
    • 应用程序将查询发送至协调器节点,由协调器节点将查询中继至相关工作程序并积累结果。
    • 应用程序无法直接连接至工作程序。
    • 协调器是群集的权威元数据源,而数据节点则将实际数据存储在分片中。
  • 协调器
    • 对于分布式表中的每个查询,协调器将其路由至一个工作程序节点,或根据所需数据是驻留在一个节点还是多个节点将其并行到几个节点上。协调器通过查阅元数据表来决定做什么。这些表跟踪工作程序节点的 DNS 名称和运行状况,以及节点之间的分布数据。
    • Citus 协调器仅存储有关表分片元数据,不存储任何数据。这意味着所有计算都下推到工作程序,而协调器仅对工作程序的结果进行最终聚合。因此,协调器不太可能成为读取性能的瓶颈。此外,可以通过转换到功能更强大的机器来轻松提升协调器。
    • 但是,在协调器成为性能瓶颈的某些写入繁重使用案例中,用户可以添加另一个协调器。由于元数据表很小(通常大小为几 MB),因此可以将元数据复制到另一个节点并定期同步。完成此操作后,用户可以将查询发送至任何协调器并扩展性能。
  • Citus MX
    • 是 Citus 的新版本,它增加了在 Citus 集群中从任何节点使用哈希分布表的功能,这允许您通过在所有节点之间打开许多连接来扩展查询吞吐量。
    • 这对于以可横向扩展的方式非常高速率地执行小读取和写入特别有用。
    • 分布式表只能创建、更改或通过协调器删除,但可从任何节点查询。
    • 对表进行更改时(如添加列),分布式表的元数据会使用 PostgreSQL 内置的 2PC 机制和分布式锁传播到工作程序。
    • 您可以通过以下两种方式之一访问数据库
      • 通过协调器,它允许您创建或更改分布式表。
      • 通过数据 URL,它将路由您至可对其上分布式表执行常规查询的一个数据节点。
    • 在协调器上支持的操作有:创建/删除分布式表、分片平衡器、DDL、DML、SELECT、COPY。
    • 在数据 URL 上支持的操作有:DML、SELECT、COPY。
    • 如果使用 psql 连接至数据 URL 并运行 \d,则将看到所有分布式表。
    • 对分布式表执行查询时,将基于筛选条件确定正确的分片,并将查询转发到存储分片的节点。
    • 如果查询跨越所有分片,则将在所有节点上将其并行处理。
    • 分布式表在所有节点上都是相同的,因此对分布式表进行查询时使用数据 URL 将路由到哪个节点并不重要。

[Postgres-XL]

  • 由三个主要组件组成
    1. GTM(全局事务管理器)
      • 提供一致的事务管理和元组可见性控制。
    2. 协调器
      • 是应用程序与数据库之间的接口。它像传统 PostgreSQL 后端进程一样运行。
      • 不存储任何实际数据。
      • 接收 SQL 语句,根据需要获取全局事务 ID 和全局快照,确定涉及哪些数据节点,并要求它们执行语句(的一部分)。向数据节点发出语句时,它与 GXID 和全局快照相关联,以便多版本并发控制 (MVCC) 属性扩展到整个集群。
    3. 数据节点
      • 实际存储用户数据。表可以分布在数据节点之间,也可以复制到所有数据节点。
      • 没有整个数据库的全局视图,它只负责本地存储的数据。

集群成员资格

<问题>

  • Q1:我们在哪里管理集群节点的成员资格?
    • 文本文件
    • 二进制文件
    • 系统目录
    • 外部存储,如 etcd 和 ZooKeeper

系统目录管理和数据定义

<问题>

  • Q1:我们在何处存储系统目录,在单个中心节点还是所有节点上?系统目录中包含每个数据库对象和全局对象。
  • Q2:如果单个中心节点存储系统目录,其他节点如何高效地访问它?
    • 选项 1:始终从中心节点提取访问数据并在一个事务中使用它。
    • 选项 2:从中心节点获取访问过的数据并将其缓存在每个节点上。
  • 问题 3:如果所有节点都存储系统目录,它们将如何同步目录数据?如果我们基于 SQL 语句复制目录,相同模式对象的 Oid 值在每个节点上将不同。这是否会造成不便?
    • 选项 1:在所有节点上执行 DDL 语句,通过 2PC 同步数据。如果任何节点关闭,DDL 执行将失败。
    • 选项 2:应用程序只能在一个中心节点上运行 DDL。中心节点记录 DDL 以跟踪每个节点已执行的 DDL,并将其推送到其他节点。

[Oracle]

  • 要在分片数据库中创建模式,必须在分片目录数据库上发出 DDL 命令,它将在分片上执行前验证 DDL 并将其执行在本地。因此,分片目录数据库包含所有存在于分片数据库中的对象的本地副本,并作为分片数据库模式的主副本。
  • 如果成功验证和执行 DDL 目录,DDL 将自动传播到所有分片,并按在分片目录上发出的顺序进行应用。
  • 如果在 DDL 传播期间分片关闭或不可访问,目录将跟踪无法应用到分片上的 DDL,然后在分片备份时对其进行应用。
  • 向分片数据库添加新分片时,已在 SDB 中执行的所有 DDL 都将按相同顺序应用到分片,然后再允许客户端对其进行访问。
  • 使用 SQL*Plus 连接到分片目录时,可以创建两种类型的对象:SDB 对象和本地对象。本地对象是传统对象,仅存在于分片目录中。可将本地对象用于管理目的,也可将其用于源自目录数据库的多分片查询,例如,生成并存储报告。
  • 在 SQL*Plus 会话中创建的对象类型 (SDB 或本地) 取决于会话中是否启用了 SHARD DDL 模式。
    • 要创建本地对象,SDB 用户必须首先运行 alter session disable shard ddl。在禁用 SHARD DDL 时创建的所有对象都是本地对象。
    • 在会话中启用 SHARD DDL 时创建的所有对象都是 SDB 对象。要启用会话中的 SHARD DDL,SDB 用户必须运行 alter session enable shard ddl。

[MySQL 集群]

  • 当任何数据节点重新启动时,将拒绝模式操作 (DDL 语句)。
  • 在执行联机升级或降级时也不支持模式操作。

[YugabyteDB]

  • 每个 YB-Master 都存储系统元数据,包括关于名称空间、表、角色、特权以及片分配给 YB-TServer 的信息。

[Azure Synapse]

  • 不支持在用户定义的事务中使用 DDL(例如,CREATE TABLE)

[Greenplum]

  • 主节点维护系统目录(包含有关 Greenplum 数据库系统本身的元数据的系统表集)。

[Citus]

  • 协调器是群集中元数据的权威来源。
  • 要在新数据库上运行 Citus,需要在协调器和工作器上创建数据库,在该数据库中创建 Citus 扩展,并在协调器数据库中注册工作器。
  • DDL 命令只能从协调器节点运行。
  • Citus 使用两阶段提交协议从协调器节点将架构更改传播到工作器。
  • 某些 DDL 语句需要手动传播,还明确禁止某些其他语句(例如会修改分布列的语句)。
  • 在协调器节点上运行后,某些命令不会传播到工作器
    • CREATE ROLE/USER(Citus Enterprise 中将传播)
    • CREATE DATABASE
    • ALTER SET SCHEMA
    • ALTER TABLE ALL IN TABLESPACE
    • CREATE FUNCTION(使用 create_distributed_function)
    • CREATE TABLE
  • 对于上述其他类型的对象,在所有节点上明确创建它们。Citus 提供了一个在所有工作器上执行查询的函数
    • SELECT run_command_on_workers($cmd$ CREATE ROLE ...; $cmd$);
  • 自动传播的优点是,Citus 将自动在任何新添加的工作器节点上创建一份副本。
    • citus.pg_dist_object 表包含对象(如类型和函数)的列表,这些对象已在协调器节点上创建并传播到工作器节点。
    • 当管理员将新工作器节点添加到群集后,Citus 会自动在新建节点上创建分布式的对象副本(按正确的顺序满足对象依赖性)。

[Postgres-XL]

  • 每个协调器和数据节点都存储系统编录。
  • 将 DDL 执行传播到其他节点,但节点管理语句例外:CREATE/ALTER/DROP NODE 和 CREATE/DROP NODE GROUP。
  • 同一个架构对象在每个节点上的 OID 不同。

节点间通信

<问题>

  • 问 1:我们是否支持 IPv6?
  • 问 2:我们如何实施连接池来减少连接数和建立连接的开销?
  • 问 3:我们如何将会话设置传播到远程节点?
  • 问 4:我们应该关心哪些方面才能实现高性能通信,例如,套接字缓冲区、巨型帧、消息格式(文本/二进制)等。

[MySQL 集群]

  • 用于 SQL 节点(MySQL 服务器)之间的连接支持 IPv6,但所有其他类型 NDB 群集节点之间的连接必须使用 IPv4。实际上,这意味着您可以将 IPv6 用于 NDB 群集之间的复制,但同一 NDB 群集中的节点之间的连接必须使用 IPv4。

[Greenplum]

  • 默认情况下,Greenplum 数据库互连使用带有流量控制的 UDP 通过网络发送消息,以便进行互连通信。Greenplum 软件执行了其他数据包验证和检查,而 UDP 没有执行这些操作,因此可靠性相当于 TCP,性能和可扩展性超过 TCP。
  • 连接池
    • 您可以配置 Greenplum 系统使用代理进行互连通信,以减少在查询处理期间使用的连接和端口。
    • 通常,在运行查询时,Greenplum 主节点上的 QD(查询分发器)会创建到各个片段上的一个或多个 QE(查询执行器)进程的连接,而 QE 可以创建到其他 QE 的连接。默认情况下,主节点上的 QD 与片段实例上的 QE 之间的连接以及不同片段实例上的 QE 之间的连接需要一个单独的网络端口。你可以将 Greenplum 系统配置为在 Greenplum 在 QD 和 QE 之间以及不同片段实例上的 QE 之间进行通信时使用代理。
    • 互连代理只需要一个网络连接即可用于两个片段实例之间的 Greenplum 内部通信,因此它消耗的连接和端口比 TCP 模式少,在高延迟网络中的性能比 UDPIFC 模式更好。
    • 有关详细信息,请参见 为 Greenplum 互连配置代理

[Citus]

  • 数据传输格式
    • 默认情况下,Citus 会以文本格式传输中间查询数据。这通常会更好,因为文本文件通常比二进制表示形式文件小。因此,这会导致在写入和传输中间数据时降低网络和磁盘 I/O。
    • 但是,对于某些数据类型(如 hll 或 hstore 数组),序列化和反序列化数据的成本很高。在这种情况下,使用二进制格式传输中间数据可以由于降低 CPU 使用量而提高查询性能。
    • 有两个配置参数与中间数据在工作程序之间或在工作程序与协调器之间传输的格式有关。
      • citus.binary_master_copy_format:使用二进制格式从工作程序向协调器传输中间查询结果
      • citus.binary_worker_copy_format:对于需要在工作程序之间动态混洗中间数据的查询很有用

[Postgres-XL]

  • 连接池
    • Postgres-XL 在协调器与数据节点之间配备了连接池程序。
    • 当协调器后端需要与数据节点进行连接时,连接池程序会从池中寻找合适的连接。如果有一个可用的连接,连接池程序会将其分配给协调器后端。
    • 当不再需要连接时,协调器后端会将连接返还给连接池程序。连接池程序不会断开连接。它会保留连接以供以后重用,从而保持数据节点后端运行。

FDW 或非 FDW

<问题>

  • 问题 1:我们是否可以将 FDW 用作横向扩展的基础架构?
  • 问题 2:如果我们采用 FDW,有什么是无法实现的吗?如果是,是否值得用枷锁开发内置横向扩展功能?

Citus Data 不采用 FDW 的原因是 Citus 有架构限制。

  • 对比。 PostgreSQL、pg_shard、外部数据封装程序以及我们的技术经验
  • "一项重要的学习是,即使得到计划器的充分配合,外部数据包装器 API 也不会推动对 count(distinct) 计算向下传递。计划器和执行器 API 都需要从根本上改变来支持对这一计算进行并行处理。其它许多查询也面临着同样的挑战。"
  • "这个限制是我们决定从 pg_shard 中还原使用 FDW 的四个原因之一。即使 FWD API 进行了重大改进,我们仍然无法扩展出许多复杂的 SELECT 查询。"
  • FDW 的四个技术问题
    1. 即使对 FDW API 进行重大更改,也无法并行处理复杂的 SELECT 查询
    2. 更新和删除操作首先通过从表扫描函数中获取记录,然后检查获取的记录来执行。如果用户想要更新单行,那么会先提取行,再更新相关记录。这个限制不像 SELECT 的限制那么基本,但是仍然存在。"
    3. 我们提供高可用性 (HA) 特性的选项变得相当有限。FDW API 被设计为从一个远程数据源读取数据。如果我们想要通过流复制之外的任何方式复制数据,或者在查询中途故障转移到另一台机器,我们最终会编写逻辑来在应该读取下一条记录的函数中间打开连接并启动新的扫描。"
    4. 当用户创建分布式表时,传播每个分区的数据定义语言 (DDL) 命令。这里的问题是常规 PostgreSQL 表和外部 PostgreSQL 表不支持相同的功能。例如,你目前无法在一个外部表上创建索引。因此,当我们使用一个外部表来模拟分布式常规表时,你如何允许和传播创建索引的命令?我们最终推断并隐藏创建了两张表,并且为此在它们之间进行交换。"

<FDW 的当前限制和潜在障碍>

  • 某些分布式查询优化是不可能的。"
    • 在 FDW 世界中,一个本地节点单方面地访问远端节点。远端节点不能互相访问。"
    • 某些分布式查询需要远端节点之间的直接通信。Greenplum、Citus 和 Postgres-XL 在某些联结中会这样做。"
  • 仅支持表,不支持其他对象。"
  • 没有集中式用户和权限管理。"
  • 没有集中式序列。"
  • 如果父表上有唯一索引,则当前不允许将外部表创建为父表的各个部分。* 缺乏对带有 ON CONFLICT DO UPDATE 子句的 INSERT 语句的支持。"
  • 带有 ON CONFLICT 子句的 INSERT 不支持指定冲突目标,因为远端表上的唯一约束或排除约束无法被本地识别。这也意味着不支持 ON CONFLICT DO UPDATE,因为那里需要强制该规范。"
  • postgres_fdw 目前不支持带有 ON CONFLICT DO UPDATE 子句的 INSERT 语句。但是,如果省略唯一索引推断规范,则支持 ON CONFLICT DO NOTHING 子句。
  • Oid 和 ctid 值在每个节点上不同。
    • psqlODBC 的游标更新/删除使用 Oid 或主键。如果没有这些值,它将使用 ctid。
  • 虽然可以将行从本地分区移动到外键表分区(如果外键数据包装器支持元组路由),但不能将行从外键表分区移动到另一个分区。
  • 在多个节点之间可以滚动游标吗?
  • 会话变量不会传播到远程节点。
  • libpq 额外负担:在文本格式和二进制格式之间转换数据。
  • 只有 IMMUTABLE 内置数据类型、操作符和函数才会在远程服务器上执行。
  • 在 READ COMMITTED 模式下重新检查连接条件
    • 另一个需要考虑的是,在 READ COMMITTED 隔离模式下,PostgreSQL 可能需要针对某个目标元组的更新版本重新检查限制和连接条件。重新检查连接条件需要重新获取以前连接到目标元组的非目标行的副本。
    • 在使用标准 PostgreSQL 表时,可以通过以下方法来实现:将非目标表的 TID 包含到通过连接预测的列列表中,然后在需要时重新获取非目标行。此方法使连接数据集保持紧凑,但它需要低成本的重新获取功能,以及能够唯一标识要重新获取的行版本的 TID。
    • 因此,与外键表搭配使用时默认的方法是将从外键表获取的整行副本包含到通过连接预测的列列表中。这不会对 FDW 提出特殊要求,但可能会导致合并和哈希连接的性能降低。如果 FDW 能够满足重新获取要求,则它可以选择第一种方法来实现。
  • postgres_fdw 限制
    • 即使本地事务使用 READ COMMITTED,远程服务器上的事务也会使用 REPEATABLE READ。
    • 不支持带有 ON CONFLICT DO UPDATE 子句的 INSERT 语句。但是,如果省略唯一索引推断规范,则支持 ON CONFLICT DO NOTHING 子句。
    • postgres_fdw 支持由在分区表上执行的 UPDATE 语句调用的行移动,但目前不支持将移动行要插入到的远程分区也是稍后将被更新的 UPDATE 目标分区的这种情况。
    • 用户无法设置 fallback_application_name(始终设置为 postgres_fdw)
    • 为了降低错误执行查询的风险,只有在 WHERE 子句仅使用内置数据类型、操作符和函数,或属于列在外键服务器的扩展选项中的扩展的情况下,才会将 WHERE 子句发送到远程服务器。此类子句中的操作符和函数也必须是 IMMUTABLE。
    • 在由 postgres_fdw 打开的远程会话中,search_path 参数仅设置为 pg_catalog,以便只有内置对象在没有模式限定的情况下可见。

[MySQL 集群]

  • NDB 集群需要数据节点和 API 节点(包括 SQL 节点)之间的通信,以及数据节点和其他数据节点之间的通信才能执行查询和更新。

[Greenplum]

  • 要执行联接,必须在同一细分中找到匹配的行。如果数据未分布在同一联接列上,则从一个表中需要的行将动态重新分发到其他细分中。在某些情况下,它执行广播动作,其中每一个细分都向所有其他细分发送其个别行,而不是执行重新分配动作,其中每一个细分重新哈希数据并根据哈希键将行发送到适当的细分中。
  • 除了表扫描、联接等常见的数据库操作之外,Greenplum 数据库还有一种其他类型的操作称为动作。动作操作涉及在查询处理期间在细分之间移动元组。
  • 例如,考虑涉及两个表之间的联接的以下简单查询

SELECT customer, amount FROM sales JOIN customer USING (cust_id) WHERE dateCol = '04-30-2016'; 

  • 此示例的查询计划包含一个重新分配动作,它在细分之间移动元组以完成联接。重新分配动作是必需的,因为 customer 表根据 cust_id 在细分之间进行分布,但 sales 表根据 sale_id 在细分之间进行分布。
  • 为了执行联接,必须按 cust_id 重新分发 sales 元组。计划在重新分配动作的任一侧进行切分,创建切片 1 和切片 2。

[Citus]

  • 有时需要 work 彼此连接,例如在重新分区联接期间。
  • 现在,INSERT..SELECT 命令可以在 work 之间切换数据,而不是将数据拉取到协调器。这种改变意味着 INSERT..SELECT 的速度可以提升 5 倍。能够在 Citus 中通过重新分区执行 INSERT..SELECT,意味着用户不再受限于单一分配列才能扩展数据处理管道,这能够在 Citus 数据库中实现更高级的实时分析场景和数据处理管道。
  • 任务跟踪程序执行程序旨在高效处理复杂查询,这些查询需要对 work 之间的中间数据进行重新分区和切换。

[Postgres-XL]

  • shared_queues(整数)
    • 仅适用于数据节点的参数
    • 对于查询中出现的一些联接,可能需要将来自一个数据节点的数据与来自另一个数据节点的数据联接。Postgres-XL 使用共享队列进行此目的。在执行期间,每一个数据节点都知道它需要生成或消费元组,或两者兼而有之。

可扩展性和性能

目标

  • 仅访问集群中一个节点的事务性能与访问非集群化节点的事务性能几乎相同。
  • 事务每秒的线性可扩展性,随着添加新的分片来支持更大的工作负载和/或数据量,响应时间保持恒定。
  • 为实现读取的可伸缩性和低延迟以及可用性和安全性,单个逻辑数据库可以进行地理分布
    • 允许将特定数据存储在靠近使用者的位置

<问题>

  • 问题一:我们的目标是处理多少数据?
  • 问题二:一个集群中可容纳的最大节点数是多少?

[Oracle]

  • 最多 1,000 个数据库节点

[MySQL 集群]

  • 存储限制:128 TB
  • 节点数量
    • 最大为 255 个。此数字包括所有 SQL 节点(MySQL 服务器)、API 节点(除 MySQL 服务器之外访问该集群的应用程序)、数据节点和管理服务器。
    • 数据节点的最大数量为 145 个。
    • 节点组的最大数量为 48 个。
  • 数据库对象数量
    • 单个 NDB 集群中所有 NDB 数据库对象(包括数据库、表和索引)的最大数量限制为 20320 个。

[Spanner]

  • Spanner 的设计能够跨数百个数据中心和数万亿行数据库数据扩展到数百万台机器。

[CockroachDB]

  • 除了光速,CockroachDB 在扩展性、吞吐量、延迟或并发性方面没有理论上的限制。实践中,它可在 256 个节点上以接近线性的性能运行 TPC-C。
  • 在单个可用性区域内,1 ms 内返回单行读取,并在 2 ms 内处理单行写入。

[Greenplum]

  • 数据大小:数百 TB

[Citus]

  • 最大客户的数据大小:堆:70 节点 Citus 数据库集群上的 1.4PB 数据

数据分片和放置

  • 同时提供自动和手动数据放置方法。
    • 自动:PostgreSQL 根据节点数量、数据大小和节点负载确定将哪些记录放置在哪些节点上。
    • 手动:用户根据用户邻近度和安全性要求(例如 GDPR),控制将哪些记录放置在哪些节点上。

<问题>

  • 问题一:分片的单位是什么?它与传统的分区有什么关系?
    • 选项 1:用户定义的分区和子分区
    • 选项 2:范围、切分或块,由 PostgreSQL 自动划分
  • 问题二:我们采用什么分片方法?
    • 选项 1:按一致哈希分配
    • 选项 2:按范围分配
    • 选项 3:按列表分配:地理分布
    • 选项 4:复合分配:组合列表/范围和哈希,例如按国家/地区按列表分区以将数据分配到附近的区域,然后按哈希对每个区域中的多个节点进行子分区
    • 选项 5:按复制分配:所有节点都保存一张表的相同副本,例如产品目录等主数据
  • 问题三:分片键的要求是什么?
  • 问题四:我们将在系统目录中存储什么分片元数据?
  • 问题五:用户如何创建一个分布式表?

[Oracle]

  • 支持分片、重复和本地表。
  • 系统管理的分片
    • 不要求您将数据映射到分片。使用按一致哈希分片的数据,自动将数据分布到分片中。分区算法将数据均匀且随机地分布到分片中。
    • 系统管理分片中使用的分布旨在消除热点,并跨分片提供统一的性能。在向分片数据库中添加或从中删除分片时,Oracle Sharding 将自动维护块的平衡分布。
  • 用户定义分片
    • 允许您明确指定数据到各个分片的映射。在由于性能、法规或其他原因,需要将某些数据存储在特定分片上,并且管理员需要完全控制在分片之间移动数据时,这种情况将被使用。
    • 用户定义分片的另一个优点是,在分片计划或非计划停机的情况下,用户确切知道哪些数据不可用。
    • 用户定义分片的缺点是数据库管理员需要监控和维护跨分片的数据和工作负载的平衡分布。
    • 使用用户定义分片,分片表可以通过范围或列表进行分区。分片表的 CREATE TABLE 语法与常规表的语法没有很大不同,除了每个分区都应存储在单独的表空间中的要求外。

CREATE SHARDED TABLE accounts ( id NUMBER , account_number NUMBER , customer_id NUMBER , branch_id NUMBER , state VARCHAR(2) NOT NULL , status VARCHAR2(1) ) PARTITION BY LIST (state) ( PARTITION p_northwest VALUES ('OR', 'WA') TABLESPACE ts1 , PARTITION p_southwest VALUES ('AZ', 'UT', 'NM') TABLESPACE ts2 , PARTITION p_northcentral VALUES ('SD', 'WI') TABLESPACE ts3 , PARTITION p_southcentral VALUES ('OK', 'TX') TABLESPACE ts4 , PARTITION p_northeast VALUES ('NY', 'VM', 'NJ') TABLESPACE ts5 , PARTITION p_southeast VALUES ('FL', 'GA') TABLESPACE ts6 ); CREATE TABLESPACE tbs1 IN SHARDSPACE west; CREATE TABLESPACE tbs2 IN SHARDSPACE west; 

  • 复合分片
    • 允许您使用两级分片。首先,通过范围或列表对数据进行分片,然后通过一致哈希对其进一步进行分片。
    • 在许多使用案例中,特别是对于数据主权和数据邻近性要求,复合分片方法提供了系统管理和用户定义分片方法的最佳选择,为您提供了所需的自动化和对数据放置的控制。
  • 分片存储
    • 分片表的每个分区都驻留在一个单独的表空间中,并且每个表空间都与一个特定分片相关联。
    • 根据分片方法,该关联可自动建立或由管理员定义。
    • 使用系统管理分片的 sharded 数据库中的块的数量可在创建分片目录时指定。如果未指定,将使用块的默认值 120 每个分片。一旦部署分片数据库,只有通过拆分块才能更改块的数量。
    • Oracle 分片创建并管理表空间,作为一个称为表空间集的单元。 PARTITIONS AUTO 子句指定应该自动地确定分区的数量。此类型的哈希在分片之间迁移数据方面提供了更高的灵活性和效率,这对于弹性可扩展性很重要。

创建分片表客户 (客户号未 NULL,姓名 VARCHAR2(50),地址 VARCHAR2(250),约束 RootPK 主键 (客户号)) 按一致哈希 (客户号) 分区分区自动表空间集 ts1; 创建分片表订单 (订单号未 NULL,客户号未 NULL,订单日期日期,约束 OrderPK 主键 (客户号, 订单号),约束 CustFK 外键 (客户号) 参考客户 (客户号)) 按引用 (CustFK) 分区;

    • 在创建按一致哈希分区的 sharded 表之前,必须创建一组表空间(每个分块一个表空间)来存储表分区。通过执行 SQL 语句 “创建表空间集”,自动创建表空间。
      • 创建表空间集 ts1;
    • 此语句中的 PARTITIONS AUTO 表示分区数自动设置为表空间集 ts1 中的表空间数(等于分块数),并且每个分区将存储在一个单独的表空间中。
  • 分片键
    • 分片键支持以下数据类型
      • NUMBER、INTEGER、SMALLINT
      • RAW
      • (N)VARCHAR、(N)VARCHAR2、(N)CHAR
      • DATE、TIMESTAMP

[MySQL 集群]

  • 可以在使用 NDB 集群的 MySQL 服务器上使用其他存储引擎(例如 InnoDB 或 MyISAM)创建表,但由于这些表不使用 NDB,因此它们不参与集群;每个此类表严格限定为创建它的各个 MySQL 服务器实例。
  • 分区。这是集群存储的数据的一部分。每个节点负责为分配给它的至少一个副本(即至少一个备份)保持至少一个可用于集群的可用分区。
  • NDB 集群默认使用的分区数取决于数据节点数和数据节点使用的 LDM 线程数,如下所示
    • [# of partitions] = [# of data nodes] * [# of LDM threads]

[Spanner]

  • Cloud Spanner 通过根据请求负载和数据大小自动分片数据来优化性能。结果上,你可以花更少的时间来担心如何扩展数据库,而将焦点放在扩展业务上。

[CockroachDB]

  • CockroachDB 是世界上唯一允许你在行级别附加到数据的数据库。此功能允许你对用户与其数据之间的距离进行调控。
    • 无论用户在哪里,都确保了终端用户的低延迟。
    • 将数据固定到某个区域以遵守数据保护法。
    • 将特定数据和特定云或数据中心联系在一起。

[YugabyteDB]

  • 分片方法
    • DocDB 将用户表隐式管理为多个分片。这些分片称为数据片。表中每行的主键都唯一确定数据片在其中的位置。
    • YugabyteDB 目前支持两种分片数据的方法 - 哈希(又名一致哈希)分片和范围分片。
    • 哈希分片 YugabyteDB 表的哈希空间是从 0x0000 到 0xFFFF 的 2 字节范围。因此,此类表最多有 64K 个数据片。

CREATE TABLE customers ( customer_id bpchar NOT NULL, company_name character varying(40) NOT NULL, ... PRIMARY KEY (customer_id HASH) ); 

    • 对于一致哈希分片,分片比节点的数量多得多,并且存在显式映射表,用于跟踪分片到节点的分配。在添加新节点时,可以有效地将现有节点中一部分分片移到新节点,而无需进行大规模数据重新分配。
    • 范围分片涉及将表的行拆分为连续范围,这些范围尊重基于主键列值的表的排序顺序。通常,范围分片的表一开始只有单个分片。随着数据插入到表中,它会动态地拆分为多个分片,因为不可能始终提前知道表中的键分布。

CREATE TABLE order_details ( order_id smallint NOT NULL, product_id smallint NOT NULL, unit_price real NOT NULL, quantity smallint NOT NULL, discount real NOT NULL, PRIMARY KEY (order_id ASC, product_id), FOREIGN KEY (product_id) REFERENCES products, FOREIGN KEY (order_id) REFERENCES orders ); 

  • 数据片拆分
    • DocDB 允许通过使用以下三种机制拆分数据片来重新分片数据
      1. 预拆分数据片:在 DocDB 中创建的所有表都可以在创建时拆分为所需数量的数据片。
      2. 手动数据片拆分:运行中的集群中的数据片可以在运行时由用户手动拆分。
      3. 自动数据片拆分:运行中的集群中的数据片根据数据库中的某些策略自动拆分。
    • 自动数据片拆分可以在达到指定大小阈值时自动对集群中的数据重新分片,同时在线进行,对用户透明。
  • 分片键
    • 主键列有两种类型
      1. 哈希主键列:主键可以有零个或多个前导哈希分区列。默认情况下,只有第一列被视为哈希分区列。但这种行为可以通过显式使用 HASH 注解来修改。
      2. 范围主键列:一个表可以拥有零个或多个范围主键列,并且它控制表内行的高级别排序(如果不存在哈希分区列)或拥有相同的一组哈希分区列值的行之间的行的排序。默认情况下,范围主键列按升序存储。但是,可以通过明确使用 ASC 或 DESC 控制此行为。
    • 例如,如果主键规范是 PRIMARY KEY ((a, b) HASH, c DESC),则列 a 和 b 一起用于对表进行哈希分区,并且在 a 和 b 中拥有相同值的行按照 c 值的降序顺序存储。
    • 如果主键规范是 PRIMARY KEY(a, b),则列 a 用于对表进行哈希分区,并且在 a 中拥有相同值的行按照 b 值的升序顺序存储。
  • 指定分片数
    • 对于哈希分片表,您可以使用 SPLIT INTO 子句指定要为表创建的平板电脑数。然后将哈希范围均匀地拆分到这些平板电脑中。
    • 使用 SPLIT INTO 对平板电脑进行预拆分可在生产集群上分发读写工作负载。例如,如果您有 3 台服务器,将表拆分成 30 个平板电脑可以在表上提供写吞吐量。
    • 默认情况下,YugabyteDB 将表预拆分成 ysql_num_shards_per_tserver * num_of_tserver 个分片。SPLIT INTO 子句可用于按表为基础覆盖该设置。
    • 要指定表的平板电脑数,您可以使用 SPLIT INTO 子句。
      • CREATE TABLE tracking (id int PRIMARY KEY) SPLIT INTO 10 TABLETS;

[Azure Synapse]

  • Synapse SQL 利用 Azure 存储来保护您的用户数据安全。数据分片到分布中以优化系统性能。在定义表时,您可以选择用于在数据中进行分布的分片模式。
  • 受支持的分片模式为哈希、循环和复制。

[Greenplum]

  • 所有表都是分布的。创建或更改表时,您可以选择指定 DISTRIBUTED BY(哈希分布)、DISTRIBUTED RANDOMLY(循环分布)或 DISTRIBUTED REPLICATED(完全分布)来确定表行分配。
  • 如果在创建表时未指定 DISTRIBUTED BY 子句,则服务器配置参数 gp_create_table_random_default_distribution 控制表分配策略。
  • 分片键
    • 具有几何或用户定义数据类型的列不符合作为分布键列的条件。如果表没有符合条件的列,则 Greenplum Database 将随机或以循环方式分布这些行。
    • 用于哈希分布策略的哈希函数是由该列数据类型的哈希运算符类定义的。由于 Greenplum Database 默认使用数据类型的默认哈希运算符类,因此与用于哈希联接和哈希聚合的运算符类相同,适用于大多数用例。但是,您可以在 DISTRIBUTED BY 子句中声明非默认哈希运算符类。
      • CREATE TABLE atab (a int) DISTRIBUTED BY (a abs_int_hash_ops);

[Citus]

  • 提供了分布式、复制和本地表。
  • 可以使用 create_distributed_table() 函数来指定表分布列并创建工作分片。
    • SELECT create_distributed_table('github_events', 'repo_id');
    • 该函数会通知 Citus 根据 repo_id 列(通过对列值进行哈希计算)对此 github_events 表进行分布。该函数还使用 citus.shard_count 和 citus.shard_replication_factor 配置值在工作器节点上创建分片。
    • 此示例将创建 citus.shard_count 个分片,每个分片的拥有部分哈希令牌空间,并根据默认的 citus.shard_replication_factor 配置值进行复制。在工作器上创建的分片副本与协调器上的表具有相同的表模式、索引和约束定义。创建副本后,此函数会将所有分布式元数据保存在协调器上。
    • 每个已创建的分片均分配有唯一分片 ID,而该分片的所有副本都具有相同的分片 ID。每个分片都用名为 tablename_shardid 的常规 PostgreSQL 表在工作器节点上表示,其中 tablename 是分布式表的名称,而 shardid 是分配给该分片的唯一 ID。
    • 可以连接到工作器 postgres 实例,以便在各个分片上查看或运行命令。
    • 可以在将分片分布到整个群集时为每个表配置分片数量。为每个分布式表选择分片数量需在具有更多分片的灵活性以及跨分片进行查询规划和执行的开销之间取得平衡。最佳选择将根据对数据的访问模式而有所不同。
      • 例如,在多租户数据库用例中,我们建议选择 32 - 128 个分片。对于较小的工作负载,比如 <100GB,可以从 32 个分片开始,而对于较大的工作负载,可以选择 64 个或 128 个。这意味着可以灵活地将工作器机器从 32 个扩展到 128 个。
      • 在实时分析用例中,分片数量应该与工作器上的核心总数相关。为确保最大并行度,每个节点上应创建足够的分片,以致每个 CPU 核心至少一个分片。我们通常建议创建大量初始分片,例如是当前 CPU 核心的 2 倍或 4 倍。如果你添加了更多工作器和 CPU 核心,这将允许在将来扩展。
    • 若要为想要分布的表选择分片数量,请更新 citus.shard_count 变量。这会影响随后对 create_distributed_table 的调用。例如
      • SET citus.shard_count = 64;
    • 但请记住,对于每次查询,Citus 会为每个分片打开一个数据库连接,而这些连接受到限制。
  • 分片键
    • Citus 要求主键和外键约束包括分布列。此要求可在分布式环境中极大地提高对这些约束的执行效率,因为只需要检查一个节点即可保证这些约束。
    • 你必须选择每张表中的单列作为分布列。人们想要按两列分布的常见情况是对时间序列数据的分布。然而,对于这种情况,我们建议对非时间列使用哈希分布,并将其与时间列上的 PostgreSQL 分区相结合。
  • 手动放置以实现租户隔离
    • 为了改进资源分配并保证租户 QoS,值得将大租户移到专用节点。Citus 提供了实现此目的的工具。

[Postgres-XL]

  • 分布式和复制表格可用。
  • 用于特定行的 Data 节点将基于分布列的值来确定,如果使用了按哈希分布,则选择该值。
  • 如果没有使用,则如果存在 CREATE TABLE 子句中,则使用主键或唯一约束的第一列。
  • 如果两者都不存在,则使用外键约束的第一列,其理念是子数据可以与父表在同一个节点上并置。
  • 如果没有定义此类约束,则 Postgres-XL 将选择它可以找到的第一个合理的列,即具有确定性可分布的数据类型的第一个列。你还可以选择其他分布方法,例如 MODULO 和 ROUNDROBIN。若要指定选择哪个列作为分布列以及选择什么值测试,你可以执行以下操作

CREATE TABLE disttab( col1 int, col2 int, col3 text ) DISTRIBUTE BY HASH(col1); 

已复制的表

<问题>

  • Q1:用户如何创建一份已复制的表?
  • Q2:我们在哪里存储已复制的表数据?我们在哪里允许用户更新它?
  • Q3:已复制的表如何在节点间复制?
    • 逻辑复制
    • 基于语句的复制和 2PC(Citus,Postgres-XL)
    • 基于物化视图的复制(Oracle 分片:默认延迟为 60 秒,可配置)

[Oracle]

  • 复制的表是已复制到所有分片的非分片表。
  • 通常包含常见的引用数据。
  • 可以在每个分片上进行读取和更新。
  • Oracle 分片使用物化视图复制来同步复制表的的内容。每个分片上的复制表由一个物化视图表示。物化视图的主表位于分片目录中。CREATE DUPLICATED TABLE 语句自动创建主表、物化视图以及物化视图复制所需的其他对象。
  • 你可以在分片上更新已复制的表。更新首先从分片通过 dblink 传播到分片目录上的主表。然后,更新结果作为物化视图刷新,异步传播到所有其他分片。
  • 所有分片上的物化视图均会按可配置频率自动刷新。所有重复表的刷新频率都由数据库初始化参数 SHRD_DUPL_TABLE_REFRESH_RATE 控制。此参数的默认值为 60 秒。
  • 当在分片上运行的事务尝试更新在分片目录中删除的行时,可能会出现竞争条件。在这种情况下,系统会返回一个错误,并且对分片的事务将回滚。

CREATE DUPLICATED TABLE Products ( StockNo NUMBER PRIMARY KEY , Description VARCHAR2(20) , Price NUMBER(6,2) ); 

[Azure Synapse]

  • 复制表为小型表提供了最快的查询性能。
    • 已复制的表在每个计算节点上缓存表的一个完整副本。
    • 因此,复制表消除了在连接或聚合之前在计算节点之间传输数据所需的步骤。
    • 复制表最适合用于小型表。还需要额外的存储空间,并且在写入数据时会产生额外的开销,这使得大型表不切实际。

[Greenplum]

  • 复制表的首要用例是
    • 解除对用户定义函数对区段执行操作的限制
    • 无需将常用表广播到所有区段,即可改善查询性能
  • Greenplum 数据库返回查询的列不存在错误,因为它们没有单一、明确的值,因此无法在对复制表的用户查询中引用隐藏的系统列(ctid、cmin、cmax、xmin、xmax 和 gp_segment_id)。

[Citus]

  • 引用表
    • 创建在所有节点上复制的引用表,如下所示
      • SELECT create_reference_table('geo_ips');
    • 除了将表作为单个复制分片进行分配之外,create_reference_table UDF 还会在 Citus 元数据表中将其标记为引用表。
    • 对于这样标记的表,Citus 会自动执行两阶段提交(2PC)以修改,这样可以提供强一致性保证。

[Postgres-XL]

  • 创建复制表如下所示

CREATE TABLE repltab ( col1 int, col2 int ) DISTRIBUTE BY REPLICATION; 

  • 读取复制表时,协调器可以选择任意数据节点进行读取。最有效的方式是选择在同一硬件或虚拟机上运行的数据节点。这称为首选数据节点,并且可以通过每个协调器的 GUC 本地进行指定。
  • 写入复制表时,所有协调器首先选择相同的数据节点,以避免更新冲突。这称为主数据节点。

分区

<问题>

  • Q1:跨节点的表分布与分区之间的关系是什么?

[MySQL 集群]

  • 唯一支持的用户定义分区类型是 KEY 和 LINEAR KEY。
  • 在使用用户定义分区时,每个节点组的最大分区数为 8。

[Greenplum]

  • Greenplum 数据库将表划分为段(也称为分区)以实现大规模并行处理。在使用 PARTITION BY(以及可选的 SUBPARTITION BY)子句的 CREATE TABLE 期间对表进行分区。
  • Greenplum 数据库支持
    • 范围分区
    • 列表分区
    • 两种类型的组合
  • 分区不会更改各个段中表数据的物理分布。
    • 表分布是物理的:Greenplum 数据库对各个段中的分区表和非分区表进行物理划分,以便实现并行查询处理。
    • 表分区是逻辑的:Greenplum 数据库对大表进行逻辑划分,以改善查询性能并促进数据仓库维护任务,例如将旧数据从数据仓库中滚动导出。
  • 不支持对复制表(DISTRIBUTED REPLICATED)进行分区。
  • 分区表上的主键或唯一约束必须包含所有分区列。
  • 唯一索引可以省略分区列;但是,它仅在分区表的各个部分中强制实施,而不在整个分区表中强制实施。

表空间

<问题>

  • Q1:我们如何向用户展示表空间功能?

[Greenplum]

  • 文件系统位置必须存在于所有主机上,包括运行主服务器、备用主服务器、每个主段和每个镜像段的主机。

[Postgres-XL]

  • 为所有协调器和数据节点分配一个表空间的相同路径。所以在创建表空间时,用户需要对集群中所有涉及服务器上的同一个位置路径拥有权限。

数据同置

  • 使用户能够将一起访问的相关数据同置在同一节点上,以提高性能,并将它们一起移动到另一个节点。

<问题>

  • Q1:用户如何指定数据同置?

[Oracle]

  • 提供了一个称为表族的特性。

[Spanner]

  • Cloud Spanner 的表交错对于很多父级-子级关系是不错的选择,其中子表的 primary key 包含父表的 primary key 列。将子行与其父行同置能大幅提高性能。
    • 例如,如果你有一个 Customers 表和一个 Invoices 表,你的应用程序经常会获取给定客户的所有发票,你可以将 Invoices 定义为 Customers 的一个子表。在这么做时,你就是在两个逻辑上独立的表之间声明了一个数据位置关系:你要告诉 Cloud Spanner,在物理上用一行 Customers 将一行或多行 Invoices 存储在一起。
    • 你应该选择将父级-子级关系表示为交错表或外键,但不要同时表示。
    • Cloud Spanner 根据 primary key 值按排序顺序存储行,在共享相同 primary key 前缀的父行之间插入子行。沿 primary key 维度在父行之间插入子行的过程称为交错,子表也被称为交错表。
    • 如果你的应用程序经常需要检索某个歌手的所有专辑的信息,那么你应该将 Albums 创建为 Singers 的子表,这将沿着 primary key 维度将来自两个表的行同置在一起。
    • 交织行首先按父表的行排序,然后按共享父主键的子表的连续行排序,即“歌手 (1)”、然后为“专辑 (1, 1)”、然后为“专辑 (1, 2)”,依此类推。

CREATE TABLE Singers ( SingerId INT64 NOT NULL, FirstName STRING(1024), LastName STRING(1024), SingerInfo BYTES(MAX), ) PRIMARY KEY (SingerId); CREATE TABLE Albums ( SingerId INT64 NOT NULL, AlbumId INT64 NOT NULL, AlbumTitle STRING(MAX), ) PRIMARY KEY (SingerId, AlbumId), INTERLEAVE IN PARENT Singers ON DELETE CASCADE; 

[CockroachDB]

  • 如果表是交织的,写入一个表(称为子表)的数据将直接插入到密钥-值存储中的另一个表(称为父表)中。这是通过将子表的 Primary Key 与父表 Primary Key 进行匹配来实现的。
    • 对于要匹配 Primary Key 的交织表,子表必须将父表的整个 Primary Key 用作其自己 Primary Key 的前缀,这些匹配的列称为交织前缀。最简单的想法是将这些列视为表示相同的数据,通常通过外键实现这一点。
    • 为了正式执行每个表的交织前缀列之间的关系,我们建议使用外键约束。

CREATE TABLE orders ( customer INT, id INT, total DECIMAL(20, 5), PRIMARY KEY (customer, id), CONSTRAINT fk_customer FOREIGN KEY (customer) REFERENCES customers ) INTERLEAVE IN PARENT customers (customer); 

[YugabyteDB]

  • 表并置会将其所有数据放入一个称为并置表的单一平板电脑中。这可以显著增加每个节点可支持的关系(表、索引等)的数量,同时保持每个节点的平板电脑数量较低。
  [Citus]
  • 并置是战术性地划分数据的实践,将相关信息保留在同一台机器上以实现高效关系运算,同时利用整个数据集的水平可伸缩性。
    • 数据并置的原则是数据库中的所有表都具有公共分布列,并且以相同方式跨机器分片,使得具有相同分布列值的行始终位于同一台机器上,即使跨越不同的表也是如此。只要分布列提供有意义的数据分组,即可在组内执行关系运算。
    • 表以组的形式并置。要手动控制表的并置组分配,请使用 create_distributed_table 的可选参数 colocate_with。
    • 如果您不考虑表的并置,则忽略此参数。它的默认值为“default”,该值将包含相同分布列类型、分片计数和复制因子的任何其他默认并置表的表分组在一起。如果您想中断或更新此隐式并置,可以使用 update_distributed_table_colocation()。

-- 通过使用相同的 -- 分布列类型和碎片计数搭配默认并置组,这些表格会隐式并置

    • 如果某个新表与其在原本隐式并置组中的其他表无关,请指定 colocated_with => 'none'。
    • 将无关的表拆分为其独立的并置组会提高碎片重新平衡性能,因为同一组中的碎片必须一起移动。

-- 未与其他表并置

    • 如果表确实相关(例如将被连接),则对其进行明确并置可能很有意义。适当并置的好处比任何重新平衡开销都更重要。
    • 要显式地并置多张表,请分布一张表,然后将其他表放入其并置组。例如

-- 分布商店

  • 为了确保并置,即使在重新平衡操作后,具有相同哈希范围的碎片也会始终放置在同一节点上,以便相等的分布列值始终位于表中的同一节点上。
  • 插入选择
  • 当表格并置时,支持使用 INSERT / SELECT 语法将分布式表上的查询结果复制到分布式表。

查询规划、执行和调整

希望实现

  • 跨节点并行查询
  • 碎片连接,其中表的并置碎片在每个远程节点上连接,并且连接结果被发送回本地节点
  • 通过在远程节点之间直接交换数据来优化连接执行,而无需本地节点中继数据
  • 在规划查询时将节点间数据传输纳入成本

<问题>

  • 问 1:数据库统计信息存储在哪里?
  • 问 2:应该在本地节点上制定整个查询计划并将其发送到远程节点,还是应该发送查询片段文本并在远程节点上制定其查询计划?
  • 问 3:我们如何表示节点间通信成本?
  • 问 4:EXPLAIN 为分布式查询提供了哪些信息?

[Oracle]

  • 多碎片查询和未指定分片键的查询通过多碎片查询协调器路由,该协调器充当请求数据的应用程序的代理。多碎片查询协调器(即“协调器”)在分片目录或其副本上运行。
  • 多碎片 DML 不支持并行 DML。DML 将始终一次运行在一个碎片上(串行)。
  • MERGE 语句仅部分受到 Oracle Sharding 的支持,也就是说仅支持影响单个分片的 MERGE 语句。如果 MERGE 语句需要修改多个分片,则会引发 ORA 错误。
  • 多分片 DML 不支持触发器。
  • 协调器的 SQL 编译器分析并改写查询,将其改写为由参与分片发送和执行的查询片段。查询会被改写,以便在参与分片上完成大部分查询处理,然后由协调器进行汇总。
    • 数据库链接用于协调器和分片之间的通信。
    • 高层次上,协调器会将每个传入查询 Q 改写为分布式形式,即由两个查询组成,CQ 和 SQ,其中 SQ(分片查询)是 Q 中在每个参与分片上执行的部分,CQ(协调器查询)是 Q 中在协调器分片上执行的部分。
    • Q => CQ ( Shard_Iterator( SQ ) )
    • 每个分片都会生成一个针对分片上可用数据大小和计算资源优化的独立执行计划。
  • 如果仅标识了单个参与分片,则会将完整查询路由到该分片进行执行。这称为单分片查询。
  • 单分片查询支持 SELECT、UPDATE、DELETE、INSERT、FOR UPDATE 和 MERGE。不支持 UPSERT。
  • 在多分片查询中只允许在 SELECT 子句中使用用户定义的 PL/SQL。如果在 WHERE 子句中指定了此类内容,则会引发一个错误。
  • 仅涉及重复表的查询在协调器上运行。
  • 您无需连接到各个分片即可查看 SQL 片段的说明计划。在 dbms_xplan.display_cursor() 中提供的接口显示了协调器上在分片上执行的 SQL 片段的计划,并且 [V/X]$SHARD_SQL 会将多分片查询的分片 SQL 片段唯一映射到目标分片数据库。

[Spanner] 感知位置的基于成本的优化器

  • 拆分可以独立地相互移动,并被分配到不同的服务器(可能位于不同的物理位置)。为了在分布式数据上评估执行计划,Cloud Spanner 使用基于以下内容的执行:
    • 包含数据的服务器中本地执行子计划
    • 带激进分布修剪的多个远程执行的编排和汇总
  • Cloud Spanner 使用原始运算符分布式联合以及其变种分布式交叉应用和分布式外部应用,来启用此模型。
  • Cloud Spanner 中的 SQL 查询会首先编译成执行计划,然后发送到初始根服务器进行执行。根服务器的选择目的是为了尽量减少到达所查询数据的跳数。然后,根服务器会
    1. 启动子计划的远程执行(如果需要)
    2. 等待远程执行的结果
    3. 处理任何剩余的本地执行步骤,例如汇总结果
    4. 返回查询结果
  • 接收子计划的远程服务器充当其子计划的“根”服务器,遵循与最顶层根服务器相同的模型。结果是一个远程执行树。
  • 你可以通过 Cloud 控制台或客户端库来检索查询执行计划。

[CockroachDB]

  • 默认情况下,CockroachDB 在创建表时和表更新时自动生成表统计信息。它通过一个后台作业实现此功能,该作业自动统计
    • 所有已建立索引的列
    • 最多 100 个未建立索引的列
  • 模式更改会触发对受影响表的自动统计信息收集。
  • 由于使用复制区域有不同的局部性约束,所以针对多个相同的索引,优化器将优先选择最靠近正在计划查询的网关节点的索引。
  • EXPLAIN 显示涉及查询执行的节点。例如输出,请参阅 EXPLAIN

[Greenplum]

  • 优化器使用的统计信息经过计算并保存在主机上的系统目录中。
  • 主服务器对查询进行优化。结果查询计划可能是并行的或有针对性的。
    • 主服务器将并行查询计划分派到所有分段。
    • 主服务器将有针对性的查询计划分派到单个分段。
  • 大多数数据库操作(例如表扫描、联结、聚合和排序)在所有分段中并行执行。
  • 移动操作涉及在查询处理期间在分段之间移动元组。例如,按不同列分布的表之间的联结会执行移动操作。
  • 处理查询计划的同一部分但处在不同分段上的相关进程称为组。在完成一部分工作后,元组从一个进程组沿查询计划向上流向下一个进程组。分段之间的这种进程间通信称为互连组件。
  • 有关 EXPLAIN 输出的示例,请参阅 查询分析

[Citus]

  • 通过将其拆分为在工作分片上并行运行的多个片段查询,对传入查询进行并行化处理。
  • 在规划 SQL 查询时,采用一个两阶段优化器。
    1. 第一阶段涉及将 SQL 查询转换为它们的交换性和关联性形式,以便可以下推并在工作分片上并行运行。
  • 共置联结:当两个表共置时,可以在其公共分布列上有效地联结它们。共置联结是联结两个大型分布表的最高效方式。
  • 重新分区联接:允许通过为查询动态重新分区表而在非分布式键列上进行联接。在这种情况下,要分区的表由查询优化器根据分布列、联接密钥和表的规模确定。使用重新分区的表,可以确保只有相关的分片对彼此联接,极大地减少了跨网络传输的数据量。
  • 提供一个分布式 EXPLAIN 功能,在分布式数据库中执行相同的功能。
    • 设置 citus.explain_all_tasks = 1;
    • 这将导致 EXPLAIN 显示所有任务(而不仅仅是一个任务)的查询计划。

[Postgres-XL]

  • 在一个协调器上生成一次计划,并将其下发到各个数据节点。然后执行此计划,数据节点直接彼此通信,其中每个节点都了解它希望从何处接收它需要发送的任何元组,以及它需要将其发送到何处。返回顶部
  • 从数据节点中提取统计数据,并将其存储在每个协调器的目录表中,以帮助制定查询规划决策。
  • 应用传统的 PostgreSQL 计费,但 Postgres-XL 还会尝试考虑为用于节点间联接而在网络中传输行的成本,这是一项昂贵的操作。
  • 以分布式或复制方式存储表数据。为了利用此优点,计划器尝试找到尽可能多地利用数据节点功能的最佳方法。
    • 如果按分布列完成等值联接并且它们共享分布方法(哈希/模数),则协调器可以告诉数据节点执行联接。
    • 如果不是这样,它可能会告诉数据节点将行运送到其他数据节点,并期望从其他数据节点向其运送行。
  • EXPLAIN 提供将执行的群集范围执行计划,并让深入了解如何并行处理查询的内部工作原理。


可用性

目标

  • 必须考虑应用程序可用性和数据可用性。
  • 最大程度地提升故障隔离性:一个节点的故障只应该影响访问它的应用程序。
  • 对群集配置进行建模,使其适合于公共云中常见的层次结构区域和可用性分区 (AZ) 结构,并提供 HA 功能以从区域或 AZ 故障中恢复。

<问题>

  • 问题 1:我们如何描述可用性(例如,99.99% 或 99.999% 的正常运行时间)?

[MySQL 集群]

  • 99.999%

[Spanner]

  • 多区域配置提供 99.999% 的可用性,高于 Cloud Spanner 区域配置提供的 99.99% 的可用性。

故障恢复

<问题>

  • 问题 1:我们是否需要或推荐像 Pacemaker 这样的集群软件来进行隔离、STONITH 和故障切换协调,或者一些像 JGroups、ZooKeeper 和 etcd 这样的组协调软件?
  • 问题 2:每个节点如何监视其他节点?(心跳、流言等)
  • 问题 3:我们如何区分宕机节点、出于计划维护而临时停止的节点以及已退役的节点?
  • 问题 4:我们如何确保每个节点组内的数据可用性?
    • 我们是否为一个节点组中所有成员节点定义相同的数据集以进行冗余?
    • 选项 1:依赖于存储硬件或软件提供冗余
    • 选项 2:DBMS 提供主从复制(物理或逻辑)
    • 选项 3:DBMS 采用多主拓扑结构,例如 MySQL 组复制
  • 问题 5:复制的单位是什么?
    • 选项 1:分片(颗粒度最高;失败节点的分片可分配到多个节点,避免一个节点过载)
    • 选项 2:表空间
    • 选项 3:节点(颗粒度最低;接管的节点可能会过载)
  • 问题 6:我们假设的典型副本数量是什么?(最近 3 个,Amazon Aurora = 6)
  • 问题 7:当当前主/领导节点发生故障时,我们如何在节点组中选举一个主/领导节点?
  • 问题 8:每个节点的故障会对应用程序显示什么?
    • 我们能否尽可能地掩盖节点中断对应用程序的影响?
    • 我们如何通知应用程序节点故障?(例如,指示事务可重试的 SQLSTATE)
    • 我们能否使应用程序避免 TCP 超时?
    • 在远程节点发生故障后,我们如何继续会话?(会话变量、事务、游标)

[Oracle]

  • 推荐使用 Oracle Data Guard 来提高分片目录的高可用性。分片目录的可用性不会影响分片数据库的可用性。分片目录中断仅影响在自动故障转移到备用分片目录所需的短时间内执行维护操作或多分片查询的能力。分片数据库继续路由和执行事务,不受目录中断的影响。
  • 如果某个参与分片宕机,那么协调器会向具有相同数据另一个分片发送该查询。
  • 如果在参与分片执行查询期间发生故障,那么用户会收到一条错误信息。
  • 数据可用性
    • 对于用户定义的分片数据库,支持两种复制方案:Oracle Data Guard 或 Oracle Active Data Guard。如果使用 Oracle GoldenGate 作为复制方法,则不支持用户定义分片。
    • Oracle Data Guard 复制针对分片(主分片)维护一个或多个同步副本(备用分片),以实现高可用性和数据保护。可以本地或远程部署备用分片,当使用 Oracle Active Data Guard 时,还可以将其开放为只读访问。
    • 在系统管理和复合分片中,复制的逻辑单元是一组称为分片组的分片。
    • 在系统管理的分片中,分片组包含分片数据库中存储的所有数据。这些数据通过一致哈希方式分片到构成分片组的分片中。属于分片组的分片通常位于同一数据中心。整个分片组可以完全复制到同一数据中心或不同数据中心中的一个或多个分片组中。
    • 使用用户自定义分库分表时,复制的逻辑(和物理)单元称为分片。分片不会合并到分片组中。每个分片及其副本会组成对应一个单一 Data Guard Broker 配置的分片空间。可以为每个分片空间单独配置复制。分片空间可以有不同数量的备用,它们可以位于不同的数据中心中。
    • 在 Oracle GoldenGate 中,复制在块级别处理。例如,存储在每个分片中的一半数据复制到一个分片,另一半复制到另一个分片。如果任何分片变为不可用,其工作负载将在分片组中的其他两个分片间分割。多故障转移目标能减轻分片故障的影响,因为没有哪个单一分片必须处理故障分片的所有工作负载。
    • 使用 Oracle GoldenGate 复制时,一个分片组可以包含分表中每个行的多个副本;因此,会在分片组内提供高可用性,并且无需拥有分片组的本地副本,因为在 Data Guard 复制中需要这样。每个行在分片组内复制的次数称为其复制因子,并且是可配置的参数。
    • 为了提供灾难恢复,可以将分片组复制到一个或更多的数据中心。分片组的每个副本可以具有不同的分片数、复制因子、数据库版本和硬件平台。但是,所有分片组副本必须具有相同数量的块,因为复制在块级别完成。

[MySQL 集群]

  • 自我修复
    • 失败的节点能够通过在重新加入群集之前自动重启和与其他节点重新同步来自我修复,具有完全的应用程序透明度。
    • 数据节点恢复需要从正常的数据节点同步失败节点的数据,并在数据节点返回服务之前重新建立基于磁盘的重做和检查点日志。此恢复可能需要一些时间,在这期间群集以较低冗余运行。
  • 使用心跳和超时机制将节点的长时间通信丢失视为节点故障。
  • 故障转移时间
    • 自动故障转移 - MySQL 群集的心跳机制会立即检测到任何故障,并且在群集中的其他节点自动执行故障转移,通常在一秒内完成,且不会中断对客户端的服务。
  • 数据可用性
    • 副本。这是群集分区的一个副本。节点组中的每个节点都存储一个副本。
    • 副本数量等于每个节点组的节点数。最多完全支持 4 个数据副本。
    • 同步复制。每个数据节点中的数据会同步复制到另一个数据节点。所有数据节点都保持同步,并且由任何一个数据节点提交的事务都会针对所有数据节点提交。
    • 节点组。一个节点组包含一个或多个节点,并且存储分区,或者副本集。一个 NDB 群集中的节点组数量不可直接配置;它取决于数据节点的数量和副本的数量
      • [节点组数量] = [数据节点数量] / NoOfReplicas
    • NDB 集群中的所有节点组必须具有相同数量的数据节点。
    • 节点组是隐式形成的。第一个节点组是由具有最低节点 ID 的数据节点集形成的,下一个节点组是由拥有较低节点 ID 集的数据节点形成的,依此类推。比如,假设我们有 4 个数据节点,将 NoOfReplicas 设置为 2。这四个数据节点具有节点 ID 2, 3, 4 和 5。则第一个节点组由节点 2 和 3 形成,第二个节点组由节点 4 和 5 形成。

[Spanner]

  • 在区域和多区域配置中提供透明、同步复制。
  • 复制用于全球可用性和地理位置。
  • 数据分布:Cloud Spanner 在具有强一致性保证的区域之间自动复制您的数据。这允许将您的数据存储在使用该数据的位置,从而可以减少延迟并改善用户体验。
  • 外部一致性:即使 Cloud Spanner 在地理上相距遥远的位置之间复制,您仍然可以像在单个机器上运行数据库一样使用 Cloud Spanner。事务是可序列化的,数据库内的事务顺序与客户观察到的事务提交顺序相同。外部一致性比“强一致性”更能提供可靠的保证,“强一致性”是由其他一些产品提供的。
  • 系统还可以动态且透明地在数据中心之间移动数据以平衡数据中心之间的资源使用情况。
  • 数据可用性
    • 尽管构建 Cloud Spanner 的基础分布式文件系统已经提供字节级复制,Cloud Spanner 还会复制数据以提供数据可用性和地理位置的额外优势。在较高的层面上,Cloud Spanner 中的所有数据都整理成行。Cloud Spanner 创建了这些行的多个副本或“副本”,然后将这些副本存储在不同的地理区域。Cloud Spanner 使用基于 Paxos 的同步复制方案,其中投票副本在写入提交前对每个写入请求进行投票。全局同步复制的这一特性让您能够从任何 Cloud Spanner 读写或只读副本读取最新数据。
    • 拆分是顶级表格中一系列连续行,其中行是按主键排序的。拆分中的所有数据在副本中都以物理方式存储在一起,Cloud Spanner 从独立故障区域提供每个副本。
    • 使用 Paxos 存储和复制一组拆分。
    • 对于每组 Paxos 副本,会选出一个副本担任领导者角色。领导者副本负责处理写入,而任何读写副本或只读副本都可以在不与领导者通信的情况下提供读取请求(不过,如果请求强读,那么通常会与领导者协商以确保只读副本已收到所有最近的改动)。
    • 领导者副本会记录传入的写入,并将其并行转发给有资格对该写入进行投票的其他副本。每个有资格的副本都将完成其写入,然后向领导者反馈对是否提交写入的投票。在投票副本(或“写入法定人数”)的大多数同意提交写入时,则提交写入。在后台,所有剩余的(非见证)副本都会记录写入。如果读写副本或只读副本在记录写入时落后,那么它可以从其他副本请求缺失的数据,以获得数据的一个完整且最新的副本。
    • 数据行会按架构中的祖先关系被分区到称为目录的集群中。每个目录都至少有一个片段,大型目录可能有多个片段。组存储目录片段的集合。每个组通常在每个数据中心拥有一个副本平板电脑。
    • 数据使用 Paxos 算法进行同步复制,且组的所有平板电脑都存储相同的数据。一个副本平板电脑被选为该组的 Paxos 领导者,该领导者是该组所有事务活动的门户。
    • 组还可以包含只读副本,它不会对 Paxos 算法进行投票,也不能成为组领导者。
    • 数据的复制配置可以由应用程序以精细化实现动态控制。应用程序可以指定约束来控制
      • 哪个数据中心包含哪些数据
      • 数据与其用户相距多远(以控制读取延迟)
      • 副本彼此相距多远(以控制写入延迟)
      • 维护多少副本(以控制耐用性、可用性和读取性能)
    • 对于任何区域配置,Cloud Spanner 都会在该区域的不同 Google Cloud 区域中各自维护 3 个读写副本。每个读写副本都包含操作数据库的一个完整副本,能够提供读写和只读请求。Cloud Spanner 在不同的区域中使用副本,以便在发生单区域故障时,数据库仍然可用。
    • 对拆分不同副本的持续复制由 Paxos 算法管理。在 Paxos 中,只要拆分的投票副本的大多数都处于正常运行状态,便可选择其中一个副本作为领导者来处理写入,并允许其他副本提供读取。
    • 要保证写入的持久性,Spanner 事务通过写入突变到受影响的分区的至少多数副本并提交。且承载那些分区的机器持久的将那些突变写入分布式文件系统中。Spanner 采用的是“无共享”体系结构(具有高扩展性),但由于集群中的任何服务器都能从此分布式文件系统中读取数据,因此我们可以从整个机器故障中快速恢复。
    • 分区在节点之间分布的方式在每个区域中可能有所不同,Paxos 领导也不全部驻留在同一个区域中。这种灵活性帮助 Spanner 对特定类型的负载情况和故障模式具有更高的稳定性。
  • Cloud Spanner 有三种类型的副本:读写副本、只读副本和见证副本。单区域实例只使用读写副本,而多区域实例配置使用全部三种类型的副本。
  • 见证副本不支持读取,但会参与投票以提交写入。无需读写副本存储数据完全副本和为读取提供服务所需的存储和计算资源,这些副本简化了在未达到写入法定人数的情况下实现法定人数。
  • 见证副本
    • 仅用于多区域实例。
    • 不保持数据完全副本。
    • 不提供读取服务。
    • 投票决定是否提交写入。
    • 参与领导选举,但没有资格成为领导。
  • 读取
    • 客户端读取请求可能会在领导副本处执行或需要与领导副本通信,具体取决于读取请求的并发模式。
    • 作为读写事务一部分的读取是通过领导副本提供的,因为领导副本维护执行串行化所需的锁。
    • 单个读取方法(事务上下文之外的读取)和只读事务中的读取可能需要与领导通信,具体取决于读取的并发模式。
      • 强读取请求可以发送至任何读写副本或只读副本。如果该请求发送至非领导副本,则该副本必须与领导副本通信以便执行读取。
      • 陈旧读取请求发送至已追赶至请求时间戳的最近的可用只读副本或读写副本。如果领导是向其发出读取请求的客户端最近的副本,则此处可以为领导副本。
  • 写入
    • Cloud Spanner 需要多数投票副本同意提交才能提交突变。换句话说,写入 Cloud Spanner 数据库的每次写入都需要投票副本之间的通信。
    • 为使这种通信的延迟最小化,最好使用最少的投票副本数,并将这些副本放置得尽可能近。这就是区域配置仅包含三个读写副本的原因,每个副本都包含数据的完整副本,并且能够投票:如果一个副本发生故障,其他两个副本仍然可以形成写入法定人数,而且由于区域配置中的副本位于同一个数据中心,因此网络延迟最小。
  • 多区域配置根据设计包含更多副本,并且这些副本位于不同的数据中心(以便客户可以从更多位置快速读取其数据)。
    • 这些其他副本应具有哪些特征?它们都可以是读写副本,但这样做不太理想,因为向配置中添加更多读写副本会增加写入法定人数的大小(这意味着由于更多副本相互通信,网络延迟可能会更高,尤其是在副本在地理上分布分散的位置),而且还会增加所需的存储量(因为读写副本包含数据的完整副本)。
    • 多区域配置不会使用更多读写副本,而是包含两种比读写副本具有更少职责的附加副本类型。
      • 只读副本不投票选举领导者或提交写入,因此它们允许你在不增加写入所需的的法定人数规模的情况下扩展读取容量。
  • 地理复制
    • 每个多区域配置都包含两个指定为读写区域的区域,每个区域都包含两个读写副本。
    • 其中一个读写区域指定为默认领导者区域,这意味着它包含数据库的领导者副本。对于每个拆分,将在默认领导者区域中的副本中选择一个领导者。
    • Cloud Spanner 也将见证副本放置在称为见证区域的第三个区域中。
    • 每一次客户向你的数据库发布变异,都会形成一个写入法定人数,该法定人数由来自默认领导者区域的一个副本以及其他四个投票副本中的任意两个组成。(该法定人数可以由组成配置的两个或三个区域中的副本形成,具体取决于哪些其他副本参与投票。)
    • 除了这些 5 个投票副本,该配置还可以包含用于提供低延迟读取的只读副本。包含只读副本的区域被称为只读区域。
    • 一般来说,多区域配置中的投票区域在地理上靠近放置(相距不到一千英里),以形成能够快速写入的低延迟法定人数。然而,这些区域仍然相距甚远(通常至少相距几百英里),以避免协调故障。
    • 发生领导副本故障时,默认领导区域中的其他副本会自动接管领导权。事实上,领导会自行运行运行状况检查,如果检测到自身不健康,可以主动放弃领导权。在默认领导区域中的副本可用时的正常情况下,默认领导区域包含领导,因此此处会首先处理写入。
    • 第二个读写区域包含有资格成为领导的附加副本。在极不可能发生默认领导区域内所有副本丢失的情况下,将从第二个读写区域选择新的领导副本。从第二个读写区域进行的读写工作负载最快。
    • 见证区域包含用于对写入进行投票的见证副本。在罕见的读写区域不可用的情况下,见证副本变得重要。见证区域可以被认为是用于达成写入法定人数的系统配置区域。

[CockroachDB]

  • 数据可用性
    • 多活动可用性是 CockroachDB 版本的高可用性(在部分故障发生时使您的应用程序保持联机),我们设计此版本时避免了主动被动和传统主动主动系统存在的不足。与主动主动设计类似,所有副本都可以处理流量,包括读取和写入。
    • 但是,CockroachDB 还要确保数据在副本间保持一致,以提高其设计的性能,而我们通过使用“一致性复制”来实现此目的。在此设计中,复制请求将发送到至少 3 个副本,并且只有在多数副本确认已收到请求后才将其视作提交。这意味着,即使发生故障,也依然不会影响可用性。
    • 为防止冲突并确保数据的稳定性,丢失多数副本的集群将停止响应,因为它们已无法就数据的状态达成共识。当多数副本重新启动后,数据库将恢复操作。
    • CockroachDB 为确保可用性复制您的数据,并使用 Raft 共识算法来确保副本间的一致性,该算法是 Paxos 的一种流行替代方案。
    • 您可以通过多种方式定义副本的位置,具体取决于您希望保护的故障类型和网络拓扑。您可以在以下位置找到副本
      • 机架内不同的服务器,以容忍服务器故障
      • 数据中心内不同机架上的不同服务器,以容忍机架的电源/网络故障
      • 不同数据中心内的不同服务器,以容忍大规模网络或电源故障
    • 通过 Raft 共识算法,每个已确认的写入都会持续存储在大多数副本上(默认情况下,至少为 2 个)。仅影响少数副本(通常为 1 个)的电源或磁盘故障不会阻止集群运行,也不会丢失任何数据。
  • 自动修复
    • 对于短期故障,例如服务器重新启动,CockroachDB 使用 Raft 继续无缝运行,只要大多数副本仍然可用即可。如果之前的领导失败,Raft 会确保为每组副本选举一位新的领导,这样事务就可以继续执行,受影响的副本一旦重新上线即可重新加入其组。
    • 对于长期故障,例如服务器/机架长时间宕机或数据中心故障,CockroachDB 会自动从丢失的节点重新平衡副本,将未受影响的副本作为来源。使用来自 Gossip 网络的能力信息,集群中的新位置将被识别,并且丢失的副本会以分布式方式重新复制,使用所有可用节点以及集群的聚合磁盘和网络带宽。
  • 读取
    • 与写入不同,读取请求会访问租赁持有者并向客户端发送结果,而不需要与任何其他范围副本进行协调。这减少了涉及的网络往返,并且这是可能的,因为租赁持有者由于所有写入请求也会发送给租赁持有者,而保证是最新的。
  • 写入
    • 对于每个范围,一个副本是写入请求的“领导者”。通过 Raft 共识协议,此副本基于其 Raft 日志确保大多数副本(领导者和足够的跟随者)同意,然后再提交写入。Raft 领导者通常与租赁持有者是同一个副本。
    • 当一个范围收到写入时,包含范围副本的节点的法定人数确认写入。这意味着您的数据已安全存储,并且大多数节点同意数据库的当前状态,即使其中一些节点处于离线状态。
    • 如果写入未达成共识,向前推进将停止,以维护群集内的一致性。
    • 同步复制要求所有写入在被视为已提交之前传播到数据副本的法定人数。
  • 复制区
    • 让您能够控制您的 CockroachDB 群集中的数据在何处执行。具体来说,它们用于控制以下对象所属的数据的副本数量和位置
      • 数据库
      • 索引
      • 群集中的所有数据,包括内部系统数据(通过默认复制区)
    • 对于以上每个对象,您可以控制以下内容
      • 通过群集传播每个范围有多少副本。
      • 哪些约束应用于哪些数据,例如,“表 X 的数据只能存储在德国数据中心”。
      • 范围的最大大小(范围在被拆分之前有多大)。
      • 在进行垃圾回收之前保留旧数据的时间长度。
      • 希望某些范围的租户所在的区域,例如,“对于已受限为至少在一个 region=us-west 中具有一个副本的范围,还尝试将其租户放入 region=us-west”。
    • 集群中的每个范围都是复制区的组成部分。在重新平衡集群中的范围时考虑每个范围的区域配置,从而确保遵守所有约束条件。

[YugabyteDB]

  • 主故障
    • YB-Master 不处于正常 IO 操作的临界路径中,因此其故障不会影响正在运行的 universe。
    • 不过,YB-Master 是 Raft 组的一部分,其中对等方在不同的节点上运行。其中一个对等方是活动主服务器,其它对等方是活动备用服务器。如果活动主服务器(YB-Master 领导端)出现故障,这些对等方会检测到领导端故障并重新选出一个新的 YB-Master 领导端,该领导端在故障发生后的数秒内会变成活动主服务器。
  • 数据可用性
    • DocDB 表中的数据被拆分成平板电脑。默认情况下,每个平板电脑都会使用 Raft 算法在各个节点或故障域(如可用区/机架/区域/云提供商)中同步进行复制。
    • DocDB 在保持数据一致且避免操作员干预的情况下自动同步复制数据以应对故障。它利用 Raft 分布式一致性协议来执行此操作。
  • 读副本
    • 集群内异步副本称为读副本。
    • 除了基于核心分布式一致性的复制之外,DocDB 还扩展了 Raft 以添加读副本(又称观察者节点),它们不参与写操作,但会异步获取数据的时间线一致副本。
    • 读副本是集群中主要数据的只读扩展。对于读副本,集群的主要数据部署在同一区域中的多个区域,或部署在附近的区域中。
    • 读副本不会增加写延迟,因为它不会同步向它们复制数据,而是异步将数据复制到读副本。
  • 集群间的复制
    • 每个 universe 都包含一个主要数据集群和一个或多个读副本集群。因此,每个读副本集群可以独立拥有自己的复制因子。
    • 主集群可以执行写操作和读操作。一个主集群中的节点之间的复制以同步方式进行。
    • 读副本集群只能执行读操作。发送到读副本集群的写操作会被自动重新路由到 universe 的主集群。这些集群有助于为远离主集群的区域提供时间线一致的数据,来增强读操作。这确保了地理分布式应用程序的低延迟读取。
    • 通过从主集群异步复制数据的方式将数据引入读副本集群。换句话说,读副本集群中的节点充当不参与主集群中 Raft 领导端和 Raft 追随者所涉及写路径的 Raft 观察者。
    • 这个只读节点(或时间线一致的节点)仍然比最终一致性好,因为对于最终一致性,应用程序的数据视图可以向前或向后移动,并且难以编程。
  • 故障转移时间
    • RTO(恢复时间目标)为 3 秒,这是完成故障转移并在新区域投入使用的时限。
    • 任何平板对等者的故障都会在几秒钟内自动触发新的 RAFT 级领导者选举,并且位于另一个 YB-TServer 上的另一个平板对等者将成为新的领导者取而代之。平板对等者发生故障后,不可用时段约为几秒钟(假设默认心跳间隔为 500 毫秒)。

[Greenplum]

  • 您可以选择部署主实例的备份或镜像。如果主主机会变得不可操作,备份主机会作为热备用。您可以在指定的冗余主机会上或某个段主机会上部署备用主机会。
  • 备用主机会通过事务日志复制进程保持是最新的,此进程在备用主机会上运行,并且主备主机会之间的数据同步。如果主主机会发生故障,日志复制进程会关闭,管理员可以在其位置激活备用主机会。
  • 检测和管理段故障的方法
    • 在主服务器上,Postgres postmaster 进程会派生故障探测进程 ftsprobe。这也称为 FTS(容错服务器)进程。如果 FTS 出现故障,postmaster 进程会重新启动该进程。
    • FTS 在一个循环中运行,每个周期之间都有睡眠间隔。在每个循环中,FTS 通过使用在 gp_segment_configuration 表中注册的主机名和端口向段实例建立 TCP 套接字连接来探测每个主段实例。
    • 如果连接成功,该段会执行一些简单的检查并报告给 FTS。检查包括对关键段目录执行 stat 系统调用并检查段实例中的内部故障。如果没有检测到问题,则会向 FTS 发送肯定答复,并且不对该段实例执行任何操作。
    • 如果无法建立连接,或者在超时时间内没有收到答复,则会尝试对段实例进行重试。
    • 如果探测尝试的配置最大数量失败,FTS 会探测该段的镜像以确保将其启动,然后更新 gp_segment_configuration 表,将主段标记为“关闭”,并将镜像设置为作为主段。FTS 使用执行的操作更新 gp_configuration_history 表。
  • 启用镜像时,如果主副本变得不可用,系统会自动故障转移到镜像副本。
  • Greenplum 数据库系统只有在所有数据部分在剩余活动段上可用的情况下才能保持在段实例或主机出现故障的情况下保持可用。
  • 当 Greenplum 数据库检测到主段故障时,WAL 复制过程会停止,镜像段会自动作为活动主段启动。
  • 如果一个镜像段在主段处于活动时发生故障或无法访问,主段会跟踪将应用于恢复后镜像的日志中的数据库更改。
  • 如果主数据库无法连接到段实例,它会在 Greenplum 数据库系统目录中标记该段实例无效。段实例会一直保持无效并停止运行,直到管理员将该段重新联机。管理员可以恢复故障段,同时系统正常运行。恢复过程只会复制段在非运行状态时错过的更改。
  • 如果没有启用镜像且一个段变得无效,系统会自动关闭。管理员必须恢复所有故障段,然后才能继续操作。
  • 可以在系统中的主机中按照两种标准配置之一或者您设计的自定义配置排列镜像段。
    • 默认配置名为组镜像,它将一个主机上的所有主段的镜像段放到另一个主机上。
    • 另一种选择名为分布镜像,它将每个主机的镜像分散到剩余的主机上。分布镜像要求系统中的主机比主机上的主段多。在具有多个网络接口的主机上,主段和镜像段会均等地分布到各个接口中。
    • 通过块镜像,节点会划分为各个块,例如四或八个主机的块,每个主机的段的镜像都会放到块中的其他主机上。根据块中的主机数量和每个主机中的主段数量,每个主机都会维护其他主机的各个段的多个镜像。

[Citus]

  • Citus 协调器会维护元数据表,以跟踪所有群集节点和数据库分片在这些节点上的位置。元数据表很小(一般几 MB),且变化非常小。这意味着它们可以复制,如果节点遇到故障,可以快速恢复。用户可以采用若干选项来应对协调器故障。
    1. 使用 PostgreSQL 流复制:您可以使用 PostgreSQL 的流复制功能,创建协调器的热备用。然后,如果主协调器节点发生故障,备用可以自动提升为主要节点,来为您的群集提供查询服务。
    2. 由于元数据表很小,用户可以使用 EBS 卷或者 PostgreSQL 备份工具备份元数据。然后,他们可以轻易复制该元数据到新的节点,以恢复操作。
  • Azure Database for PostgreSQL - Hyperscale(Citus)提供高可用性(HA),以避免数据库宕机。启用 HA 后,服务器组中的每个节点都会获得一个备用节点。如果原始节点出现故障,则其备用节点将被提升以替换它。由于 HA 会使组中的服务器数量翻倍,因此它也会使成本翻倍。
  • 数据可用性
    • Citus 允许对分片进行复制以防止数据丢失。有两种复制模式
      • Citus 分片复制:创建额外的备份分片放置区,并针对它们运行查询以更新其中任何一个。此选项最适合仅追加工作负载。Citus 通过自动复制 DML 语句并管理一致性,跨不同节点复制分片。如果节点出现故障,协调器节点将通过将工作无缝地路由到副本继续处理查询。
      • PostgreSQL 流复制:更高效,可利用 PostgreSQL 流复制将每个节点的整个数据库备份到跟随数据库。这是透明的,不需要 Citus 元数据表的参与。此选项最适合繁重的 OLTP 工作负载。
  • 故障转移时间
    • 故障转移在几分钟内发生,并且提升的节点始终通过 PostgreSQL 同步流复制获得最新数据。

[Postgres-XL]

  • 设置一个备份 GTM 来为 GTM 故障做好准备。
  • 对每个协调器和数据节点使用流复制。
    • 流复制仅在异步模式下经过彻底测试。
    • 不支持热备用。
  • pgxc_ctl 实用工具可以帮助设置数据节点和协调器的从属服务器。
    • PGXC$ add datanode slave dn1 localhost 40101 40111 $dataDirRoot/dn_slave.1 none $dataDirRoot/datanode_archlog.1

<参考文献>

查询处理的连续性

  • 希望在节点发生故障时通过在具有副本的另一个节点上恢复工作来继续并成功完成长时间的数据加载、DML 和 SELECT。

[Spanner]

  • 对于只读事务和快照读取,一旦选择了一个时间戳,提交是不可避免的,除非在该时间戳处的数据已被垃圾回收。因此,客户端可以避免在重试循环内缓冲结果。
  • 当服务器发生故障时,客户端可以通过重复时间戳和当前读取位置在不同的服务器上继续查询。

[Citus]

  • Citus 的分布式执行器运行分布式查询计划并处理在查询执行期间发生的故障。执行器连接到工作节点,将分配的任务发送给它们并监督其执行。
  • 如果执行器无法将任务分配给指定的
  • 执行程序只处理故障查询子树,在处理故障时不会对整个查询进行处理。

脑裂

  • 无论何时集群中的部分变得不可访问,都需要使用某种多数/仲裁机制来保证数据一致性。

[MySQL 集群]

  • 当至少一个节点组中的所有数据节点都处于活动状态时,网络分区并非问题,因为集群中的任何单个子集都不能独立形成一个功能性集群。
  • 真正的问题出现于没有一个节点组拥有其所有活动节点时,在这种情况下,网络分区(脑裂场景)就可能发生了。
  • 然后需要一个仲裁程序。所有集群节点都将相同的节点识别为仲裁程序,通常为管理服务器;然而,可以将集群中任何一个 MySQL 服务器配置为仲裁程序。
  • 仲裁程序接受第一批与它联系的集群节点,并指示剩余节点关闭。
  • 仲裁程序选择受 MySQL 服务器和管理服务器节点的 ArbitrationRank 配置参数控制。您也可以使用 ArbitrationRank 配置参数来控制仲裁程序选择进程。

备份和恢复

  • 希望在跨集群节点时并行进行备份和恢复。

<问题>

  • Q1:我们是否假定或推荐共享存储来累积所有节点的备份(NFS/CIFS,对象存储,云存储)?
  • Q2:我们如何为整个集群的每个备份命名(贴标签)?
  • Q3:我们是否允许恢复为不同的集群配置,即具有不同节点数的集群?
  • Q4:如何实现恢复,以保持节点之间的一致性?
    • 在备份时,分布式事务可能已在一个节点上完成提交,但在其他节点上尚未完成提交。
    • PITR 需要阻止半生不熟的分布式事务,该事务在某个节点上重放直至提交,但在其他节点上并未提交。

[Oracle]

  • 由于分片托管在单独的 Oracle 数据库上,因此您可以使用 Oracle Maximum Availability 最佳实践来单独备份和恢复分片。

[MySQL 集群]

  • 您可以在 NDB 管理客户端和 ndb_restore 程序中使用 NDB Cluster 本机备份和恢复功能。
  • 您还可以使用 mysqldump 和 MySQL 服务器中为此目的提供的传统功能。
  • 备份是在给定时间对数据库的快照。
  • 可以从 NDB 备份中恢复到包含不同数量数据节点的集群,这与从中获取备份的原始集群不同。
  • 备份包含三个主要部分
    1. 元数据。所有数据库表名称和定义
    2. 表记录。在进行备份时存储在数据库表中的实际数据
    3. 事务日志。顺序记录讲述数据如何在数据库中存储以及何时存储
  • 这些部分中的每一个都保存在参与备份的所有节点上。在备份期间,每个节点都会将这三个部分保存在磁盘上的三个文件中
    1. 备份-backup_id.node_id.ctl:一个包含控制信息和元数据的控制文件。每个节点将相同表定义(对于群集中的所有表)保存到此文件的其自己的版本中。
    2. BACKUP-backup_id-0.node_id.data:一个包含表记录的数据文件,该文件以每个碎片为基础进行保存。也就是说,在备份期间,不同的节点会保存不同的碎片。每个节点保存的文件以头开始,头中指出了记录所属的表。在记录列表之后是包含所有记录校验和的页脚。
    3. BACKUP-backup_id.node_id.log:一个包含已提交事务记录的日志文件。只有备份中存储的表上的事务才会存储在日志中。参与备份的节点保存不同的记录,因为不同的节点托管不同的数据库碎片。
  • 备份和还原命令
    • START BACKUP [backup_id] [wait_option] [snapshot_option]
    • ABORT BACKUP backup_id
    • ndb_restore [-c connection_string] -n node_id -b backup_id [-m] -r --backup-path=/path/to/backup/files

[Spanner]

  • 备份
    • 数据一致性:备份是对 Cloud Spanner 数据库在备份创建时刻的事务性和外部一致副本。
    • 在备份创建启动后对数据或模式的任何修改都将不会包括在备份中。
    • 为了确保备份的外部一致性,Cloud Spanner 在创建时刻固定数据库的内容。这可防止垃圾回收系统在备份操作期间移除相关数据值。
    • 然后,实例中的每个区域都会并行复制数据。如果某区域暂时不可用,则备份不会完成,直到该区域重新联机并完成为止。操作完成后即可还原备份。
  • 还原
    • 不必使实例的节点数量保持相同。
    • 恢复过程专为高可用性设计,只要实例中大部分区域和区域可用于恢复,就可以恢复数据库。

[CockroachDB]

  • 分布式备份/恢复
    • 如有需要,可以将全群集备份到 AWS S3、Google Cloud Storage 或 NFS 等服务中
    • BACKUP TO '<backup_location>';
    • 备份过程通过将工作分配给所有节点来尽量减少其对群集性能的影响。每个节点只备份它存储的数据的特定子集(对其进行写入服务的子集),没有两个节点备份相同的数据。
  • 时间点恢复
    • 在对数据进行错误删除或更新之前将 CockroachDB 回滚到确切时刻
    • RESTORE TABLE bank.customers FROM '<backup_location>';
    • RESTORE DATABASE bank FROM '<backup_location>';
    • RESTORE FROM '<backup_location>';
    • 仅当目标群集中从未有过用户创建的数据库或表时,才可以运行全群集还原。
    • RESTORE 流程通过向所有节点分配工作最大程度减少对集群性能的影响。已还原数据的子集(称为范围)在随机选定的节点中均匀分布,每个范围最初仅还原到一个节点。一旦还原范围,节点便开始将其复制到其他节点。

[YugabyteDB]

  • ysql_dump、ysql_dumpall:这些是 pg_dump 和 pg_dumpall 的类似工具。
  • YugabyteDB 支持 YSQL 数据库的分布式备份和还原。尚未支持备份和还原数据库中的各个表。
    • 使用 yb-admin create_database_snapshot 命令创建数据库快照
    • $ yb-admin -master_addresses <ip1:7100,ip2:7100,ip3:7100> create_database_snapshot ysql.<database_name>
    • 有关详细信息,请参阅 快照和还原数据

[Greenplum]

  • 支持并行和非并行方法来备份和还原数据库。并行操作无需考虑系统中段数多少而进行缩放,因为各个段主机同时将各自分的数据写入本地磁盘存储。
  • gpbackup 和 gprestore 是 Greenplum Database 备份和还原实用工具。
    • 默认情况下, gpbackup 会备份指定数据库中的对象以及全局 Greenplum Database 系统对象。
    • gpbackup 在各个表级别使用 ACCESS SHARE 锁,而不是在 pg_class catalog 表中使用 EXCLUSIVE 锁。
    • 默认情况下, gpbackup 仅存储 Greenplum Database 主数据目录中某个备份的对象元数据文件和 DDL 文件。
    • Greenplum Database 段使用 COPY ... ON SEGMENT 命令将已备份表的段存储在每个段的 backups 目录中,这些数据采用压缩 CSV 数据文件形式。
    • 各个 gpbackup 任务在 Greenplum Database 中使用单个事务。在此事务期间,元数据已在主主机上进行备份,各个段主机上的每个表的相关数据使用 COPY ... ON SEGMENT 命令并行写入 CSV 备份文件。备份流程获取每个备份表的 ACCESS SHARE 锁。
    • 如果同时运行 DDL 命令,使用 gpbackup 备份数据库可能会导致 gpbackup 发生故障,目的是确保备份集内一致性。例如,如果在备份操作开始后删除某个表, gpbackup 会退出并显示错误消息 ERROR: relation <schema.table> does not exist。
    • gpbackup 在备份操作过程中删除某张表时可能会因表锁定问题而发生故障。 gpbackup 会生成要备份的表列表,并获取表上的 ACCESS SHARED 锁。如果某张表持有 EXCLUSIVE LOCK, gpbackup 会在释放现有锁后获取 ACCESS SHARED 锁。如果 gpbackup 尝试获取表上锁时该表已不存在, gpbackup 会退出并显示错误消息。
    • 只能将使用 gpbackup 创建的备份还原到与源集群具有相同数量段实例的 Greenplum 数据库集群。如果运行 gpexpand 向集群中添加段,则在开始扩展前创建的备份在扩展完成后将无法还原。

[Postgres-XL]

  • 函数:pgxc_lock_for_backup() 布尔型
    • 锁定集群以进行备份,该备份将还原到将添加的新节点上。
    • pgxc_lock_for_backup 使用 pg_dump/pg_dumpall 对集群进行锁定以进行备份。锁定意味着我们不允许更改由 pg_dump/pg_dumpall 备份目录部分的语句。此函数不会影响 SELECT 或 DML。
    • 为了在添加新节点时锁定集群进行备份,Postgres-XL 使用咨询锁。每次发出不允许的语句时,系统都会尝试以共享模式获取事务级咨询锁,并且当 DDL 或发出 DDL 的事务结束时,该锁将被释放。函数 pgxc_lock_for_backup 尝试在会话级别以独占模式获取相同的咨询锁。因此,有必要在发行者希望系统保持锁定的情况下,保持发出 pgxc_lock_for_backup 的会话处于活动状态。
  • 障碍
    • 必须确保集群中的任何全局事务都必须在所有节点上提交,或者没有任何节点上提交。如果以这样的方式进行全局恢复:在某个节点上,在处理某个全局事务的提交记录后停止 WAL 恢复,但在某些其他节点上处理同一事务的提交记录前停止 WAL 恢复,则集群可能会处于不一致状态。由于全局事务的提交消息可能会在不同节点上乱序到达,因此很难找到公共同步点。
    • 例如,对于两个全局事务 T1 和 T2,这些事务的提交消息可能会到达节点 N1 和 N2,使得 N1 首先收到 T1 的提交消息,而 N2 首先收到提交消息 T2。在这种情况下,在 PITR 期间,无论我们是否在 T1 或 T2 停止,集群都会丢失其一致性,因为至少一个事务将在一个节点上标记为已提交,而在另一个节点上标记为已中止。
    • 在恢复期间,可能很难甚至不可能找到集群范围内的同步点。事实上,这样的同步点可能根本不存在。
    • Postgres-XL 提供了一个机制来在正常操作期间创建这样的同步点,称为障碍。可以使用 SQL 命令 BARRIER 创建障碍
    • 用户必须连接到其中一个协调器并发出 BARRIER 命令,之后可以选择性地跟一个标识符。如果用户未指定标识符,则将生成一个唯一标识符并将其返回给调用者。
    • 收到 BARRIER 命令后,Coordinator 会暂时暂停所有新的两阶段提交。它还会与其他 Coordinator 沟通以确保集群中没有正在进行的两阶段提交。此时,一个带有用户给定的或系统生成的 BARRIER 标识符的隔离 WAL 记录会被写入所有 Data 节点和 Coordinator 的 WAL 流。
    • 用户可以创建任意多个隔离。在执行时间点恢复时,必须在所有 Coordinator 和 Data 节点的 recovery.conf 文件中指定相同的隔离 id。当集群中的每个节点都恢复到相同的隔离 id 时,将达到一个全集群的一致状态。
    • 务必在生成隔离之前获取的备份中启动恢复非常重要。如果未找到匹配的隔离记录(可能是因为隔离是在用于恢复的基准备份之前创建的,也可能未创建该隔离),则运行恢复至结束。
    • CREATE BARRIER barrier_name;
    • CREATE BARRIER 将在集群的每个节点上持续创建新的 XLOG 记录。实际上,隔离是集群中您可恢复到的一个一致点。
    • 如果没有隔离,如果您恢复单个组件,则它可能与其他节点不一致,具体取决于其何时提交。
    • 通过一个远端 Coordinator 中的类似 2PC 的机制创建隔离,它具有准备、执行和结束三阶段。
    • 已在 recovery.conf 中添加了一个名为 recovery_target_barrier 的新恢复参数。若要执行完整的 PITR 恢复,必须将 recovery_target_barrier 设置为已创建隔离的值。然后,将 recovery.conf 分发到每个节点的每个数据文件夹,再一个接一个地重新启动节点。
  • pg_ctl -Z restore
    • 从其他 Coordinator 或 Data 节点导入 Postgres-XL 的目录数据。
  • pg_resetwal
    • 只会为 Coordinator 和 Data 节点本地运行。您应为每个 Coordinator 或 Data 节点手动运行它。

灾难恢复

<问题>

  • Q1:我们是否允许生产和备份站点的集群配置不同?
  • Q2:我们如何复制并应用更改?
    • 一对一:一个集群中的一个节点收集所有更新并将其发送到另一个集群中的一个节点(MySQL 集群)
    • 多对多:一个集群中的每个节点将其更新发送到另一个集群上的对应节点
  • Q3:我们如何在节点之间取得一致性,就像本地数据中心内的 PITR 一样?

[Oracle]

  • 使用云备份服务、RMAN 和 Zero Data Loss Recovery Appliance 进行灾难恢复备份
  • 如遇灾难,请联系 Oracle 支持人员获取具体步骤以恢复分片。

[MySQL 集群]

  • 地理复制 - 地理复制使节点能够被镜像到远程数据中心,以用于灾难恢复。
  • MySQL 集群还可跨数据中心复制,以实现灾难恢复和全球可扩展性。利用其冲突处理机制,每个集群都可以处于活动状态,接受更新,同时保持不同位置之间的一致性。异地更新复制使多个集群能够在地理位置上分布,以实现灾难恢复和全球网络服务的可扩展性。
  • 复制过程是将源集群的连续状态记录到副本集群中并保存的过程。此过程由一个称为 NDB 二进制日志注入器线程的特殊线程完成,该线程在每台 MySQL 服务器上运行并生成二进制日志 (binlog)。此线程确保将产生二进制日志的集群中的所有更改(而不仅仅是通过 MySQL 服务器施加的更改)以正确的序列化顺序插入到二进制日志中。
  • 复制通道需要 two MySQL 服务器充当复制服务器(每个服务器各为源和副本)。例如,这意味着在具有 two 个复制通道(为冗余提供一个额外的通道)的复制设置的情况下,将总共有 four 个复制节点,每个集群两个。

[YugabyteDB]

  • xCluster 复制数据在不同的 YugabyteDB 集群之间异步复制 - 单向复制(主从)或跨 two 个集群的双向复制。
  • 每个 YugabyteDB 的 TServer 都有 CDC 订阅者 (cdc_subscribers),负责获取 TServer 作为领导者的所有表格的更改。
  • 针对一个行或同一表格中的多个行的所有数据更改都将按发生的顺序接收。然而,由于问题的分布式特性,无法保证不同表格之间的顺序。
  • 在活动-活动配置的情况下,如果同一键存在冲突写入,则带有较晚时间戳的更新被视为最新的更新。因此,最终在 two 个数据中心之间进行部署一致。
  • 限制
    • 从生产者处获得的事务将不会自动应用于使用者。也就是说,事务中的某些更改可能会在其他更改之前可见。
    • 目前:DDL 更改不会自动复制。对同步集群应用 create table 和 alter table 命令是使用者的责任。
    • 未来:允许安全执行 DDL 更改,并自动传播更改。
    • 这些事务(尤其是那些不涉及重叠行的的事务)可能不会按照它们在源集群中发生的顺序应用。

连接故障转移

<问题>

  • 问题 1:我们如何避免尝试连接或向故障节点发送请求以及 TCP 超时?

[Spanner]

  • 客户端会自动在副本之间进行故障转移。

[Greenplum]

  • 规划在发生故障时将客户端切换到新主实例的方法,例如通过在 DNS 中更新主地址。
  • 您可以为主要服务器和备用服务器配置一个虚拟 IP 地址,以便当当前主要服务器发生变化时,客户端程序不必切换到不同的网络地址。如果主服务器主机发生故障,那么虚拟 IP 地址可以交换到实际的主服务器。


安全

<问题>

  • Q1: 我们是否需要集中控制可以加入集群的节点?
  • Q2: 我们是否需要加密节点间流量?
  • Q3: 我们是否需要验证节点间连接?

[MySQL 集群]

  • 不做节点间流量加密
    • NDB 集群节点之间的通信不会以任何方式加密或屏蔽。在 NDB 集群内保护传输的唯一方法是在受保护的网络上运行 NDB 集群。如果你打算将 NDB 集群用于 Web 应用程序,则集群绝对应该驻留在防火墙后,而不能位于网络的非军事区 (DMZ) 或其他地方。
    • 集群通信协议本质上不安全,并且集群中节点之间的通信不会使用任何加密或类似的安全措施。由于网络速度和延迟会直接影响集群的效率,因此也不建议对节点之间的网络连接使用 SSL 或其他加密,因为此类方案实际上会降低通信速度。
  • 不使用任何身份验证来控制 API 节点对 NDB 集群的访问。与加密一样,强制实施身份验证要求的开销将对集群性能产生不利影响。
  • DBA 可以通过在主机的 config.ini 中创建插槽来控制哪些节点可以加入该集群。
    • 通过使用其主机名或 IP 地址创建 [mysqld] 或 [api] 部分来限制 SQL 节点
    • 通过创建一个空插槽(不指定主机名或 IP 地址的 [mysqld] 或 [api] 部分)来允许任何 SQL 节点
  • 用户名和权限
    • 访问同一 NDB 集群的不同 MySQL 服务器之间的 MySQL 用户帐户和权限通常不会自动传播。MySQL NDB 集群使用 NDB_STORED_USER 权限提供对共享和同步用户及权限的支持;
    • 授予 NDB_STORED_USER 权限的语句(例如 GRANT NDB_STORED_USER ON *.* TO 'cluster_app_user'@'localhost')会指示 NDB 使用以下查询创建快照:SHOW CREATE USER cluster_app_user@localhost 和 SHOW GRANTS FOR cluster_app_user@localhost,然后将结果存储在 ndb_sql_metadata 中。然后要求任何其他 SQL 节点读取和应用该快照。每当 MySQL 服务器启动并作为 SQL 节点加入集群时,它都会执行这些存储的 CREATE USER 和 GRANT 语句作为集群架构同步过程的一部分。
    • 如果来自多个 SQL 节点中的多个 GRANT、REVOKE 或其他用户管理语句导致用户在不同 SQL 节点的权限分散,则可以通过对权限已知正确的 SQL 节点上为此用户发出 GRANT NDB_STORED_USER 来解决此问题;这会导致生成权限的新快照并将其同步到其他 SQL 节点。

[CockroachDB]

  • 你可以运行安全的 CockroachDB 集群,也可以运行不安全的集群。
    • 如果安全,客户端/节点和节点间通信将被加密,并且 SSL 证书将对客户端和节点的身份进行验证。
    • 如果不安全,则没有加密或验证。

[YugabyteDB]

  • TLS 加密确保服务器之间的网络通信是安全的。您可以将 YugabyteDB 配置为使用 TLS 加密群集内和客户端到服务器的网络通信。

[Greenplum]

  • 主实例的 pg_hba.conf 文件控制着客户端对 Greenplum 系统的访问和验证。
  • 从属也具有 pg_hba.conf 文件,但这些文件已经正确配置,仅允许来自主机的客户端连接。从属从不接受外部客户端连接,因此无需更改从属上的 pg_hba.conf 文件。

[Citus]

  • 群集中不同节点之间的流量对新安装进行加密。这是通过使用带自签名证书的 TLS 完成的。这意味着这无法防止中间人攻击。这只能防止网络上的被动窃听。
  • 当 Citus 节点相互通信时,它们会咨询 GUC 以获取连接参数,而在 Citus 企业版中,则咨询具有连接凭据的表。这使得数据库管理员能够灵活地调整安全性及效率方面的参数。


应用程序

工作负载路由

<问题>

  • 问 1:根据在连接、事务或数据访问请求期间指定的某些数据,我们如何将连接路由到具有必要数据的节点?
  • 问 2:我们是否将只读连接路由到只读副本?
  • 问 3:应使用哪种信息来路由连接或事务请求,例如服务器负载、节点容量、位置(区域、地区、机架)?
  • 问 4:我们需要中间路由器软件吗?

[Oracle]

  • 多碎片查询和未指定分片键的查询通过多碎片查询协调器路由,该协调器充当请求数据的应用程序的代理。多碎片查询协调器(即“协调器”)在分片目录或其副本上运行。
  • 直接路由到分片
    • Oracle 客户端和连接池能够识别在高性能数据相关路由的连接字符串中指定的分片键。连接层中的分片路由缓存用于将数据库请求直接路由到驻留数据的分片。
    • 分片拓扑缓存是分片键范围到分片之间的映射。Oracle 集成的连接池在它们的内存中维护此分片拓扑缓存。首次连接到给定分片时(在池初始化期间或池连接到较新的分片时),从分片收集分片键范围映射,以动态构建分片拓扑缓存。
    • 缓存分片拓扑为分片创建了一条快速路径,并加快了创建到分片的连接的过程。使用分片键发出连接请求时,连接池将(从其拓扑缓存中)查找存在此特定分片键的相应分片。如果池中提供匹配连接,那么连接池将通过应用其内部连接选择算法返回到分片的连接。
    • 如果池中没有可用的匹配连接,则通过将连接请求连同分片键转发给碎片目录创建新的连接。
    • 一旦初始化池并基于所有碎片构建分片拓扑缓存,分片目录中断不会对直接路由造成影响。
  • 负载均衡
    • 分片目录构建在 Oracle 全局服务管理器 (GSM) 之上。GSM 会根据数据库角色、负载、复制延迟和本地性路由连接。

约束

[Oracle]

  • 分片键必须包含在主键中。

[MySQL 集群]

  • 主键/唯一键
    • 如果用户在创建表时没有定义主键,NDBCLUSTER 存储引擎会自动生成一个隐藏的主键。
  • 外键
    • 与 InnoDB 存储引擎中类似,提供对外键约束的支持。
    • 作为外键引用的每列都需要一个显式唯一键(如果它不是表的唯一键)。
    • 当引用指向父表的唯一键时,不支持 ON UPDATE CASCADE。这是因为对主键的更新作为旧行(包含旧主键)的删除加上新行(采用新主键)的插入来实现的。这对 NDB 内核不可见,它将这两行视为相同,因此无法得知这次更新应当级联。

[Spanner]

  • 主键/唯一键
    • 每个表必须有一个主键,而且该主键可以由该表的零个或多个列组成。
    • 如果你声明一个表是另一个表的子表,则父表的唯一键列必须是子表唯一键的前缀。
  • 外键
    • 当事务提交时,或者当对事务中后续操作可见时,Cloud Spanner 会验证外键约束。
    • 验证会在每条 DML 语句之后立即进行。例如,你必须在插入引用行之前插入被引用行。
    • Cloud Spanner 的表交错对于很多父级-子级关系是不错的选择,其中子表的 primary key 包含父表的 primary key 列。将子行与其父行同置能大幅提高性能。
    • 外键是一种更通用的父级-子级解决方案,并且涵盖更多用例。它们不限于唯一键列,而且,表可以具有多个外键关系(既是某些关系中的父级,又是其他关系中的子级)。
    • 然而,外键关系并不暗示在存储层中表之间存在联合定位。

[CockroachDB]

  • 主键/唯一键
    • 当你没有显式定义主键时,CockroachDB 会自动添加一个隐藏的 rowid 列作为主键。
    • 用于分区的主键与约定主键不同。要定义用于分区的唯一键,使用你希望对表进行分区和子分区的全部列(按希望嵌套子分区的顺序)作为前缀,将主键中唯一标识符添加到这些列。
    • 在主键中定义列的顺序很重要。分区和子分区需要遵循这一顺序。

[YugabyteDB]

  • 不支持排除约束。

[Greenplum]

  • 主键/唯一键
    • 唯一和主键约束必须与其表的分布键和分区键(如果存在)兼容。
    • 表必须以哈希方式分布或复制(不能以随机方式分布)。
    • 如果表以哈希方式分布,则约束列必须与表的分布键列相同(或为其超集)。
    • 如果表有主键,默认情况下,此列(或列组)被选为表的分布键。
    • 请注意,唯一约束(如主键约束)隐式创建一个唯一索引,其中必须包含分布键的所有列和任何分区键。唯一约束在整个表中执行,包括所有表分区(如果存在)。
  • 外键
    • 不受支持。可以声明它们,但不会执行参照完整性。

[Citus]

  • 主键/唯一键
    • 由于分布式系统的性质,Citus 不会在工作节点间交叉引用唯一性约束或参照完整性。
    • 主键和唯一性约束必须包含分布列。将它们添加到非分布列将生成错误。
  • 外键
    • 要在分布式表之间建立外键,请始终在键中包括分布列。这可能涉及使键复合。
    • 在以下情况下可能创建外键
      • 在两个本地(非分布式)表之间
      • 在两个参考表之间
      • 在键包含分布列时,在两个分布式表之间
      • 作为一个分布式表,它引用一个参考表
    • 不支持从参考表到分布式表的外键。

[Postgres-XL]

  • 主键/唯一键
    • 在分布式表中,唯一约束必须包含表的分布列。这是因为 PostgreSQL-XL 目前只允许其推送到数据节点以在本地执行。如果我们在唯一约束中包括分布列,则有理由认为它可以在本地执行。
    • 在复制表中,在唯一约束中没有限制。
    • 在唯一约束中使用表达式时,此表达式必须包含其父表的分布列。它不能使用其他列。
    • 分布列必须包含在主键中。其他限制也适用于主键。
    • 在主键约束中使用表达式时,此表达式必须包含其父表的分布列。它不能使用其他列。
  • 外键
    • 不能在“REFERENCES”子句中省略列名称。
    • 不能为不同的列同时指定主键和“REFERENCES”键。
    • 不能指定多个外键约束。
    • 只有分布列才能具有外键约束。
    • 在分布表 A 和 B 时,其中 A 对 B 有外键,请首先对目标表 B 进行键分布。以错误的顺序执行此操作将导致错误。
    • 如果无法按正确顺序分配,则删除外键、分配表,然后重新创建外键。
  • 不支持排除约束。

序列

<问题>

  • Q1:我们存储序列的位置?
  • Q2:我们是否需要一个节点特定序列,其值不会与其他节点的值重叠?

[Oracle]

  • 分区序列在分区目录中创建,但在每个分区都有一个实例。每个实例都会生成单调递增的数字,这些数字属于一个范围,不会与其他分区中使用的范围重叠。因此,每个生成的数字在全球范围内都是唯一的。
  • 请注意,分区序列生成的数字无法立即用作插入此分区的新行的分片键,因为键值可能属于另一个分区,并且插入会导致错误。要插入新行,应用程序应首先生成分片键的值,然后使用该值连接到适当的分片。在分片目录中使用常规(非分片)序列来生成分片键的新值是一种常见的方法。
  • 如果单个分片键生成器成为瓶颈,则可以将分区序列用于此目的。在这种情况下,应用程序应连接到随机分区(使用全局服务而无需指定分片键),从分区序列中获取唯一键值,然后使用键值连接到适当的分区。

[Spanner]

  • 没有自动增量功能。

[Greenplum]

  • 如果 Greenplum 数据库中启用了镜像,则无法在 UPDATE 或 DELETE 语句中使用 nextval() 函数。
  • 各个分段需要一个“单点信息来源”来获取序列值,以便所有分段都得到正确增量,并且序列以正确的顺序向前移动。序列服务器进程在主机上运行,并且是序列的“单点信息来源”。各个分段在运行时从主机获取序列值。
  • 由于此分布式序列设计,对序列进行操作的函数有一些限制
    • 不支持 lastval() 和 currval() 函数。
    • setval() 只能用于设置主机上序列生成器值,不能在子查询中用于更新分布式表数据中的记录。
    • nextval() 有时会从主机获取一大块值供分段使用,具体取决于查询。因此,如果分段级别的块最终不需要,则有时可能会跳过序列中的值。请注意,常规 PostgreSQL 数据库也会这样做,所以这并非 Greenplum 数据库独有的。

[Citus]

  • Citus MX
    • 自动递增列的类型必须为 bigserial。在集群范围,序列值不会单调递增,因为高 16 位比特保留了工作节点 ID。
    • 通过数据 URL 对哈希分布式表执行写入操作时,如果表中有 bigserial 列,则序列号不再是单调的,而是具有形式 <16 位唯一节点 ID><48 位本地序列号> 以确保唯一性。
    • 协调器节点始终具有节点 ID 0,这意味着它将生成正常顺序数。
    • 分布式表中不能使用小于 bigserial 的序号类型。

视图

<问题>

  • 问 1:物化视图数据存储在哪儿?

[Oracle]

  • 在分片表上创建的物化视图在目录数据库中仍为空,而分片上的对应物化视图则包含来自各个分片的每条数据。

[Citus]

  • 物化视图
    • 将物化视图作为本地表存储在协调器节点上。
    • 物化后在分布式查询中使用它们需要将它们包装在子查询中。

[Postgres-XL]

  • 暂不提供对 TEMPORARY 视图的支持。
  • 物化视图
    • 和普通的视图一样,物化视图是在协调器级别,而不是数据节点级别创建的,并在所有协调器之间复制。当创建物化视图时,原始协调器收集所有行并复制它们。
    • 当刷新物化视图时,原始协调器修正所有行,删除所有现有行,然后复制新行。
    • 如果新行数据来自原始协调器,则使用复制协议处理数据,而不是通过运行查询。

触发器

[Oracle]

  • 不支持触发器。

[Postgres-XL]

  • 不支持触发器。
  • 不支持事件触发器。

索引

[Spanner]

  • 唯一索引
    • 约束由 Cloud Spanner 在事务提交时强制执行。具体来说,任何可能导致针对同一键存在多个索引项的事务都将无法提交。
    • 如果某表最初包含非 UNIQUE 数据,则尝试在此表上创建 UNIQUE 索引将失败。
  • Cloud Spanner 在每个辅助索引中存储以下数据
    • 来自基表的全部键列
    • 索引中包含的全部列
    • 索引定义的可选 STORING 子句中指定的所有列
  • 可以在数据库继续提供服务的同时向现有表添加新的辅助索引。与 Cloud Spanner 中的任何其他架构变动一样,向现有数据库添加索引不需要将数据库置于脱机状态,并且不会锁定整个列或表。

[YugabyteDB]

  • 暂不支持 CREATE INDEX CONCURRENTLY。

[Citus]

  • 支持 CREATE INDEX CONCURRENTLY。

[Postgres-XL]

  • 分布式表上的唯一索引必须包含分布列。对复制表而言,没有此类限制。
  • 不支持 CREATE INDEX CONCURRENTLY。

系统列

<问题>

  • 问 1:哪些系统列是有效的?

oid、tableoid [Postgres-XL]

  • 不在集群之中强制实施 OID 完整性。OID 在每个协调器和数据节点中本地分配。可以在表达式中使用此值,但不要指望整个 XL 群集中的 OID 值相同。
  • ctid 是协调器和数据节点的本地。在 SQL 语句中使用此值不是最佳做法,在使用它更新数据时可能非常危险。

外部数据

<问题>

  • 问 1:我们如何充分利用集群节点以并行访问外部数据?

[Greenplum]

  • 外部表从数据库内部访问外部文件,就好像它们是常规数据库表一样。
  • 使用 gpfdist/gpfdists、pxf 和 s3 协议定义的外部表利用 Greenplum 数据库段的所有资源加载或卸载数据,从而使用 Greenplum 并行。
    • pxf 协议利用 Hadoop 分布式文件系统的并行架构来访问该系统上的文件。
    • s3 协议使用 Amazon Web Services (AWS) 功能。
  • 你可以使用 SELECT、JOIN 或 SORT EXTERNAL TABLE DATA 等 SQL 命令直接并行地查询外部表数据,并且可以为外部表创建视图。
  • 从多个 Greenplum 数据库段实例并行读取外部表数据,以优化大型加载操作
    • PostgreSQL 外部数据封装器仅通过 Greenplum 数据库主服务器连接,不直接访问 Greenplum 数据库段实例。

[Postgres-XL]

  • 不受支持。

查询和数据操作

[Oracle]

  • 协调器仅支持聚合函数 COUNT、SUM、MIN、MAX 和 AVG。

[Citus]

  • Citus 对对数据库集群中的单个节点进行访问的查询提供 100% 的 SQL 支持。
  • 以下查询仅适用于单分片查询
    • SELECT FOR UPDATE:仅支持此功能的哈希分布和引用表,并且仅支持 replication_factor 为 1 的表。
    • TABLESAMPLE
    • 递归 CTE
    • 分组集
  • 仅当相关性位于分布列上并且子查询符合子查询下推规则(例如,按分布列分组,且没有 LIMIT 或 LIMIT OFFSET 子句)时,才支持相关子查询。
  • 聚合函数
    • 支持并行化 PostgreSQL 支持的大多数聚合函数,包括自定义用户定义聚合。聚合使用这三个方法之一执行,按此优先顺序
      1. 当聚合按表的分布列分组时,Citus 可以将整个查询的执行下推到每个工作器。所有聚合在这种情况下都受支持,并在工作器节点上并行执行。(任何使用的自定义聚合都必须安装在工作器上。)
      2. 当聚合不按表的分布列分组时,Citus 仍可以在逐个案例的基础上进行优化。Citus 针对 sum()、avg() 和 count(distinct) 等特定聚合有内部规则,允许其为工作器上的部分聚合重写查询。例如,为了计算平均值,Citus 从每个工作器获取一个总和和一个计数,然后,协调器节点计算最终平均值。
      3. 最后的手段:从各个工作节点那里拉取所有的行,并对协调节点进行聚合。当聚合未被分组于一个分布式列上且不是一个预定义的特殊情况时,Citus 会使用此方法。这会导致网络开销,并且如果要聚合的数据集过大,那么工作节点的资源可能会被耗尽。为了避免意外地将数据拉取到协调节点,您可以设置一个 GUC
        • 设置 citus.coordinator_aggregation_strategy 至“已禁用”;

[Postgres-XL]

  • 以下操作不被允许
    • 修改分布式列值
  • 聚合函数
    • 聚合以两种不同的模式进行工作。
      1. 两阶段聚合 - 当整个聚合都在协调节点上进行时,将使用该聚合。在称为转换阶段的第一阶段,Postgres-XL 会创建一个数据类型为 stype 的临时变量以保存聚合的当前内部状态。对于每个输入行,它会计算聚合参数值,并通过当前状态值和新的参数值调用状态转换函数,以计算新的内部状态值。在处理完所有行后,它会在第二阶段或完成阶段调用最终函数一次,以计算聚合的返回值。如果没有最终函数,那么它会原样返回最终状态值。
      2. 三阶段聚合 - 当聚合进程在协调节点和数据节点之间进行划分时,将使用该聚合。在此模式中,参与查询的每个 Postgres-XL 数据节点都会执行称为转换阶段的第一阶段。此阶段类似于上述两阶段聚合模式的第一阶段,但每个数据节点都会在数据节点上可用的行上应用此阶段。然后将转换阶段的结果传输给协调节点。第二阶段被称为收集阶段,在协调节点上进行。Postgres-XL 协调节点创建一个数据类型为 stype 的临时变量以保存收集阶段的当前内部状态。对于从数据节点的每个输入(该节点上的转换阶段的结果),它会使用当前收集状态值和新的转换值(从数据节点获取)调用收集函数,以计算新的内部收集状态值。
    • 在处理完来自数据节点的所有转换值后,它会在第三阶段或完成阶段调用最终函数一次,以计算聚合的返回值。如果没有最终函数,那么它会原样返回最终收集状态值。
    • Postgres-XL 规划器会在规划时从上述两种方法中选择成本较低且可行的。
  • SELECT INTO 根据默认分布(即对具有可被分布的类型的第一个列执行 HASH)对所有节点的新创建表的分布式数据进行分配。如果没有找到任何列,则会通过 ROUNDROBIN 执行分布。

游标

[Postgres-XL]

  • 不支持 WHERE CURRENT OF 子句。
  • 不支持 LAST 和 BACKWARD。

事务

<问题>

[Oracle]

  • 分片协调程序对所有主分片数据库进行迭代,并调用 UPDATE 语句的远程执行。协调程序启动分布式事务并执行两阶段提交以保证分布式事务的一致性。
  • 对于未决事务,必须手动恢复。
  • Oracle 通过全局一致性读取将读取一致性扩展到多分片操作。
  • 多分片查询必须通过在所有分片跨越最高公共 SCN 发出查询来维持全局读取一致性 (CR)。
  • 你可以使用初始化参数 MULTISHARD_QUERY_DATA_CONSISTENCY 在跨分片执行多分片查询时设置不同的一致性级别。
    • 例如,你可能希望某些查询避免在分片之间进行 SCN 同步的成本,并且这些分片可能在全球范围内分布。
    • 另一个用例是你对复制使用备用服务器,并且多分片查询可以使用略微过时的过时数据,因为可以从主服务器及其备用服务器获取结果。
    • 此参数可以在系统级别或会话级别设置。
    • MULTISHARD_QUERY_DATA_CONSISTENCY = { STRONG | SHARD_LOCAL | DELAYED_STANDBY_ALLOWED }
      • STRONG:使用此设置会在所有分片之间执行 SCN 同步,并且所有分片的数据都是一致的。此设置提供全局一致性读取功能。这是默认值。
      • SHARD_LOCAL:使用此设置不会在所有分片之间执行 SCN 同步。每个分片内的数据是一致的。此设置提供最新数据。
      • 允许延迟的备用:使用此设置,不跨所有分片执行 SCN 同步。数据在每个分片内保持一致。此设置允许尽可能地从数据保护备用数据库中获取数据(例如,根据负载均衡的情况),但可能会从备用数据库中返回过时数据。

[MySQL 集群]

  • 仅支持 READ COMMITTED 事务隔离级别。
  • NDB 以逐行方式实现 READ COMMITTED;当读取请求到达存储该行的 data 节点时,返回的内容是当时该行的最后一个已提交版本。
  • 未提交数据永远不会返回,但当修改多行的交易与读取相同行的交易同时提交时,执行读取的交易可能会观察到值,或者由于给定的行读取请求可以在另一个交易提交之前或之后被处理,因此在这其中这些值或两种值对应于不同的行。
  • 不是 MVCC

[Spanner]

  • Spanner 使用两阶段提交 (2PC) 和严格两阶段锁定来确保隔离和强一致性。
  • 使用 Paxos 进行复制
    • 2PC 被称为“反可用性”协议,因为所有成员必须正常才能工作。Spanner 通过让每个成员成为一个 Paxos 组来缓解这种情况,从而确保即使某些 Paxos 参与者宕机,每个 2PC 成员都具有高可用性。
    • 数据被分成组,这些组成为布局和复制的基本单位。
    • Spanner 中的事务只要所有受影响组都具有仲裁选举出的领导者并且位于分区的一侧就会工作。这意味着一些事务能够完美地工作,而一些事务会超时,但它们始终保持一致性。
    • Spanner 的一个实现属性是,返回的任何读取都是一致的,即使事务稍后中止(由于任何原因,包括超时)。
  • 使用 2PC
    • 对于给定的事务,Spanner 会给它分配 Paxos 分配给代表事务提交的 Paxos 写入的时间戳。
    • 当所有锁都已被获取但任何锁尚未被释放时,可以随时向事务分配时间戳。
    • 当客户端完成了所有读取和缓冲了所有写入后,它会开始两阶段提交。客户端选择一个协调器组,并向每个参与者领导者发送一个提交消息,其中包含协调器的标识和任何缓冲的写入。让客户端驱动两阶段提交避免在广域网链路上两次发送数据。
    • 非协调器参与者领导者首先获取写锁。然后它选择一个准备时间戳,它必须大于它已分配给先前事务的任何时间戳(以保持单调性),并通过 Paxos 记录一个准备记录。然后,每个参与者都会将自己的准备时间戳通知协调器。
    • 协调器领导者也首先获得写锁,但跳过准备阶段。在听到所有其他参与者领导者之后,它为整个事务选择了一个时间戳。提交时间戳 s 必须大于或等于所有准备时间戳,大于协调器收到其提交消息时的 TT.now().latest,并大于领导者分配给先前事务的任何时间戳(再次是为了保持单调性)。
    • 然后,协调器领导者通过 Paxos 记录提交记录(如果在等待其他参与者时超时,则中止)。
    • 在允许任何协调器副本应用提交记录之前,协调器领导者会一直等到 TT.after(s),以便遵守提交等待规则。此等待通常与 Paxos 通信重叠。
    • 提交等待后,协调器将提交时间戳发送给客户端和所有其他参与者领导者。
    • 每个参与者领导者通过 Paxos 记录事务结果。
    • 所有参与者在同一时间戳应用,然后释放锁。
  • 除了正常事务,Spanner 还支持快照读取,这些读取在过去的一个特定时间进行。
    • Spanner 随着时间的推移维护多个版本,每个版本都有一个时间戳,因此可以准确地以正确版本来响应快照读取。
    • 特别是,每个副本都了解它被赶上的时间(肯定),任何副本都可以在该时间之前单方面响应读取(除非它太老了并且已被垃圾回收)。
    • 类似地,可以轻松地(异步地)同时在许多组之间读取。
    • 快照读取根本不需要锁。
  • 只读事务在当前时间(在任何最新的副本上)实现为快照读取。
  • Cloud Spanner 中的读写事务在时间上的单一逻辑点以原子方式执行一组读取和写入。此外,读写事务执行的时间戳匹配时钟时间,而序列化顺序匹配时间戳顺序。
  • 以下是你为包含一系列读取和写入的读写事务获得的隔离属性
    • 该事务中的所有读取都返回来自相同时间戳的数据。
    • 如果一个事务成功提交,那么在读取数据后,没有其他写入者修改了事务中读取的数据。
    • 这些属性甚至适用于没有返回行的读取,以及范围读取返回的行之间的间隙:行不存在被视为数据。
    • 该事务中的所有写入都在同一时间戳提交。
    • 该事务中的所有写入仅在事务提交后才可见。
  • Cloud Spanner 提供可串行化,这意味着所有事务看上去都是以串行顺序执行的。Cloud Spanner 分配提交时间戳来反映已提交事务的顺序以实现此属性。
  • Cloud Spanner 提供比可串行化更强大的保证,称为外部一致性
    • 事务按其提交时间戳中反映的顺序提交,这些提交时间戳反映了真实的时钟时间,因此您可以将其与您的手表进行比较。
    • 事务中读取操作可以看到在事务提交前已提交的所有内容,而所有在事务提交后开始的操作都可以看到写入内容。
  • 读取
    • 强读取操作保证查看在读取操作开始前已提交的所有事务的结果。
    • 此外,由单个读取操作生成的所有行彼此之间都是一致的 - 如果读取操作的任何部分发现了某个事务,则读取操作的所有部分都会看到该事务。
    • Cloud Spanner 为有界陈旧性提供有界类型。有界陈旧性模式允许 Cloud Spanner 选择读取时间戳,但需遵守用户提供的陈旧性界限。Cloud Spanner 会在陈旧性界限内选择最新的时间戳,该时间戳允许在最近可用的副本上执行读取操作,而不会造成阻塞。
    • 有界陈旧读取不可重复:即使两次陈旧读取使用相同的陈旧性界限,它们也会在不同的时间戳执行,因此返回不一致的结果。
    • 有界陈旧读取通常比可比较的精确陈旧读取慢一点。
    • Cloud Spanner 为精确陈旧性提供有界类型。这些时间戳界限在用户指定的时间戳执行读取操作。按时间戳进行读取操作可以保证看到全局事务历史记录中一致的前缀:它们会看到提交时间戳小于或等于读取时间戳的所有事务所做的修改,不会看到提交时间戳更大的事务所做的任何修改。它们将阻塞,直至所有可能分配小于或等于读取时间戳的提交时间戳的冲突事务完成。
    • 时间戳可以表示为绝对 Cloud Spanner 提交时间戳或相对于当前时间的陈旧性。
    • 如果您的实例没有多区域配置,在区域配置中,陈旧读取不会提供任何延迟优势,因此当您的实例没有多区域配置时,您几乎始终应使用强读取。

[CockroachDB]

  • 事务实现了最严格的 ANSI 隔离级别:可串行化。这意味着事务绝不会导致异常。
  • 它通过将 Raft 共识算法(用于写入)与自定义的时间基准同步算法(用于读取)相结合来实现这一点。
    • 存储的数据已使用 MVCC 进行版本控制,因此读取操作只需将自己的范围限制在读取事务开始时可见的数据上。
    • 写入操作使用 Raft 共识算法(一种流行的 Paxos 替代算法)来操作。共识算法保证所有大部分副本在任何时候都同意更新是否已成功提交。在更新(写入)被视为已提交之前,它们必须到达大部分副本(默认情况下为 3 中的 2 个)。
  • 时间戳缓存
    • 为了确保写入事务不会干扰之后开始的读取事务,CockroachDB 还使用时间戳缓存记住数据被当前事务上次读取的时间。时间戳缓存追踪一个给定范围服务过的任何读取操作的最高时间戳(即最近)。
    • BatchRequest 中的每个写入操作检查其自己的时间戳与时间戳缓存以确保写入操作具有更高的时戳;这保证了历史记录永远不会被重写,并且您可以相信读取操作始终服务于最新数据。这是 CockroachDB 用于确保可串行化的关键机制之一。如果写入操作未通过此检查,那么必须以高于时间戳缓存值的时间戳重新启动它。
  • 事务重试
    • 自动重试各个语句(隐式事务)和作为单个批次从客户端发送的事务,前提是为客户端生成的结果大小(包括协议开销)小于 16KiB(默认)。一旦该缓冲区溢出,CockroachDB 便开始将结果流式传输回客户端,此时无法再执行自动重试。
  • 并行提交
  • 对事务时间戳使用 HLC
    • 虽然完全依赖 Raft 共识来维护可串行化是可能的,但这对于读取数据来说效率低下。为了优化读取性能,CockroachDB 实施了混合逻辑时钟 (HLC),它由一个物理组件(始终接近本地墙时)和一个逻辑组件(用于区分具有相同物理组件的事件)组成。这意味着 HLC 时间始终大于或等于墙时。
    • 在事务方面,网关节点使用 HLC 时间为事务选取时间戳。每当提及事务的时间戳时,它都是一个 HLC 值。此时间戳用于追踪值版本(通过多版本并发控制),以及提供我们的事务隔离保证。
    • 当节点向其他节点发送请求时,它们会包含其本地 HLC(包括物理和逻辑组件)生成的时间戳。当节点收到请求时,它们会通知其本地 HLC 发送者随事件提供的时间戳。这有助于保证在节点上读取/写入的所有数据的时间戳都小于下一个 HLC 时间。
    • 然后,这允许主要负责该范围(即租赁持有者)的节点为其存储的数据提供读取服务,方法是确保读取数据的交易在 HLC 时间上大于它读取的 MVCC 值(即读取始终在写入“之后”发生)。
  • 需要时钟同步以保持数据一致性
    • 当一个节点检测到其时钟与集群中至少一半其他节点不同步时,超过允许的最大偏移量的 80%(默认为 500 毫秒),它会立即崩溃。
    • 尽管无论时钟偏移如何,其保持着可序列化一致性,但时钟偏移范围外的偏移会导致因果相关事务之间出现对单键线性一致性的违规。因此,重要的是要通过在每个节点上运行 NTP 或其他时钟同步软件来防止时钟偏离得太远。
    • 要记住的一个罕见情况是,在节点检测到时钟之前,节点时钟突然飞跃到最大偏移之外。虽然极不可能发生这种情况,但可能会发生,例如,在虚拟机中运行 CockroachDB 时,虚拟机管理程序决定将虚拟机迁移到具有不同时间的不同硬件上。在这种情况下,节点时钟不同步和节点自发关机之间可能会有一个很小的时差。在此期间,客户端可能读到旧数据并写出源于旧读数据的写入数据。为了防止这种情况发生,我们建议使用 server.clock.forward_jump_check_enabled 和 server.clock.persist_upper_bound_interval 集群设置。

[Yugabyte]

  • 事务设计基于 Google Spanner 架构。
  • 写入的强一致性通过使用 Raft 共识进行复制以及使用混合逻辑时钟的群集范围分布式 ACID 事务实现。
  • 默认情况下,读取(查询)具有强一致性,但可以动态调整为从跟随者和只读副本中读取。
  • 支持两个事务隔离级别 - SERIALIZABLE(映射到同名 SQL 隔离级别)和 SNAPSHOT(映射到 SQL 隔离级别 REPEATABLE READ)。甚至是 READ COMMITTED 和 READ UNCOMMITTED 隔离级别也会映射到快照隔离。
  • 为了支持这两个隔离级别,锁管理器在内部支持三种类型的锁
    1. 快照隔离写入锁:快照隔离事务在要修改的值上获取此类锁。
    2. 可序列化读取锁:可序列化读改写事务在为了保证在事务提交之前它们不会被修改而要读取的值上获取此类锁。
    3. 可序列化写入锁:可序列化事务在其写入的值上获取此类锁,纯写入快照隔离事务也获取此类锁。因此,多个写入相同项的快照隔离事务可以并行进行。
  • 正当 YugabyteDB 将由单片区 ACID 事务编写的数值存储到 DocDB 中时,它需要以类似的持久数据结构来存储由分布式事务编写的未提交数值。然而,我们不能仅仅将它们作为普通数值写入 DocDB,因为它们随后在不同平板服务器上读取时对客户端会以不同时间可见,允许客户端查看部分应用的事务,从而打破原子性。因此,YugabyteDB 会向负责事务尝试修改的关键数据的所有平板写入暂行记录。我们称之为“暂行”而非“普通”(“永久”)记录,因为它们对于在事务提交前进行读取的用户不可见。

[Azure Synapse]

  • 无分布式事务
  • 不允许嵌套事务
  • 事务支持的隔离级别默认设置为未提交读。
  • 连接主数据库时,通过启用用户数据库的 READ_COMMITTED_SNAPSHOT 数据库选项,可以将其更改为提交快照隔离读取。

[Greenplum]

  • 可串行化快照隔离 (SSI) 不可行。
  • 未提交读和已提交读的行为类似于标准已提交读。
  • 可重复读和可串行化的行为类似于可重复读。
  • XID 是数据库的属性。每个片段数据库都有自己的 XID 序列,无法与其他片段数据库的 XID 相比较。
  • 主使用一个名为 gp_session_id 的集群范围会话 ID 编号,与片段协同分布式事务。片段维护分布式事务 ID 与其本地 XID 的映射关系。
  • 主使用两阶段提交协议来协同所有片段中的分布式事务。

[Citus]

  • 片区间没有快照隔离的概念,这意味着与 COPY 同时运行的多片区 SELECT 可能会看到它在部分片区已提交,但在其他片区尚未提交。
  • 更新/删除影响了多个片区时,Citus 默认使用单阶段提交协议。要获得更大的安全性,可以通过设置启用两阶段提交
    • SET citus.multi_shard_commit_protocol = '2pc';

[Postgres-XL]

  • 隔离级别已串行化自动以静默方式转换为可重复读。

<参考文献>

子事务和保存点

[MySQL 集群]

  • 忽略保存点和回滚到保存点。
  • 没有部分事务,也没有事务的部分回滚。重复键或类似的错误会导致整个事务回滚。

[CockroachDB]

  • 使用 SAVEPOINT 支持嵌套事务。

[YugabyteDB]

  • 不支持保存点。

[Azure Synapse]

  • 不允许保存点。

[Postgres-XL]

  • 未支持 SAVEPOINT。

  • 我们希望避免一个中心节点承担锁管理的繁重任务。

[MySQL 集群]

  • 没有分布式表锁。
    • LOCK TABLES 仅适用于发出锁定的 SQL 节点,集群中的其他 SQL 节点无法识别该锁。
    • 对于作为其操作部分而锁定表的任何语句发出的锁定,也是如此。
  • 在运行多个 MySQL 服务器(SQL 节点)时,ALTER TABLE 不会完全锁定。

[Greenplum]

  • 对于堆表上的 UPDATE、DELETE 和 SELECT...FOR UPDATE 操作,Greenplum Database 默认获取更严格的 EXCLUSIVE 锁(而不是 PostgreSQL 中的 ROW EXCLUSIVE)。当启用全局死锁探测器时,堆表上的 UPDATE 和 DELETE 操作的锁模式为 ROW EXCLUSIVE。
  • Greenplum 始终对 SELECT...FOR UPDATE 语句保持表级锁。
  • Greenplum Database 全局死锁探测器后台工作程序进程收集所有段上的锁信息,并使用有向算法来检测本地和全局死锁是否存在。该算法允许 Greenplum Database 放宽堆表上的并发更新和删除限制。
  • 默认情况下,全局死锁探测器处于禁用状态,Greenplum Database 顺序执行堆表上的并发更新和删除操作。可以通过设置服务器配置参数 gp_enable_global_deadlock_detector 来启用这些并发更新,让全局死锁探测器确定死锁是否存在。
  • 启用全局死锁探测器后,启动 Greenplum Database 时,会在主主机上自动启动后台工作程序进程。可以通过 gp_global_deadlock_detector_period 服务器配置参数配置全局死锁探测器收集和分析锁等待数据的时间间隔。
  • 如果全局死锁探测器确定存在死锁,它会通过取消与涉及的最年轻事务相关的一个或多个后端进程来打破死锁。
  • 要查看所有段的锁等待信息,请运行 gp_dist_wait_status() 用户定义函数。您可以使用此函数的输出确定哪些事务正在等待锁,哪些事务正在持有锁,锁的类型和模式,等待者和持有者会话标识符,以及哪些段正在执行这些事务。

[Spanner]

  • Cloud Spanner 使用标准的“伤后等待”算法来处理死锁检测。
    • 在后台,Cloud Spanner 会跟踪请求冲突锁的每笔事务的创建时间。
    • 它还允许较早的事务取消较晚的事务(“较早”是指事务最早的读取、查询或提交发生得较早)。

[Citus]

  • 为了处理跨越多个节点的死锁,Citus 添加了一个新的分布式死锁探测器。此死锁探测器在 Postgres 扩展框架中作为后台工作程序进程运行。
  • 当客户端向 Citus 发送事务时,协调器将事务发送到相关的工作节点。但是,在发送事务之前,协调器还会调用函数 SELECT assign_distributed_transaction_id(); 该调用确保工作节点上的本地事务与协调器上的分布式事务相关联。
  • 为了检测分布式死锁,Citus 需要持续监控所有节点是否有哪些进程等待锁超过了可忽略的时间(例如 1 秒)。当出现这种情况时,我们从所有节点收集锁表,并构建一个有向图,表示等待彼此的所有进程跨所有节点的情况。如果这个图中存在一个循环,则存在分布式死锁。为了结束死锁,我们需要主动终止进程或取消事务,直到这个循环消失。

[Postgres-XL]

  • 无法检测到涉及多个节点(协调器和/或数据节点)的全局死锁。为了解决这个问题,建议设置 statement_timeout,以便在正常的处理环境中导致这些语句失败。
  • 咨询锁是每个协调器或数据节点本地的。如果您希望在不同的协调器上获取咨询锁,则应该使用 EXECUTE DIRECT 语句手动执行此操作。

过程和函数

<问题>

  • Q1:我们应该关注过程和函数执行的哪些方面?该执行是否会被推送到远程节点?

[Spanner]

  • 不允许用户创建函数或过程。

[CockroachDB]

  • 不允许用户创建函数或过程。

[YugabyteDB]

  • 默认情况下支持 SQL、PL/pgSQL 以及 C 函数和过程。

[Greenplum]

  • 有限地使用 VOLATILE 和 STABLE 函数:为了防止 Greenplum Database 中不同片段之间的数据不同步,任何被归类为 STABLE 或 VOLATILE 的函数如果包含 SQL 或以任何方式修改数据库,则无法在片段级别执行。例如,诸如 random() 或 timeofday() 之类的函数不允许在 Greenplum Database 中分布式数据上执行,因为它们可能会导致片段实例之间的数据不一致。
  • 为了确保数据一致性,VOLATILE 和 STABLE 函数可以在主服务器上进行评估和执行的语句中安全地使用。如果一个语句包含一个带有分布式表的 FROM 子句,且 FROM 子句中使用的函数仅仅返回一组行,则可以在片段上允许执行。
  • 无法从任何类型的函数中返回 refcursor。
  • 具有 EXECUTE ON MASTER 特性的函数仅在主片段上执行,而具有 EXECUTE ON ALL SEGMENTS 特性的函数在所有主要片段实例(而非主实例)上执行。
  • 具有 EXECUTE ON ANY(默认)的函数表示可以在主服务器或任何片段实例上执行该函数,并且无论在何处执行,它都返回相同的结果。Greenplum Database 确定函数在何处执行。
  • 函数和复制表:仅对复制表执行 SELECT 命令的用户自定义函数可以在片段上运行。让函数在片段中读取它们是安全的,但是对复制表的更新必须在主实例上执行。
  • 用户创建的函数的共享库文件必须驻留在 Greenplum 数据库阵列(主段、段段、镜像段)中每个主机的相同库路径位置中。

[Postgres-XL]

  • PL/pgSQL 函数中只能处理一个 SQL 语句。
  • 在 PL/pgSQL 中,暂不支持 SELECT INTO 命令。
  • 强烈建议不要在 SQL 函数中使用 VARIADIC。它尚未经过充分审查,可能会返回错误的结果。
  • PostgreSQL-XL 函数的使用目前需要非常小心,否则可能发生意外结果,并且您的数据可能会处于不一致状态。此行为可能会在未来版本中更改以使其更安全。
    • 在没有 FROM 子句的情况下执行诸如 SELECT my_function(1,2);的调用将在本地协调器上执行,并可能涉及其他数据节点并按预期执行,由协调器驱动。
    • 诸如 SELECT col1, my_table_function(col2) FROM mytable 的调用将被下推到所涉及的数据节点。如果 my_table_function 碰巧执行 SELECT,则它只会从该节点的本地数据中执行。
    • 同样,如果它执行 UPDATE,它将仅更新该节点的本地数据。例如,如果 UPDATE 写入复制表,这意味着表将不同步。

各种限制

[MySQL 集群]

  • MySQL 集群不支持
    • 全文索引
    • 临时表

[Postgres-XL]

  • DELETE:不支持 with_query。
  • PostgreSQL-XL 不支持大型对象。PostgreSQL-XL 无法提供一致的方法来处理大型对象,因为 OID 在集群节点之间不一致。
  • 目前不支持 NOTIFY、LISTEN 和 UNLISTEN 命令。


数据库管理

先决条件

<问题>

  • Q1:我们是否要求或推荐准备 SSH 以启用群集范围的操作,例如启动和停止群集?
  • Q2:我们对使用 NTP 在群集节点之间进行时间同步怎么说?

[CockroachDB]

  • 很有必要通过在每个节点上运行 NTP 或其他时钟同步软件来防止时钟漂移得太远。
  • 集群中的所有节点必须同步到相同的时间源,或同步到以相同方式实现 leap second smearing 的不同来源。

[YugabyteDB]

  • 使用 ntp 在机器之间同步时间。
  • 任何节点上的最大时钟漂移应限制在不超过 500 PPM(或百万分之一)。这意味着任何节点上的时钟每秒最多只能漂移 0.5 毫秒。请注意,0.5 毫秒每秒是 Linux 中时钟漂移的标准假设。

[Greenplum]

  • 无密码的 SSH:每个 Greenplum 主机上的 gpadmin 用户必须能够从群集中的任何主机到群集中的任何其他主机 SSH,而无需输入密码或密码短语。

部署

<问题>

  • Q1:我们对节点自主性有什么看法?我们是否需要允许具有现有数据的节点形成一个新集群?离开集群的节点是否可以继续独立运行?
  • Q2:我们对集群节点的处理能力有什么看法?我们是否应该建议所有节点具有相同的容量?
  • Q3:集群的所有节点是否都具有相同的数据库字符集和语言环境设置?WAL 段大小和块大小等其他设置如何?
  • Q4:我们是否允许在集群中混合使用不同的 DBMS 版本,以便用户可以执行在线滚动升级?
  • Q5:我们是否允许或建议使用共享存储为所有集群节点存储数据?
  • 集群中的所有节点必须
    • 具有相同的计算机体系结构(64 位、字节序):这样可以通过简单地移动文件而允许在节点之间快速移动分片。
    • 使用相同的操作系统版本:这是为了防止由不同的 glibc 或 ICU 版本引起的不一致的查询结果。

[Oracle]

  • 所有节点必须具有相同的操作系统和版本的 Oracle。
  • 它们不必具有相同的容量。这可以节省资本支出,因为这允许客户购买具有最新硬件配置的服务器,并与现有服务器一起使用。
  • 数据库字符集和国家字符集必须相同,因为所有分片数据库都使用它。这意味着所选择的字符集必须包含将被插入到分片目录或任何分片中所有可能的字符。

[MySQL 集群]

  • 可以在一个 NDB 集群中混合使用不同种类的硬件和操作系统,只要所有机器和操作系统都具有相同的字节序(全部是大端序或全部是小端序)。
  • 还可以在不同节点上使用不同 NDB 集群版本的软件。但是,我们仅将此类使用支持作为滚动升级过程的一部分。
  • NDB 集群目前在设计上旨在使数据节点在处理能力、内存空间和带宽方面保持同质性。
  • 同样值得注意的是,所有数据节点都应该具有相同数量的 RAM,因为集群中的任何数据节点都不能使用超过可供任何个别数据节点使用的最少内存。例如,如果四台计算机承载集群数据节点,其中三台有 3GB 的 RAM 可用于存储集群数据,而剩余的数据节点只有 1GB 的 RAM,那么每个数据节点最多可以分配 1GB 给 NDB 集群数据和索引。

[Greenplum]

  • Greenplum 数据库的性能将与阵列中最慢的段服务器一样快。因此,建议 Greenplum 数据库阵列中的所有段主机都具有相同的硬件资源和配置。

初始化集群

<问题>

  • Q1:创建准备好启动的集群的过程是什么?
  • Q2:如何指定初始集群节点,命令行选项、配置文件或 SQL 语句?

[Oracle]

  • 分片数据库管理员定义拓扑(区域、分片主机、复制技术),并使用 GDSCTL 命令行界面在声明性规范中调用 DEPLOY 命令。
    1. 创建将成为分片目录的数据库以及任何所需的副本,用于灾难恢复 (DR) 和高可用性 (HA)。
    2. 创建将成为配置中的分片的数据库,包括 DR 和 HA 所需的任何备用数据库。
    3. 使用 GDSCTL 命令行实用程序中的部分或所有下列命令指定分片拓扑:CREATE SHARDCATALOG、ADD GSM、START GSM、ADD SHARDSPACE、ADD SHARDGROUP、ADD SHARD、ADD INVITEDNODE
    4. 运行 DEPLOY 来部署分片拓扑配置。
    5. 添加访问分片式数据库中任何分片的所需的全局服务。
  • 该过程很复杂。有关详细信息,请参阅 分片式数据库部署
  • 提供 Terraform、Kubernetes 和 Ansible 脚本来自动化和简化分片式数据库部署操作。

[MySQL 集群]

  1. 在每个数据节点和 SQL 节点上,创建一个 my.cnf 文件,其中包含一个连接字符串,该字符串告诉节点从哪里查找管理节点。
  2. 在管理节点上,创建一个 config.ini 文件,告诉它维护多少个副本、为每个数据节点上的数据和索引分配多少内存、从哪里查找数据节点、在每个数据节点上的磁盘上保存数据的位置以及从哪里查找 SQL 节点的位置。
  3. 启动集群。

[CockroachDB]

  • 运行 cockroach start 启动初始节点,然后运行 cockroach init 对集群执行一次性初始化。

$ cockroach start \ --certs-dir=certs \ --advertise-addr=<node1 address> \ --join=<node1 address>,<node2 address>,<node3 address> \ --cache=.25 \ --max-sql-memory=.25 \ --background $ cockroach init --certs-dir=certs \ --host=<address of any node> 

[YugabyteDB]

  • 没有初始化。启动 YB-Master 会初始化集群。

[Greenplum]

    1. 在主节点和段主机上创建数据目录。
    2. 运行 gpinitsystem。 gpinitsystem 根据用户提供的集群配置文件创建主主实例、备用主实例以及主段和镜像段实例。它内部使用 SSH 和 initdb。每个段实例都将并行设置。
      • $ gpinitsystem -c gpconfigs/gpinitsystem_config -h gpconfigs/hostfile_gpinitsystem -s standby_master_hostname -S
    3. 最佳做法是配置 Greenplum 数据库和主机系统以使用已知的、受支持的时区。设置 Greenplum 数据库时区可防止 Greenplum 数据库在每次重启集群时选择时区,并设置 Greenplum 数据库主实例和段实例的时区。
      • $ gpconfig -c TimeZone -v 'US/Pacific'

[Citus]

  1. 在每个协调器和工作器节点上,执行以下操作
    1. 运行 initdb。
    2. 将“citus”添加到 shared_preload_libraries 参数。
    3. 启动实例并运行“CREATE EXTENSION citus;”。
  2. 在协调器上,运行 UDF 以将工作器节点信息添加到 pg_dist_node 目录表。
    • SELECT * from master_add_node('worker-101', 5432);

[Postgres-XL]

  • 手动初始化步骤如下。 pgxc_ctl 命令通过 ssh 远程节点和执行必要的步骤简化了这些任务。
  1. 在每个协调器和数据节点上创建数据库集群。
    • $ initdb -D /usr/local/pgsql/data --nodename foo
  2. 在不同的节点上创建 GTM 主服务器和 GTM 从服务器。
    • $ initgtm -Z gtm -D /usr/local/pgsql/data_gtm
  3. 在每个协调服务器和数据节顶上创建 GTM 代理。
    • $ initgtm -Z gtm_proxy -D /usr/local/pgsql/data_gtm_proxy
  4. 在数据节顶的数据目录中,在 postgresql.conf 中设置以下参数。
    • max_connections、max_prepared_transactions
    • pgxc_node_name
    • gtm_host、gtm_port
  5. 在协调服务器的数据目录中,在 postgresql.conf 中设置以下参数。
    • max_prepared_transactions
    • pgxc_node_name
    • gtm_host、gtm_port
    • pooler_port、max_pool_size、min_pool_size
    • max_coordinators、max_datanodes

启动/停止数据库实例

<问题>

  • 问 1:我们可以使用什么代替 SSH 来替代 Windows?
  • 提供一个使用一个命令启动并关闭整个集群的命令。它在内部使用 SSH 在远程节点上运行命令。

[Oracle]

  • 启动过程为
    1. 启动分片目录数据库和本地侦听器。
    2. 启动分片管理器(GSM)。
    3. 启动分片数据库和本地侦听器。
    4. 启动全局服务。
    5. 启动连接池和客户端。
  • 关闭过程为逆序。

[MySQL 集群]

  • 要启动集群
    1. 在管理主机上,运行“ndb_mgmd -f /var/lib/mysql-cluster/config.ini”以启动管理节点。
    2. 在每个数据节点主机上,运行“ndbd”以启动数据节点。
    3. 在每个 SQL 主机上,运行“mysqld_safe &”以启动 MySQL 服务器。
  • 要停止集群
    1. 在管理主机上,运行“ndb_mgm -e shutdown”以优雅地关闭管理节点和数据节点。
    2. 可以使用 mysqladmin shutdown 及其他方式关闭任何 SQL 节点。

[CockroachDB]

  • 通过运行“cockroach start”,为集群中的所有初始节点启动 --join 标志来启动节点,这样该进程就会知道它可以通信的所有其他机器。

$ cockroach start \ --certs-dir=certs \ --advertise-addr=<node1 address> \ --join=<node1 address>,<node2 address>,<node3 address> \ --cache=.25 \ --max-sql-memory=.25 \ --background 

要停止节点,向服务器进程发送 SIGTERM。

[YugabyteDB]

  • 在与副本因子一样多的节点上启动 YB 主服务器(此处为 3 个)。在启动每个 YB 主服务器时,指定所有 YB 主服务器的地址及其自己的侦听地址。

$ ./bin/yb-master \ --master_addresses 172.151.17.130:7100,172.151.17.220:7100,172.151.17.140:7100 \ --rpc_bind_addresses 172.151.17.130:7100 \ --fs_data_dirs "/home/centos/disk1,/home/centos/disk2" \ --placement_cloud aws \ --placement_region us-west \ --placement_zone us-west-2a \ 

在多于副本因子的节点上启动 YB-TServer。在启动每个 YB-TServer 时,指定所有 YB 主服务器的地址、其用于互连通信的自己的侦听地址以及用于 PostgreSQL 客户端的侦听地址。

$ ./bin/yb-tserver \ --tserver_master_addrs 172.151.17.130:7100,172.151.17.220:7100,172.151.17.140:7100 \ --rpc_bind_addresses 172.151.17.130:9100 \ --start_pgsql_proxy \ --pgsql_proxy_bind_address 172.151.17.130:5433 \ --fs_data_dirs "/home/centos/disk1,/home/centos/disk2" \ --placement_cloud aws \ --placement_region us-west \ --placement_zone us-west-2a \ 

[Greenplum]

  • gpstart 实用工具用于在主实例上并行启动主实例和所有片段实例。
  • gpstop 会停止系统中的所有 postgres 进程,包括主实例和所有片段实例。gpstop 实用工具使用最多 64 个并行工作线程的默认值,以关闭构成 Greenplum 数据库集群的 Postgres 实例。

[Citus]

  • 使用 pg_ctl 启动和停止每个协调器和工作进程,就像香草 PostgreSQL 一样。

[Postgres-XL] 按 GTM、GTM-Proxy、数据节点和协调器的顺序启动集群。

  1. $ gtm_ctl -Z gtm start -D /usr/local/pgsql/data_gtm
  2. $ gtm_ctl start -Z gtm_proxy -D /usr/local/pgsql/data_gtm_proxy
  3. $ postgres --datanode -D /usr/local/pgsql/data
  4. $ postgres --coordinator -D /usr/local/pgsql/coorddata

也可以使用“pg_ctl start -Z {coordinator | datanode}”来启动协调器和数据节点。

按协调器、数据节点、GTM-Proxy 和 GTM 的顺序停止集群。

  1. $ pg_ctl stop -Z coordinator -D /usr/local/pgsql/coorddata
  2. $ pg_ctl stop -Z datanode -D /usr/local/pgsql/data
  3. $ gtm_ctl stop -Z gtm_proxy -D /usr/local/pgsql/data_gtm_proxy
  4. $ gtm_ctl -Z gtm stop -D /usr/local/pgsql/data_gtm

pgxc_ctl 命令可以使用一个命令启动和停止所有组件。它使用 ssh 在远程节点上运行必要的命令。

服务器配置

<问题>

  • Q1:在所有数据库实例上都应将哪些参数设置为相同的值?我们如何保证这一点?
  • Q2:我们是否应该有一个机制来集中管理参数设置,并将它们分配给集群成员?
    • 管理服务器存储配置文件,并在集群成员加入集群或
    • 提供修改所有节点上的配置文件的命令和/或 ALTER SYSTEM。
  • Q3:我们如何在所有节点上在线修改参数设置?(pg_ctl reload 和 pg_reload_conf() 的集群范围版本)
  • SHOW 和/或 pg_settings 显示特定数据库实例或所有数据库实例的参数值。

[Oracle]

  • 当您在分片目录中配置系统参数设置时,它们会自动传播到分片数据库的所有分片。系统参数的传播只在分片目录上在 ENABLE SHARD DDL 下进行时才会发生,然后在 ALTER 语句中包含 SHARD=ALL。

alter session enable shard ddl; alter system set enable_ddl_logging=true shard=all; 

[MySQL 集群]

  • 管理服务器管理集群配置文件。集群中的每个节点从管理服务器中检索配置数据,因此需要一种方法来确定管理服务器的位置。

[CockroachDB]

  • 集群设置适用于 CockroachDB 集群的所有节点,例如,控制是否与 Cockroach Labs 共享诊断详细信息,以及用于调试和集群调优的高级选项。在集群启动后,只能由属于根用户的 admin 角色的成员随时更新这些设置。
    • SET CLUSTER SETTING sql.defaults.distsql = 1;
  • 更改集群设置不是瞬时的,因为该更改必须传播到集群中的其他节点。
  • 可以显示集群范围内的设置。
    • SHOW CLUSTER SETTING <setting>;
    • SHOW CLUSTER SETTINGS;

[YugabyteDB]

  • 虽然可以设置、显示和重置参数的值,但目前尚不支持该效果。目前将使用默认设置和行为。

[Greenplum]

  • 主实例和每个分段实例都有自己的 postgresql.conf 文件。有些参数是本地的:每个分段实例检查其 postgresql.conf 文件以获取该参数的值。在主实例和每个分段实例上设置本地参数。
  • 其他参数是主参数,您在主实例上设置它们。该值在查询运行时传递给(或在某些情况下被)分段实例,或被它们忽略。
  • 要跨多个分段更改本地配置参数,请在每个目标分段(主分段和镜像分段)的 postgresql.conf 文件中更新参数。使用 gpconfig 实用程序在所有 Greenplum postgresql.conf 文件中设置参数。
    • $ gpconfig -c gp_vmem_protect_limit -v 4096
  • SHOW 仅列出主实例的设置。要查看整个系统(主实例和所有分段)中特定参数的值,请使用 gpconfig 实用程序。
    • $ gpconfig --show max_connections

[Postgres-XL]

  • 仅显示客户端已连接到的节点的本地设置。

扩展集群

<问题>

  • 问 1:如何指定集群节点,命令行选项、配置文件或 SQL 语句?
  • 问 2:添加或删除节点是否应始终需要数据重新分配,或者将它们分开,并允许将新节点保留空闲状态?
  • 问 3:我们如何实现自动扩展?什么触发自动扩展(数据量、服务器负载,...)?
  • 节点应该能够在线添加和删除。
  • 添加和删除节点不应影响访问其他节点的应用程序。

[Oracle]

  • 向分片数据库添加分片时,如果环境通过一致哈希进行分片,那么现有分片中的数据块会自动移至新分片,以重新平衡分片环境。自动重新分片是系统管理的分片方法的一项特性,该特性提供了分片数据库的弹性可扩展性。
  • 在使用自定义分片时,使用数据填充新分片可能需要使用 GDSCTL 分割分块和移动分块命令,将现有分片中的分块手动移动到新分片。
  • 在向环境中添加分片时,验证备用服务器是否就绪,在新分片就位后备份所有参与移动分块操作的分片。

[MySQL 集群]

  • 可以进行在线扩展(增加节点以增加容量和性能)。
  • 在添加新数据节点之前就已存在的 NDBCLUSTER 表的重新分发不会自动进行,但可以使用 mysql 或其他 MySQL 客户端应用程序中的简单 SQL 语句来完成。但是,在添加新节点组后创建的表中添加的所有数据和索引都会自动分配给所有集群数据节点,包括作为新节点组一部分添加的数据和索引。
  • 目前,您必须作为新节点组的一部分将新数据节点添加到 NDB Cluster 中。此外,无法在线更改副本数(或每个节点组的节点数)。
  • 可以添加新的节点组而不启动所有新的数据节点。还可以向已降级的集群添加新的节点组——即仅部分启动的集群或未运行一个或多个数据节点的集群。在后一种情况下,在添加新的节点组之前,集群必须具有足够的正在运行的节点才可用。
  • 创建或添加新的节点组或通过表重新组织并不会阻止使用 NDB Cluster 数据执行正常的 DML 操作。
  • 无法与表重组同时执行 DDL。也就是说,在执行 ALTER TABLE ... REORGANIZE PARTITION 语句期间无法发布任何其他 DDL 语句。
  • 在执行 ALTER TABLE ... REORGANIZE PARTITION(或执行任何其他 DDL 语句)期间,无法重新启动群集数据节点。
  • 在线添加数据节点需要以下步骤
    1. 编辑群集配置文件 config.ini 文件,添加与要添加的节点相对应的新的 [ndbd] 部分。如果集群使用多个管理服务器,则需要将这些更改应用到管理服务器使用的所有 config.ini 文件中。
    2. 对所有 NDB Cluster 管理服务器执行滚动重启。
    3. 对所有现有 NDB Cluster 数据节点执行滚动重启。
    4. 对连接到 NDB Cluster 的任何 SQL 或 API 节点执行滚动重启。
    5. 启动新的数据节点。可以按照任何顺序启动新的数据节点。也可以同时启动它们,只要在完成所有现有数据节点的滚动重启后并开始执行下一步骤之前启动即可。
    6. 在 NDB 群集管理客户端中执行一条或多条 CREATE NODEGROUP 命令来创建新节点组或新数据节点所属的节点组。
      • ndb_mgm > CREATE NODEGROUP 3,4

[Spanner]

  • Cloud Spanner 通过根据请求负载和数据大小自动分片数据来优化性能。
    • Cloud Spanner 根据负载拆分数据:当它检测到许多分片中的读取或写入负载较高时,会自动添加分片边界。你对数据的拆分方式有些控制权,因为 Cloud Spanner 只能在作为层次结构根目录的表的行(即,不在父表中交错的表)之间划出分片边界。
    • 交错表的行无法从其父表中对应的行中拆分出来,因为交错表中的行按照排序的主键顺序与父表中共享相同主键前缀的行一起存储。
    • 假设你的数据库包含一个表,其中有 10 行比表中的所有其他行读取频率更高。只要该表位于数据库层次结构的根目录(换句话说,它不是交错表),Cloud Spanner 就可以在每一行的之间添加分片边界,以便由不同的服务器处理,而不是让所有读取这些行的操作都消耗单一服务器的资源。

[CockroachDB]

  • 添加容量就像把一个新节点指向正在运行的群集一样简单。CockroachDB 水平扩展,无需重新配置或大规模架构检修。只需向群集中添加一个新节点,CockroachDB 即可处理底层复杂性。
    • 只需向 CockroachDB 群集添加新节点即可实现扩展
    • 自动平衡和分配范围,而不是分片
    • 在所有节点间均匀优化服务器利用率
  • 当你的群集跨越多个节点(物理机、虚拟机或容器)时,新拆分的范围会自动重新平衡到容量较大的节点。CockroachDB 通过对等八卦协议通信来协调重新平衡的机会,通过此协议,节点交换网络地址、存储容量和其他信息。
  • 当一个节点满足以下两个条件时,它就被认为已退役
    1. 该节点已完成退役流程。
    2. 该节点已停止,并且在通过 server.time_until_store_dead 配置的持续时间内(默认 5 分钟)未更新其生存记录。
  • 退役流程将该节点上的所有范围副本传输到其他节点。在此流程期间和之后,该节点被视为“退役中”,并将继续接受新的 SQL 连接。即使没有副本,该节点仍可用作路由连接到相关数据的网关。
  • 在退役节点之前,请确保其他节点可用于接管该节点的范围副本。如果没有任何其他节点可用,则退役流程将无限期地挂起。

[YugabyteDB]

  • 只需指向 YB-Masters 即可启动一个新 YB-TServer。
  • 现有数据将自动重新分布。

[Azure Synapse]

  • 为了执行扩展操作,SQL 池会先关闭所有传入的查询,然后再回滚事务以确保一致的状态。只有在事务回滚完成后才会进行扩展。对于扩展操作,系统会将存储层从计算节点分离,添加计算节点,然后将存储层重新附加到计算层。每个 SQL 池存储为 60 个分布,均匀分布到计算节点。

[Greenplum]

  • 在系统正常运行并可用时可以执行 Greenplum 数据库扩展。
  • 所需时间取决于 Greenplum 系统中的架构对象数量以及与硬件性能相关的其他因素。在大多数环境中,初始化新区段所需脱机时常不足 30 分钟。
  • gpexpand 实用程序分两个阶段执行系统扩展:区段实例初始化和表数据重新分发。
    • $ gpexpand -f /home/gpadmin/new_hosts_file
    • 在初始化阶段,gpexpand 使用指定数据目录、dbid 值和新区段实例的其他特征的输入文件运行。在 postgres 数据库中创建一个名为 gpexpand 的扩展架构,存储扩展操作的状态,包括表的详细信息状态。
    • 在表数据重新分发阶段,gpexpand 会重新分发表数据,以重新平衡旧区段实例和新区段实例中的数据。

[Citus]

  • 通过使用新节点的主机名(或 IP 地址)和端口号调用 master_add_node UDF 添加节点。
    • SELECT * from master_add_node('node_name', 5432);
  • 新节点可用于新建分布式表的碎片。现有碎片将保留在它们所在的位置,除非重新分发,因此在不采取进一步措施的情况下,添加新工作器可能无法帮助提高性能。
  • 它还会将参考表复制到新节点。
  • 为了将现有碎片从旧节点重新平衡到新节点,Citus 提供了一个碎片重新平衡器实用程序。为了最大程度地控制,碎片重新平衡器的运行时间由数据库管理员决定。Citus 不会在创建节点时自动重新平衡。
  • 通过使用要删除的节点的主机名(或 IP 地址)和端口号,调用 master_remove_node UDF 来删除节点。事先必须删除或将碎片移动到其他节点。
    • SELECT * from master_remove_node('node_name', 5432);
[Postgres-XL]
  • 使用 pgxc_ctl 的“add datanode”命令在线添加一个数据节点。
    • PGXC$ add datanode master dn3 localhost 40003 40013 $dataDirRoot/dn_master.3 none none none
    • 在群集重新配置期间,所有未完成的事务都会中止,会话会重置。因此,您通常会看到打开的会话上有以下错误
      • 错误:因用户请求而取消语句<==== pgxc_pool_reload() 会重置所有会话并中止所有打开的事务
    • 现有数据不会自动移动到新数据节点。要重新分发数据,您需要为每个表运行 ALTER TABLE ADD NODE。
  • 使用 pgxc_ctl 的“remove datanode”命令在线删除一个数据节点。
    • 不会采用任何其他检查以确定要删除的数据节点是否来自被复制/分布的表中的数据。用户需负责确保删除数据节点是安全的。
    • ALTER TABLE disttab DELETE NODE (dn3);
    • PGXC$ remove datanode master dn3 clean
  • 通过 pgxc_ctl 的 add/remove coordinator 命令添加/删除协调器。它还会取消所有事务并重置会话,并导致“因用户请求而取消语句”错误。

数据重新分配

<问题>

  • Q1:数据迁移的单位是什么?
  • Q2:用户可以如何识别需要移至其他节点的分片?哪些分片是热点?
  • Q3:如何在节点之间在线快速迁移数据,同时最大程度地降低对应用程序性能的影响?
    • 我们是否可以复制文件(而非记录)?当相关节点使用共享存储时,我们是否可仅重命名文件?
    • 我们是否可以消除每个数据记录的 WAL 发射?
  • Q4:我们是否可以将数据移动和新的目标通知到应用程序,以便自动连接到最佳节点?
  • 允许自动和手动数据移动。

[Oracle]

  • 分片之间的数据迁移单位是分块。分块是一组表空间,用于存储一个表系列中所有表的相应分区。一个分块包含一组相关表中每个表的单个分区。这会确保可共同移动来自不同分片表的相关数据。在创建 SDB 时指定每个分片中的分块数。
  • 可以使用 Oracle Enterprise Manager Cloud Control 来帮助识别适合移动或拆分并移动到新分片的分块。
  • 分片 MOVE CHUNK 命令在内部使用 Oracle Data Pump 来将可传输表空间从一个分片移动到另一个分片。
  • 当发生数据或工作负载倾斜时,可在不更改分片数的情况下,将某个特定分块从一个分片移动到另一个分片。在这种情况下,数据库管理员可以启动分块迁移来消除热点。
  • 使用 RMAN 增量备份、可传输表空间和 Oracle 通知服务技术来最大程度地降低分块迁移对应用程序可用性的影响。分块迁移期间会将分块保持在线状态。在分块中存储的数据可供只读访问的时间有一小段时间(几秒钟)。
  • 支持 FAN 的客户端会在源分片中的分块即将变成只读时收到通知,还会在分块迁移完成后分块在目标分片中完全可用时收到通知。当客户端收到分块只读事件时,他们可以重复连接尝试,直到分块迁移完成,或者在源分块中访问只读分块。在后一种情况下,尝试写入分块会导致运行时错误。
  • 如果某个分片数据库在重新分片时运行多碎片查询可能会导致错误,因此,建议不要在多碎片工作负载期间部署新碎片。
  • 如果碎片只是暂时移除,请跟踪移动到每个碎片的块,以便在维护完成后可轻而易举地识别并将其移回。
  • 不管何时将某个块从一个碎片移至另一个碎片,您都应制作参与操作(即区块移动的源头和区块移动的目标)的数据库的完整备份。
  • Oracle Sharding 支持块的在线拆分。从理论上讲,每个碎片可进行单块处理,并在每次需要数据迁移时拆分它。但是,即使某块拆分不影响数据可用性,拆分也可能花费大量时间和大量 CPU,这是由于拆分扫描了拆分分区的所有行,随后逐一将它们插入新分区。对于复合分片,拆分可能十分耗时,且为分片键或超级分片键重新定义新值可能需要停机。因此,建议您预先在每个碎片上创建多个块,并在块数量不足以在重新分片期间平衡地重新分配数据时或某个特定块成为热点时拆分这些块。

[MySQL 集群]

  • 按照以下步骤在所有数据节点之间重新分配集群数据
    1. 为每个表在 MySQL 客户端中发出 "ALTER TABLE ... ALGORITHM=INPLACE, REORGANIZE PARTITION" 语句。
    2. ALTER TABLE ... REORGANIZE PARTITION ALGORITHM=INPLACE 会对分区进行重新整理,但不会回收在旧节点上释放的空间。为此,您可以为每个表在 MySQL 客户端中发出 OPTIMIZE TABLE 语句。
  • 以“ALTER TABLE ... REORGANIZE PARTITION” 进行重新分配目前不包括唯一索引(仅对有序索引进行重新分配)。

[Spanner]

  • 随着数据量或服务器数量发生变化,Spanner 会跨机器自动重新分片数据,而且会跨机器(甚至跨数据中心)自动迁移数据,以平衡负载并根据故障情况进行相应处理。
  • 如果某个目录变得过大,Spanner 会将其分片为多个碎片。这些碎片可能由不同的 Paxos 组(因此可能是不同的服务器)提供。实际上, movedir 在组之间移动碎片,而不是整个目录。
  • 在 Paxos 组之间移动数据时,会按目录进行移动。
  • Spanner 可能会移动目录,以减少 Paxos 组的负载;将经常一起访问的目录放入同一个组;或移动目录使其更靠近其访问者。
  • 在客户端操作进行期间也可以移动目录。
  • 没有将 movedir 实现为单一事务,以避免在大量数据移动中阻止进行中的读写操作。相反,movedir 会先登记其开始移动数据这一事实,然后在后台移动数据。在其移动了几乎所有数据(名义数量)后,它将使用事务以原子方式移动名义数量的数据,并更新两个 Paxos 组的元数据。
  • 我们预期可以数秒钟内移动 50MB 目录。

[CockroachDB]

  • 分布式事务在重新平衡过程中会继续执行,不会发生停机或产生额外延迟。您甚至可以在群集处于负载状态下,在数据中心或云基础设施提供商之间移动表 - 或整个数据库。

[YugabyteDB]

  • 现有数据片会自动重新分布到所有 YB-TServer 中。

[Greenplum]

  • 数据重新分配应在使用较少的时段执行。可以在较长时间内将重新分配划分为多个批次。
  • 若要开始重新分配阶段,请使用 -d(持续时间)或 -e(结束时间)选项运行 gpexpand,或不使用任何选项。如果您指定了结束时间或持续时间,则该实用程序会重新分配扩张模式中表格的数据,直到达到指定的结束时间或持续时间为止。如果您未指定任何选项,那么该实用程序的重新分配阶段将持续,直至重新组织扩张模式中所有表为止。会使用 ALTER TABLE 命令重新组织每张表,以跨新段重新平衡表。
  • 在计划重新分配阶段时,请考虑对每张表施加 ACCESS EXCLUSIVE 锁和表数据重新分配方法的影响。用户对表进行的活动可能会延迟其重新分配,但表在重新分配期间也对用户活动不可用。
  • 在执行 Greenplum 数据库扩展时,有两种重新分配数据的方法。
    1. 重建 - 创建新表,将所有数据从旧表复制到新表,并替换旧表。这是默认选项。该重建方法类似于使用 CREATE TABLE AS SELECT 命令创建新表。在数据重新分配期间,会在表上获取 ACCESS EXCLUSIVE 锁。
    2. 移动 - 扫描所有数据并执行 UPDATE 操作,以根据需要将行移动到不同的段实例。在数据重新分配期间,会在表上获取 ACCESS EXCLUSIVE 锁。通常,此方法需要的磁盘空间更少,但它会创建过时的表行,因此可能需要在数据重新分配后对表执行 VACUUM 操作。此外,此方法会逐行更新索引,而这可能比使用 CREATE INDEX 命令重建索引慢得多。
  • 由于 gpexpand 实用程序必须在重新分配后重新索引每个已索引的表,因此较高水平的索引会产生较大的性能影响。
  • 在创建扩张模式后,可以使用 gpexpand 跨整个系统重新分配表。计划在使用较少的时段运行此项任务,当时实用程序的 CPU 使用率和表锁定对操作的影响很小。对表进行排序以首先重新分配最大或最重要表。
  • 对于大型系统,您可以控制表重新分布的顺序。调整扩展架构中表的等级值,以优先考虑使用率高的表并最小化对性能的影响。
  • ALTER TABLE 提供了更改表的分发策略的选项。更改表分发选项时,表数据可能会在磁盘上重新分布,这可能非常消耗资源。您还可以使用现有分发策略来重新分布表数据。
    • ALTER TABLE sales SET DISTRIBUTED BY (customer_id);

[Citus]

  • 要将现有分片移至新添加的辅助工作站,请连接到集群协调器节点并运行
    • SELECT rebalance_table_shards('distributed_table_name');
    • 如果省略表名称,则会平衡所有分片。
  • rebalance_table_shards 函数对参数中命名的表所在分布组中的所有表重新分配均衡。因此,您不必针对每张表调用该函数,只需针对分布组中的每个代表性表调用一次即可。
  • 分片重新分配均衡期间,应用程序无需经历停机。
    • 在> = PostgreSQL 10 上,Citus 分片重新分配均衡使用 PostgreSQL 逻辑复制将数据从旧分片(按复制术语称为“发布者”)移至新分片(“订阅者”)。逻辑复制允许应用程序在复制分片数据时继续无中断地读取和写入。Citus 仅在更新元数据以将订阅者分片提升为活动分片所需的时间段内才会对分片进行短暂的写锁定。
    • 对于不支持逻辑复制的< PostgreSQL 10,则退回到效率较低的方法:在将分片复制到其新位置时对其写操作进行锁定。与逻辑复制不同,此方法会给写语句带来停机(尽管读取查询不受影响)。

[Postgres-XL]

  • 使用 ALTER TABLE 将节点添加或删除为分布表的目标。
    • ALTER TABLE disttab ADD NODE (dn3);
    • ALTER TABLE disttab DELETE NODE (dn1);
  • 此操作以 3 或 4 个步骤完成。在目标表上保留 ACCESS EXCLUSIVE 锁。
    1. 使用 COPY TO 命令提取所有数据后,数据保存到协调器上。此时,所有元组都使用元组存储库进行保存。
    2. 在所有节点上截断表。
    3. 更新编录。
    4. 最后,使用内部 COPY FROM 机制重新分配元组存储库中的数据。必要时发出 REINDEX。

数据导入导出

  • 对 COPY FROM 并行化以异步地将数据推送到分片,以便多个集群节点可以并行工作。
  • 启用 COPY FROM/TO 以指示群集中的每个节点在其本地存储上读取或写入文件,从而实现文件输入和输出的并行化。此处假设本地存储通常是本地装载的远程存储,例如 NFS、Ceph 和云存储。
  • 当一个群集节点故障转移时,自动继续导入导出,因为重新启动是一个灾难。

[Oracle]

  • 建议通过在每个分片上运行 Data Pump 并行地将数据直接加载到数据库分片,因为它要快得多。由于拆分逻辑在分片协调器(目录)节点上运行,并且向分片推送数据还有其他开销,因此通过分片协调器加载数据要比将整个数据集加载到非分片表中要慢。

[MySQL 集群]

  • 对 NDB 表使用时,LOAD DATA 不是事务性的。执行 LOAD DATA 语句时,NDB 引擎会以不规则的间隔执行提交以更好地利用通信网络。无法提前知道此类提交何时发生。

[Cloud Spanner]

  • 使用 Dataflow(一种用于转换和丰富数据的托管服务)将单个数据库导出和导入到 Cloud Storage 存储空间中的一组 Avro 或 CSV 文件中,并从这些文件中导入数据。每个表的数据都拆分为多个导出文件。

[CockroachDB]

  • IMPORT 接受多种格式的文件,例如 CSV、分隔和 Avro。为了最大程度地提高导入性能,建议在 Cloud Storage 中指定尽可能多的节点输入文件,以便所有集群节点可以并行导入数据。
  • EXPORT 语句将表格数据或任意 SELECT 语句的结果导出到 CSV 文件中。EXPORT 使用 CockroachDB 分布式执行引擎,在集群中的所有节点上并行化 CSV 创建,从而能够快速从 CockroachDB 中获取大量数据,其格式可由下游系统读取。
  • 您可以指定要存储导出的 .csv 文件的基础目录。CockroachDB 将在指定目录中创建导出文件,并为其提供程序生成的名称(例如,n1.1.csv、n1.2.csv、n2.1.csv 等)。

EXPORT INTO CSV 'azure://acme-co/customer-export-data?AZURE_ACCOUNT_KEY=hash&AZURE_ACCOUNT_NAME=acme-co' WITH delimiter = '|' FROM TABLE bank.customers; 

[YugabyteDB]

  • 提供了 PostgreSQL 的 COPY 命令,但没有并行功能。

[Greenplum]

  • COPY 命令在主机的文本文件或段主机上的多个文本文件和表之间传输数据。
  • 可读外部表允许您使用 SQL 命令(例如 SELECT、JOIN 或 SORT EXTERNAL TABLE DATA)直接并行查询数据库外部的数据,并且您可以创建外部表的视图。外部表通常用于使用 CREATE TABLE table AS SELECT * FROM ext_table 等命令将外部数据加载到常规数据库表中。

[Citus]

  • COPY 的强大功能是,它通过许多并行连接(每个分片放置一个)异步将数据复制到工作线程。这意味着可以使用多个工作线程和多个内核并行读取数据。特别是在有开销很大的索引(如 GIN)时,这可能比读入常规 PostgreSQL 表大幅提高性能。

日志管理

<问题>

  • Q1:如何关联不同节点上的事件?我们是否应添加一些标记到日志行前缀中,来显示操作、源会话或它们的组合?
  • Q2:我们是否应将一些事件(如群集重新配置、数据移动和 DDL 执行)收集到中心节点上的服务器日志中?我们是否将其留给外部日志管理软件(例如 syslog)?
  • Q3:我们是否应提供收集所有节点上日志文件的功能?

[Oracle]

  • 主分片管理器 (GSM) 跟踪/警报文件包含任何和所有异步命令或后台任务的状态和错误(移动块、拆分块、部署、分片注册、Data Guard 配置、分片 DDL 执行等)。

[MySQL 集群]

  • 事件日志分以下两种类型
    • 群集日志:记录群集整体所需报告的所有事件。在正常情况下,只需保留并检查群集日志即可,这一点既必要又足够。
    • 节点日志:为每个单独节点保留一个单独的日志。节点日志仅用于应用程序开发期间,或用于调试应用程序代码。
  • 当数据节点中发生有趣事件时,这些节点会将有关这些事件的信息传输到管理服务器,然后管理服务器将这些信息写入群集日志。

[CockroachDB]

  • “cockroach debug zip” 命令会将每个活动节点中的日志文件收集到一个文件中(不包括非活动节点)。

[Greenplum]

  • 你可以通过查询的会话标识符 (gp_session_id) 和命令标识符 (gp_command_count) 来识别特定查询的相关日志条目。

监控

  • 群集成员节点和节点组
  • 每个节点对当前群集状态的内存视图
  • 整个群集数据库、表和索引的总大小
  • 各节点之间的数据分布
  • 各节点之间的负载分布:事务和读/写,以查找热点
  • 数据重新分布/移动进度
  • 各会话访问的节点
  • 与其他节点之间的连接
  • 各个节点之间的通信,例如每个会话/数据库的发送/接收计数和数量
  • 远程操作的等待事件
  • 分布式事务计数
  • 包含节点信息的锁
  • 检测到的分布式死锁日志
  • 类 Oracle GV$ 视图的群集范围统计视图 (pg_gstat_*)

[Oracle]

  • 分片负载图显示事务是如何在分片之间分布的。
  • 可以使用分片目录数据库作为使用 SQL SHARDS() 子句执行集中式诊断操作的入口点。SHARDS() 子句允许你在所有分片上查询相同的 Oracle 提供对象,例如 V$、DBA/USER/ALL 视图和字典对象和表,并返回聚合结果。在执行多分片查询时,会自动将称为 SHARD_ID 的虚拟列添加到 SHARDS()-包装的对象中,以指示结果中每行的来源。

select ORA_SHARD_ID, INSTANCE_NAME from SHARDS(sys.v_$instance); 

[MySQL 集群]

[CockroachDB]

  • 提供群集内所有节点之间的往返延迟。

[Greenplum]

  • 包括一个可选的系统监控和管理数据库 gpperfmon。
  • gp_toolkit 架构包含展示数据库、表格和索引的群集范围总大小的视图。
  • 提供系统列 gp_segment_id,以便了解表格行的数据分布(每段的行数)

SELECT gp_segment_id, count(*) FROM table_name GROUP BY gp_segment_id; 

[Citus]

  • pg_dist_node 表格包含群集中工作人员节点的信息。
  • pg_total_relation_size() 大幅低估分布式表格的大小。此函数揭示协调器节点上表格的大小。相反,可以使用以下函数。
    • citus_total_relation_size(relation_name)
    • citus_relation_size(relation_name)
    • citus_table_size(relation_name)
  • 提供以下视图来监视整个群集中的查询和锁定,包括在内部用于构建分布式查询结果的特定分片查询。
    • citus_dist_stat_activity:显示所有节点上执行的分布式查询。
    • citus_worker_stat_activity:显示针对工作人员的查询,包括针对各个分片的片段查询。
    • citus_lock_waits:整个群集中的已阻止查询。
  • citus_stat_statements 显示哪些查询在单个节点上运行,哪些查询在多个节点上运行。

SELECT sum(calls), partition_key IS NOT NULL AS single_tenant FROM citus_stat_statements GROUP BY 2; 

维护操作

<问题>

  • 问题 1:我们是否允许从任何节点运行群集范围操作?
  • 问题 2:空闲节点上的自动 vacuum 启动器是否需要对其它节点上的更新敏感,以防止 XID 环绕?就此而言,每个节点是否可以独立?
  • 问题 3:CHECKPOINT 是否有仅在本地节点执行工作的选项?(Oracle RAC 有此类 LOCAL 从句。)
  • 如果目标是某个表格或索引,而不是特定分片,则这些命令将在所有分片上并行运行。
    • VACUUM
    • ANALYZE
    • REINDEX
    • TRUNCATE
    • CLUSTER
  • CHECKPOINT 在所有节点上并行运行检查点/重启点处理。

[YugabyteDB]

  • 尚未完全支持 ACCESS EXCLUSIVE 锁定选项。

[Citus]

  • 将 ANALYZE 命令传播到所有工作人员节点放置。
  • 针对分布式表格使用 vacuum 时,会向该表格的每个放置发送一个 vacuum 命令(每个放置一个连接)。此操作是并行进行的。
  • 未指定表格的 VACUUM 命令不会传播到工作人员节点。
  • 不支持 VACUUM 的 VERBOSE 选项。

[Postgres-XL]

  • 还将把手动 VACUUM 推送到所有数据节点。
  • 还将在所有数据节点上执行 CLUSTER。
  • 将检查点在本地协调器和所有基础数据节点上执行。

修改架构

<问题>

  • Q1:可以在哪里执行架构更改,它们是如何在整个集群中传播的?
  • Q2:如果在运行 DDL 语句时某些集群节点已关闭,会怎么样?
  • Q3:是否有要禁止的架构修改?
  • Q4:如何最大程度地减少架构更新所需的停机时间,并保持应用程序读写数据?

[Oracle]

  • 对重复表或分片表进行更改应当在分片目录数据库中完成。
  • 如果需要更细粒度的控制,您可以在每个分片上直接发出命令。
  • 如果您执行需要锁定表格的操作(例如,添加非空列),务必记住,每个分片需要获取对表格的锁才能执行 DDL 操作。

[MySQL 集群]

  • 不支持在线 DROP COLUMN 操作。
  • 除了运行在线 ALTER TABLE ADD COLUMN、ADD INDEX 或 DROP INDEX 操作(或 CREATE INDEX 或 DROP INDEX 语句)的节点之外,要修改的表格对于其他 API 节点不会被锁定。但是,在执行在线操作时,表格会被锁定,以防止同一 API 节点上发起的其他操作。
  • 表空间无法在线更改。

[Spanner]

  • Cloud Spanner 中的架构更新不需要停机时间。当您向 Cloud Spanner 数据库发出批处理 DDL 语句时,您可以在不中断的情况下继续向数据库写入和读取数据,而 Cloud Spanner 会将更新应用为一项长时间运行的操作。
  • 如果架构更新不需要 Cloud Spanner 验证现有数据,则可以在数分钟内完成。需要验证的架构更新可能需要更长的时间,具体取决于需要验证的现有数据的量,但是数据验证会在后台以低于生产流量的优先级进行。
  • 某些架构更新可以在架构更新完成之前更改对数据库的请求行为。例如,如果您向某列添加 NOT NULL,Cloud Spanner 几乎会立即开始拒绝对使用 NULL 作为该列的新请求的写入。如果新的架构更新最终因数据验证而失败,则存在一段时间,其间写入会被阻止,即使旧架构接受它们也是如此。
  • Cloud Spanner 使用架构版本控制,以便在大数据库架构更新期间没有停机时间。Cloud Spanner 维护旧架构版本,以便在处理架构更新时支持读取。然后,Cloud Spanner 会创建新的架构版本,用于处理架构更新。每个版本都包含由单个原子更改的语句集合的结果。
  • 架构版本可能会占用大量服务器和存储资源,它们最多持续一周。在 7 天内应避免需要验证或索引回填的 DDL 语句超过 30 个,因为每个语句在内部都会创建多个架构版本。
  • TrueTime 使 Spanner 能够支持原子架构更改。
    • 使用标准事务将不可行,因为参与者的数量(数据库中组的数量)可能达到百万。
    • Spanner 架构更改事务通常是标准事务的非阻塞变种。
    • 首先,它会明确地分配一个未来的时间戳,该时间戳在准备阶段被注册。由此,跨越数千台服务器的架构更改可以在对其他并发活动造成最少中断的情况下完成。
    • 其次,隐式依赖于架构的读写会在时间 t 与任何已注册的架构更改时间戳同步:如果其时间戳在 t 之前,它们可以继续,但如果其时间戳在 t 之后,它们必须在架构更改事务的后面阻塞。如果没有 TrueTime,定义在时间 t 发生的架构更改将毫无意义。

[CockroachDB]

  • 我们在维护一致的分布式架构缓存和一致的表数据方面的解决方案采用了并发使用多个架构版本的方式,允许在新架构仍在使用时推出新架构。它会在不保持锁的情况下回填(或删除)基础表数据。此解决方案源自 Google 的 F1 团队所做的工作。
  • 如何在 CockroachDB 中进行在线架构更改

[Citus]

  • Citus 使用两阶段提交协议从协调器节点将架构更改传播到工作器。
  • 某些 DDL 语句需要手动传播,还明确禁止某些其他语句(例如会修改分布列的语句)。

[Postgres-XL]

  • 以下操作不被允许
    • 放弃分布式列

终止会话

<问题>

  • 问题一:当控制权移交给远程节点时,是否始终可以在合理的时间内强制终止会话?
  • 问题二:当会话被强制终止时,如何将关联的节点间连接返回连接池?

取消查询

<问题>

  • 问题一:当控制权移交给远程节点时,是否始终可以在合理的时间内取消查询?
  • 问题二:当查询被取消时,如何将关联的节点间连接返回连接池?

软件更新、升级和降级

希望启用

  • 滚动硬件/软件维护:逐个停止、修补和重新启动节点
  • 更改特定虚拟机实例或容器的容量(CPU、RAM),而不影响整个集群
  • 在不关闭整个集群的情况下升级软件

<问题>

  • 问题一:我们是否允许包含不同 PostgreSQL 主要版本和次要版本的集群配置?
  • 问题二:我们是否允许降级和/或恢复到更早的次要版本,以防最新的次要版本有致命错误?
  • 问题 3:如何区分需要花费较长时间才能完成的计划内维护和需要在新节点上创建新副本的故障?

[Oracle]

  • 更新
    • 滚动模式下的 oPatchAuto 自动化 patch 和升级。
    • 大多数 patch 每一次可以应用到一个分片。
    • 某些 patch 应该应用到所有分片。
    • 如果 patch 修复了多分片查询、复制或分片基础设施的问题,则应该应用到所有分片。
  • 升级
    • 必须首先升级分片目录,然后是分片管理器,最后是分片。
    • 分片目录和分片在各自的数据保护配置中进行滚动升级。
    • 逐个停止、升级和重新启动所有分片管理器服务器。为了确保零停机时间,至少应始终运行一个分片管理器服务器。
  • Oracle 分片不支持降级。

[MySQL 集群]

  • 在升级任何数据节点之前,必须升级所有管理节点。
  • 可以在升级管理节点、数据节点或两者之前或之后升级 SQL 节点。
  • 在新版本中特有的功能只能在升级所有管理节点和数据节点之后才能使用。

[CockroachDB]

  • 用户每次只能升级一个节点,并且在节点重新加入群集后至少等待一分钟才能升级下一个节点。同时升级多个节点会增加区间丢失大部分副本并造成群集不可用的风险。

[YugabyteDB]

  • 基本流程时逐个升级每个 YB-Master 和 YB-TServer,在每一步后从 yb-master 管理 UI 验证群集是否正常,以及升级的进程是否已恢复联机。
  • 在升级节点之间暂停约 60 秒。

[Citus]

  • 如果同时升级 Citus 和 Postgres,请务必始终先升级 Citus 扩展,然后升级 PostgreSQL 版本。它们不能同时升级。
  • 基本升级流程包括:备份旧协调器的 Citus 元数据,创建一个具有新版本的新数据库群集,停止旧服务器,运行 pg_upgrade,启动新服务器,然后还原 Citus 元数据。如需了解详细信息,请参阅升级 Citus

[Postgres-XL]

  • 可使用 pg_dumpall 和 psql 来升级 Postgres-XL,就像升级 PostgreSQL 一样。
  • 未在 Postgres-XL 中测试对 pg_upgrade 的支持。


迁移

<问题>

  • 问题 1:如何将单服务器数据库迁移到横向扩展数据库,反之亦然?
  • 问题 2:如何有效地将数据从一个横向扩展数据库迁移到另一个横向扩展数据库?

[Oracle]

  • 分片建议工具连接到现有的非分片数据库,分析其架构和查询工作负载,并为分片数据库生成一组替代设计,包括针对有效分片密钥、要分片哪些表以及要在所有分片上复制哪些表的建议。
  • Oracle Data Pump 具有分片感知功能,并在从非分片 Oracle 数据库迁移数据到分片 Oracle 数据库时,可以执行并行数据导出和导入。

[MySQL 集群]

  • ndb_import 程序使用 NDB API 直接将 CSV 格式文件中的数据导入 NDB 表,而无需连接到 MySQL Server。虽然这没有在迁移上下文中进行描述,但似乎很快,并且有助于迁移。

[Spanner]

  • 使用 Dataflow(一种用于转换和丰富数据的托管服务)将单个数据库导出和导入到 Cloud Storage 存储空间中的一组 Avro 或 CSV 文件中,并从这些文件中导入数据。每个表的数据都拆分为多个导出文件。

[CockroachDB]

  • 用户可以使用 pg_dump 将数据库或单个表转储到 SQL 脚本文件,并运行 IMPORT 语句加载数据。CockroachDB 不支持类型或函数定义,也不支持从非公共架构加载数据,因此用户必须在 SQL 脚本中移除或修改这些内容。
  • IMPORT 接受多种格式的文件,例如 CSV、分隔和 Avro。为了最大程度地提高导入性能,建议在 Cloud Storage 中指定尽可能多的节点输入文件,以便所有集群节点可以并行导入数据。

[YugabyteDB]

  • 用户可以使用 pg_dump 或源自 pg_dump 的 ysql_dump,将数据库或单个表转储到 SQL 脚本文件,并运行 ysqlsh 加载数据。
  • COPY TO 和 COPY FROM 可用于导出和导入表格,就像原始 PostgreSQL 一样。

[Greenplum]

  • pg_dump、pg_dumpall、psql 和 COPY 可像 PostgreSQL 一样使用。
  • 带有 ON SEGMENT 子句的 COPY 会让每个分段实例在其数据分段主机上的一个单独文件读取或写入其数据。示例语法为“COPY table [TO|FROM] '<SEG_DATA_DIR>/gpdumpname<SEGID>_suffix' ON SEGMENT;”。
  • 您可以使用 gpcopy 实用程序在不同 Greenplum Database 集群中的数据库之间传输数据。gpcopy 是一个高性能实用程序,可以从一个 Greenplum 数据库将元数据和数据复制到另一个 Greenplum 数据库。您可以迁移数据库的整个内容,或只迁移所选表格。集群可以具有不同的 Greenplum Database 版本。

[Citus]

  • 由于 Citus 是作为 PostgreSQL 扩展部署的,因此 PostgreSQL 用户通常可以通过在其现有数据库上安装扩展,开始使用 Citus。一旦创建扩展,您就可以通过标准 PostgreSQL 接口创建和使用分布式表,同时保持与现有 PostgreSQL 工具的兼容性。
  • 如果将现有的 PostgreSQL 数据库转换为 Citus 集群的协调程序节点,则可以高效地、以对应用程序的最小中断方式分配其表中的数据。先前描述的 create_distributed_table 函数既适用于空表,也适用于非空表,并且对于后者,它会自动在集群中分配表行。当数据迁移时会阻止对表的写入,并且一旦该函数提交,挂起的写入就会作为分布式查询处理。(如果该函数失败,则查询会再次变为本地查询。)读取可以正常继续,并且一旦该函数提交,读取就会变为分布式查询。


利用 Postgres-XL 代码

<问题>

  • Q1:Postgres-XL 除原子提交和全局可见性外,还做了什么?
  • 问 2:Postgres-XL 代码的哪些部分可以重复使用?

<哪些可以重复使用的>

  • 节点管理
    • CREATE/ALTER/DROP 节点语句
    • CREATE/DROP 节点组语句
  • 跨群集节点的 DDL 传播
  • 数据分片和放置
    • 分布式表
    • 已复制的表
    • 数据重新分配
    • CREATE/ALTER TABLE、CREATE TABLE AS 语句
  • 系统目录
    • pgxc_node:群集节点
    • pgxc_group:群集节点组
    • pgxc_class:分布或复制方法和放置
  • 节点间通信
    • 连接池
    • CLEAN CONNECTION 语句
  • 序列
    • 集群范围内的集中式序列管理(在 GTM 中)
    • CREATE/ALTER/DROP SEQUENCE 语句
    • 序列操作:nextval、currval、setval,等等
  • 事务管理
    • 跨群集节点的两阶段提交
  • 备份和恢复
    • CREATE BARRIER 语句:在所有群集节点上创建一个一致点
  • 查询处理
    • Locator:确定给定表被复制或分布在哪些节点上
    • FQS(快速查询配送):确定查询是否可以在 Datanode 上直接执行,而无需涉及 Coordinator
    • 分布式查询规划和执行
      • 联接、ORDER BY、LIMIT、GROUP BY 的下推
      • 跨数据节点的聚合
    • 更新复制表
  • 数据库管理
    • initdb
    • pgxc_ctl
      • 根据配置定义初始化和配置群集
      • 在群集中添加和移除主节点和从节点
      • 启动和停止群集
      • 执行每个节点的故障转移
      • 监控群集节点的运行状况
    • pgxc_monitor
    • pg_dump、pg_dumpall
      • 包括节点定义(仅 pg_dumpall)
      • 将表分布参数包含到表定义中
    • COPY 语句:COPY TO 从数据节点收集数据,COPY FROM 将数据分布到数据节点
    • PAUSE/UNPAUSE CLUSTER 语句:阻止和允许新的事务执行维护操作
    • EXPLAIN 语句:输出分布式查询计划
    • Vacuum:即使在空闲节点上也触发自动 vacuum,以防止 XID 回绕

<哪些不会重复使用的>

  • 进程管理
    • GTM、GTM_proxy
    • Coordinator 和数据节点的分离
  • 事务管理(在 GTM 中)
    • 分配 XID
    • 提供快照
  • 实用工具
    • initgtm、gtm、gtm_proxy、gtm_ctl
    • pg_dump、pg_dumpall
      • 获取来自序列关系以及 GTM 的序列值

<参考文献>