Timescale Cloud:性能、规模、企业级

自托管产品

MST

本文档提供详细的分步说明,介绍如何使用双写和回填迁移方法,将数据从未使用 PostgreSQL 的源数据库迁移到 Timescale。

注意

在迁移的上下文中,您现有的生产数据库被称为“源”数据库,而您打算将数据迁移到的新的 Timescale 数据库被称为“目标”数据库。

具体来说,迁移过程包括以下步骤:

  1. 在 Timescale 中设置目标数据库实例。
  2. 修改应用程序以写入辅助数据库。
  3. 设置 schema 并将关系型数据迁移到目标数据库。
  4. 以双写模式启动应用程序。
  5. 确定完成点 T
  6. 将时序数据从源数据库回填到目标数据库。
  7. 在目标数据库中启用后台作业(策略)。
  8. 验证目标数据库中是否存在所有数据。
  9. 验证目标数据库能否处理生产负载。
  10. 将应用程序切换为将目标数据库视为主数据库(可能继续写入源数据库作为备份)。
提示

如果您遇到困难,可以通过开启支持请求或在社区 Slack#migration 频道中提出您的问题,该迁移方法的开发者会提供帮助。

您可以直接从 Timescale 控制台 开启支持请求,或者通过电子邮件发送至 support@timescale.com

在 Timescale 中创建数据库服务.

如果您打算迁移超过 400 GB 的数据,请开启支持请求,以确保您的 Timescale 实例预先配置了足够的磁盘空间。

您可以直接从 Timescale 控制台 开启支持请求,或者通过电子邮件发送至 support@timescale.com

具体如何执行此操作取决于您的应用程序所用的语言以及您的数据摄入和应用程序功能。最简单的情况是,您只需并行执行两次插入操作。在一般情况下,您必须考虑如何处理写入源数据库或目标数据库失败的情况,以及您希望或能够构建何种机制从此类失败中恢复。

如果您的时序数据在普通表中存在外键引用,则必须确保您的应用程序正确维护外键关系。如果被引用的列是 *SERIAL 类型,则插入到源数据库和目标数据库中的同一行可能不会获得相同的自动生成 ID。如果发生这种情况,从源数据库回填到目标数据库的数据在内部将不一致。在最好的情况下,这会导致外键违规;在最坏的情况下,外键约束得以维护,但数据引用了错误的外键。为避免这些问题,最佳实践是遵循实时迁移

您可能还希望在源数据库和目标数据库上执行相同的读取查询,以评估查询结果的正确性和性能。请记住,目标数据库在一段时间内不会包含所有数据,因此您应该预期在某个时期(可能几天)内结果不会相同。

详细描述如何从所有可能的源数据库迁移数据是不切实际的,因此我们只告诉您需要做什么,并希望您能找到支持您的资源。

在此步骤中,您需要准备数据库以接收从应用程序双写过来的时序数据。如果您从另一个时序数据库迁移,则只需担心为包含时序数据的超表设置 schema。有关超表是什么的一些背景信息,请查阅入门指南的表和超表部分。

如果您从包含关系型数据和时序数据的关系型数据库迁移,您还需要在此步骤中为关系型数据设置 schema 并将其复制过来,但不包括任何时序数据。时序数据将在后续步骤中回填。

在双写和回填场景中,我们的假设是关系型数据的数量相对于时序数据而言非常小,因此在复制关系型数据时短暂停止生产应用程序不成问题;或者,关系型数据更改不频繁,因此您可以在不停止应用程序的情况下获取关系型元数据的快照。如果您的应用程序不符合这种情况,您应该重新考虑使用双写和回填方法。

注意

如果您计划试验连续聚合,我们建议您首先完成双写和回填迁移,然后再在数据上创建连续聚合。如果在回填数据之前在超表上创建连续聚合,则必须刷新整个时间范围内的连续聚合,以确保聚合数据中没有空白。

设置好目标数据库后,您的应用程序现在可以以双写模式启动。

双写执行一段时间后,目标超表包含三个时间范围内的数据:缺失写入、迟到数据和“一致性”范围。

Hypertable dual-write ranges

如果应用程序由多个写入器组成,并且这些写入器并未同时开始写入目标超表,则会有一段时间内并非所有写入都已进入目标超表。此期间从第一个写入器开始双写时开始,到最后一个写入器开始双写时结束。

