将 Spanner 迁移到 PostgreSQL 方言数据库

本页面介绍了从 Spanner 迁移到其他 PostgreSQL 方言数据库(如果您希望将应用从 Spanner 或 Google Cloud中移出)时需要遵循的关键注意事项和步骤。如果您需要了解或证明迁移数据库的可行性(例如对于被迫退出灾难规划),也可以使用本页面中的信息。

对于需要可选择部署到其他与 PostgreSQL 兼容的环境(无论是在 Google Cloud中还是在其他位置)的应用,Spanner 的 PostgreSQL 接口是最佳选择。PostgreSQL 接口采用来自 PostgreSQL 生态系统的熟悉语法和标准客户端,使开发者和运维人员可以发挥他们现有的 PostgreSQL 知识和技能。

它使用与 GoogleSQL 方言相同的查询处理、事务协调、分布式存储和网络基础设施。如果您需要支持可移植性的数据库,那么选择 PostgreSQL 接口,您便可保留 Spanner 的核心可伸缩性、一致性或性价比优势。

详细了解 Spanner 中 PostgreSQL 方言与 GoogleSQL 方言之间的区别

概括来讲,各个步骤如下所示:

  1. 从查询和 DDL 语句中移除特定于 Spanner 的扩展
  2. 迁移架构
  3. 迁移数据
  4. 迁移应用

特定于 Spanner 的注意事项

Spanner 的 PostgreSQL 接口提供对 PostgreSQL 查询的开箱即用型支持,因此在 Spanner PostgreSQL 方言数据库上运行的大多数 SQL 查询的行为与其他与 PostgreSQL 兼容的数据库相同。使用此方法时,将应用从一个平台迁移到另一个平台所需的 SQL 和数据访问更改数量可能很少。与类似的 GoogleSQL 方言数据库相比,这使得移植过程更快、更简单且更不容易出错。

除了广泛的 PostgreSQL 兼容性之外,PostgreSQL 接口还提供了一些特定于 Spanner 的扩展。如果您在应用中使用这些扩展,则必须移除它们或手动将它们映射到 PostgreSQL 功能。查询语法扩展架构管理 (DDL) 扩展中提供了一些值得注意的示例。

查询语法扩展

Spanner 的 PostgreSQL 接口提供了一些特定于 Spanner 的扩展。其中大多数扩展使用前缀 spanner. 进行标识。下表中列出了这些扩展,以及如需使同一应用可在 PostgreSQL 数据库上运行,您可能需要执行的操作。

扩展种类 特定扩展 迁移前要执行的操作
特定于 Spanner 的函数 查找以 spanner. 为前缀的函数,并移除这些调用。
类型扩展 移除 VECTOR LENGTH 语法,或考虑使用 pgvector
查询语法 无需执行任何操作,因为提示在注释内进行展示。
如需详细了解性能注意事项,请参阅查询迁移
存储系统过程 移除对 spanner.cancel_query() 的调用。
(可选)您可以将这些调用替换为 PostgreSQL 等效项
SET/SHOW 操作 可以忽略,因为 PostgreSQL 没有以 spanner. 开头的任何内置参数,因此设置任何具有该前缀的变量都不会对预期行为产生任何影响。

架构管理 (DDL) 扩展

Spanner 提供了一系列与数据管理相关的扩展,如数据定义语言 (DDL) 页面中所述。

扩展程序 迁移前要执行的操作
交织表
在物理存储空间中将多对一相关数据放置在同一位置,从而显著提高它们之间的联接效率。
移除 INTERLEAVE IN 子句。
提交时间戳
支持以原子方式将事务的提交时间戳存储到列中。
可将 SPANNER.COMMIT_TIMESTAMP 替换为 PostgreSQL 时间戳类型,并在应用中管理时间戳的设置,也可以移除该列。
时间点恢复
针对意外删除或写入提供防护。
移除所有设置 spanner.version_retention_period 的 DDL 语句。
存留时间 (TTL)
根据记录的存在时间提示自动删除记录。
移除 TTL INTERVAL 子句。 考虑利用 cron 或计划任务来定期删除过时内容。 。
优化器选项
设置相应选项以便在查询优化器或统计信息发生变化时,最大限度地降低出现性能下降的可能性。
移除设置优化器选项的 DDL 语句。
变更数据流
近乎实时地监控和流式传输 Spanner 数据库的数据更改(插入、更新和删除)。
移除与变更数据流相关的所有 DDL 语句。
默认主要区域
可让您在双区域和多区域配置中指定数据库的主要区域。
移除所有设置 spanner.default_leader 的 DDL 语句。
地理分区
使您可以进一步对不同实例配置中数据库表内的行进行细分和存储。
移除与地理位置分区相关的所有 DDL 语句。
序列
Spanner 仅支持 bit_reversed_positive 序列。
bit_reversed_positive 替换为 PostgreSQL 中可用的序列。移除所有设置 spanner.default_sequence_kind 的 DDL 语句。
位置组
可让您定义列组策略,以单独存储列或使用分层存储
移除与位置组相关的所有 DDL 语句。
搜索索引
使您可以定义索引以执行全文搜索
移除与搜索索引相关的所有 DDL 语句。

架构迁移