某些应用程序存在迟到数据:时间戳在过去,但尚未写入的测量值(例如来自间歇性连接问题的设备)。迟到数据窗口介于当前时刻和最大延迟之间。

一致性范围是没有缺失写入且所有数据都已到达的范围,即在缺失写入范围的末尾和迟到数据范围的开头之间。

这些范围的长度由应用程序的属性定义,没有一概而论的方法来确定它们。

完成点 T 是在一致性范围内任意选择的时间点。它是可以安全地回填数据的时间点,确保不会丢失数据。

完成点应表示为要回填的超表的 time 列的类型。例如,如果您使用 TIMESTAMPTZ time 列,则完成点可能是 2023-08-10T12:00:00.00Z。如果您使用 BIGINT 列,则可能是 1695036737000

如果您的超表的 time 列使用混合类型,您必须为每种类型单独确定完成点,并独立于其他类型回填每组相同类型的超表。

按表将数据从源数据库转储为 CSV 格式,并使用 timescaledb-parallel-copy 工具将这些 CSV 文件恢复到目标数据库中。

确定要从源数据库复制到目标数据库的数据窗口。根据源表中数据量的大小,将源表分割成多个独立移动的数据块可能是明智的。在以下步骤中,此时间范围称为 <start><end>

通常 time 列的类型是 timestamp with time zone,因此 <start><end> 的值必须是 2023-08-01T00:00:00Z 这样的格式。如果 time 列不是 timestamp with time zone,则 <start><end> 的值必须是该列的正确类型。

如果您打算从源表复制所有历史数据,则 <start> 的值可以是 '-infinity',而 <end> 的值是您确定的完成点 T 的值。

双写过程可能已经在您想要移动的时间范围内向目标数据库写入了数据。在这种情况下,必须删除双写的数据。这可以通过 DELETE 语句实现,如下所示:

psql $TARGET -c "DELETE FROM <hypertable> WHERE time >= <start> AND time < <end>);"
重要

BETWEEN 运算符包含起始范围和结束范围,因此不建议使用。

请查阅您的源数据库文档,以确定如何将表转储为 CSV 格式。您必须确保 CSV 文件仅包含完成点之前的数据。在从源数据库转储数据时,应应用此过滤条件。

您可以使用 timescaledb-parallel-copy 工具将 CSV 文件加载到超表中,如下所示。将 worker 数量设置为目标数据库中的 CPU 核心数量。

timescaledb-parallel-copy \
--connection $TARGET \
--table <target_hypertable> \
--workers 8 \
--file <table dump for source table>

上述命令不是事务性的。如果出现连接问题或导致其停止复制的其他问题,必须从目标数据库中删除部分复制的行(使用上面第 6b 步中的说明),然后才能重新开始复制。

在以下命令中,将 <hypertable> 替换为目标超表的完全限定表名,例如 public.metrics

psql -d $TARGET -f -v hypertable=<hypertable> - <<'EOF'
SELECT public.alter_job(j.id, scheduled=>true)
FROM _timescaledb_config.bgw_job j
JOIN _timescaledb_catalog.hypertable h ON h.id = j.hypertable_id
WHERE j.proc_schema IN ('_timescaledb_internal', '_timescaledb_functions')
AND j.proc_name = 'policy_compression'
AND j.id >= 1000
AND format('%I.%I', h.schema_name, h.table_name)::text::regclass = :'hypertable'::text::regclass;
EOF

现在所有数据都已回填,并且应用程序正在向两个数据库写入数据,因此两个数据库的内容应该相同。如何最佳地验证这一点取决于您的应用程序。

如果您并行地从两个数据库读取每个生产查询,您可以考虑添加一个应用程序级别的验证,以确保两个数据库返回相同的数据。

另一种选择是比较源表和目标表中的行数,尽管这会读取表中的所有数据,这可能会影响您的生产工作负载。

现在双写已经到位一段时间,目标数据库应该能够承受生产写入流量。现在是时候确定目标数据库是否可以服务所有生产流量(包括读取和写入)了。具体如何操作是应用程序特定的,由您自行决定。

一旦您验证了所有数据都存在,并且目标数据库能够处理生产工作负载,最后一步就是将目标数据库切换为主数据库。您可能希望继续向源数据库写入一段时间,直到您确定目标数据库能够承受所有生产流量。

关键词

此页面发现问题?报告问题 或 编辑此页面 在 GitHub。