您可以导出采用 PostgreSQL 语法的 PostgreSQL 方言数据库架构。对于配置为使用 PostgreSQL 接口的数据库,您可以使用 PGAdapter(一种边车代理,可让您使用标准 PostgreSQL 驱动程序或客户端库连接到 Spanner)通过 psql 来实现此目的:

psql -v ON_ERROR_STOP=1 \
  --host "$PGADAPTER_HOST" \
  --port "$PGADAPTER_PORT" \
  --dbname "$SPANNER_DATABASE" \
  -qAtX \
  -c "show database ddl"

您还可以使用以下 gcloud 命令将架构输出为与 PostgreSQL 兼容的 SQL 脚本:

gcloud spanner databases ddl describe databasename

如果数据库使用特定于 Spanner 的架构扩展(例如架构管理扩展中讨论的那些),则运行此命令时会列出这些扩展。在将架构迁移到 PostgreSQL 之前,您需要移除这些对象。

数据迁移

Spanner 的 PostgreSQL 接口使用 PGAdapter 为 PostgreSQL 的 COPY TO STDINSTDOUT 扩展提供支持。这是将数据加载到 Spanner 中以及从中加载数据的一种方法。如需详细了解 COPY 命令,请参阅适用于 Spanner 的 psql 命令行工具文档

此脚本将少量数据(建议数据量小于 100 GB)从 Spanner 的 PostgreSQL 接口导出到新的 PostgreSQL 数据库中:

psql -h pgadapter-host -c "COPY $TABLE TO STDOUT BINARY" | \
psql -h postgresql-host -c "COPY $TABLE FROM STDIN BINARY"

对于较大的表(数据量大于或等于 100 GB),您可以启动 Dataflow 到 CSV 的导出模板

您可以使用 Debezium Kafka 连接器将 Spanner 更新流式传输到 PostgreSQL,从而执行实时数据迁移。如果您使用 Spanner 变更数据流 API 直接访问变更数据捕获 (CDC) 数据流,则可以进一步进行自定义。

查询迁移

适用于 Spanner 的 PostgreSQL 接口实现了许多最常见的 PostgreSQL 查询语法、函数和运算符。

如果您在查询中使用了提示,则无需重写查询,因为 Spanner 中的查询提示是在与 PostgreSQL 兼容的注释中定义的:

SELECT s.FirstName, s.LastName,
 s.SingerInfo, a.AlbumTitle, a.Charts
FROM Singers AS s
LEFT OUTER JOIN/*@JOIN_METHOD=APPLY_JOIN*/ Albums AS a
 ON s.SingerId = a.SingerId;

这些注释由 Spanner 的查询规划器处理,但 PostgreSQL 数据库会忽略这些注释,因此您可以包含或移除它们。

为了在新环境中实现最佳性能,查询和数据库架构(例如索引)可能需要针对新环境进行优化。建议您运行基准检查,以通过实证确认这一点。

应用迁移

涉及到从应用进行的连接时,您的迁移策略取决于在配置应用以使用 Spanner 时进行的初始选择,例如是否使用 PostgreSQL 驱动程序、Spanner 驱动程序或 Spanner 客户端库。本部分介绍了每种选择的注意事项。

PostgreSQL 驱动程序

Spanner 支持使用 PGAdaper(一种轻量级代理,可将 PostgreSQL 传输协议转换为 Spanner 的低级 gRPC 查询 API)的常见 PostgreSQL 客户端。如果您使用其中一种客户端,则更改为其他 PostgreSQL 目标涉及更新连接字符串,使其直接指向新的 PostgreSQL 数据库,而不是 PGAdapter 代理。此方法可提供良好的性能和强大的兼容性,因此非常适合将可移植性作为首要考虑因素的情况。在 Spanner 的 PostgreSQL 接口上运行的大多数查询在其他 PostgreSQL 环境中也同样适用。不过,反之不一定成立;PostgreSQL 支持 Spanner 不支持的语法和功能。

Spanner 驱动程序

这些驱动程序是适用于常用语言和应用框架的特定于 Spanner 的实现。例如,Spanner JDBC (Java) 驱动程序实现与 PostgreSQL JDBC 驱动程序相同的 API,因此使用 Spanner JDBC 驱动程序的应用可以在想要使用 PostgreSQL 运行应用时,更新其构建流程以链接到等效的内置 PostgreSQL 驱动程序。如果您已在使用 Spanner,或者在寻找可利用 Mutations API 等 Spanner 功能(使用内置 PostgreSQL 驱动程序无法公开这些功能)的高性能解决方案,那么此方法是最佳选择。如果您需要与内置驱动程序完全兼容并重视可移植性,则应改为考虑将 PostgreSQL 的内置驱动程序和 PGAdapter 搭配使用,以确保一定程度的应用可移植性。

如需了解详情,请参阅 PostgreSQL 驱动程序和 ORM

Spanner 客户端库

Spanner 还提供各种惯用的客户端库,通过这些库可直接访问 Spanner,而无需实现或使用 PostgreSQL 标准化接口。这些客户端可最大程度地支持访问特定于 Spanner 的功能,但其 API 与 PostgreSQL 驱动程序不兼容。这些方法可提供最高级别的功能性能,但与前述方法相比,可移植性较低。

后续步骤