如何排查 AWS DMS 任务失败并显示错误消息“ERROR: canceling statement due to statement timeout”(错误:由于语句超时取消语句)的问题?

3 分钟阅读
0

我使用 AWS Database Migration Service(AWS DMS)在我的本地 PostgreSQL 数据库中来回迁移数据。AWS DMS 任务正常运行一段时间,然后任务失败,出现错误。如何排查并解决这些错误?

简短描述

如果 PostgreSQL 数据库是您的迁移任务来源,则 AWS DMS 会在完整加载期间从表中获取数据。然后,AWS DMS 会从预写日志(WAL)中读取数据,该日志在更改数据捕获(CDC)期间由复制槽保留。

如果 PostgreSQL 数据库是目标,则 AWS DMS 会从来源中获取数据并在复制实例中创建 CSV 文件。然后,AWS DMS 运行 COPY 命令以在完整加载期间将这些记录插入到目标中。

但是,在 CDC 期间,AWS DMS 在事务应用模式下从源 WAL 日志中运行准确的 DML 语句。对于批量应用模式,AWS DMS 还会在 CDC 阶段创建 CSV 文件。然后,它将会运行 COPY 命令,以将净更改插入目标。

当 AWS DMS 尝试从来源获取数据或将数据放入目标中时,它将使用 60 秒的默认超时设置。如果源或目标的负载太大或者表格中有锁定项,则 AWS DMS 无法在 60 秒内完成这些命令的运行。因此,任务失败,并显示错误“由于语句超时取消语句”,且您会在日志中看到以下条目之一:

消息:

"]E: RetCode: SQL_ERROR SqlState: 57014 NativeError: 1 消息:错误:因语句超时取消任务;执行查询时出错 [1022502] (ar_odbc_stmt.c:2738)"

"]E: test_decoding_create_replication_slot(...) - 无法创建插槽 'lrcyli7hfxcwkair_00016402_8917165c_29f0_4070_97dd_26e78336e01b' (在执行 (...) 阶段) [1022506] (postgres_test_decoding.c:392))"

要排查并解决这些错误,请执行以下步骤:

  • 查明命令运行时间长的原因。
  • 增加超时值并检查槽创建超时值。
  • 排查槽创建问题。

解决方法

查明命令运行时间长的原因

要查找超时期间未能运行的命令,请查看 AWS DMS 任务日志和任务的表统计部分。如果参数 log_min_error_statement 被设置为 ERROR 或较低的严重程度,您还可以在 PostgreSQL 错误日志文件中查找此信息。识别失败的命令后,您可以找到失败的表名称。从 PostgreSQL 错误日志中查看此示例错误消息:

ERROR: canceling statement due to statement timeout 
STATEMENT: <The statement executed>"

要查找相关表上的锁定项,请在源或目标中运行以下命令(具体取决于错误显示的位置):

SELECT blocked_locks.pid AS blocked_pid,
 blocked_activity.usename AS blocked_user,
 blocking_locks.pid AS blocking_pid,
         blocking_activity.usename AS blocking_user, 
         blocked_activity.query    AS blocked_statement,
         blocking_activity.query   AS current_statement_in_blocking_process
   FROM  pg_catalog.pg_locks         blocked_locks 
    JOIN pg_catalog.pg_stat_activity blocked_activity  ON blocked_activity.pid = blocked_locks.pid
    JOIN pg_catalog.pg_locks         blocking_locks 
        ON blocking_locks.locktype = blocked_locks.locktype 
        AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
        AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
        AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
        AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
        AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
        AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
        AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
        AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
        AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
        AND blocking_locks.pid != blocked_locks.pid 
    JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
   WHERE NOT blocked_locks.GRANTED;

如果您发现任何被阻止的 PID,请通过运行以下命令停止或终止被阻止的 PID:

SELECT pg_terminate_backend(blocking_pid);

由于死行或“元组”可以提高 SELECT 时间,请通过运行以下命令检查源表中有无大量死行:

select * from pg_stat_user_tables where relname= 'table_name';

检查失败的目标表中是否有主键或唯一索引。如果表中没有主键或唯一索引,则会在运行任务 UPDATE 语句过程中执行完整表扫描。此表扫描可能需要很长时间。

增加超时值

AWS DMS 在源和目标端点中均使用 executeTimeout 额外连接属性。executeTimeout 的默认值为 60 秒,因此,如果查询运行时间超过 60 秒,AWS DMS 会超时。

如果 Source_UnloadSource_Capture 中出现错误,则在源中设置 executeTimeout 的超时值。如果 Target_LoadTarget_Apply 中出现错误,则在目标中设置 executeTimeout 的超时值。遵照下述步骤提高超时值设置:

1.    打开 AWS DMS 控制台

2.    从导航窗格中选择终端节点

3.    选择 PostgreSQL 终端节点。

4.    选择操作,然后选择修改

5.    展开特定于终端节点的设置部分。

6.    在 Extra connection attributes(准确连接属性)字段中,输入以下值:

executeTimeout=3600;

7.    选择 Save(保存)。

8.    从 Endpoints (终端节点) 窗格中,选择您的 PostgreSQL 终端节点名称。

9.    在 Connections(连接)部分中,端点的 Status(状态)将从 Testing(正在测试)更改为 Successful(成功)。

您可以提高 PostgreSQL 数据库实例中的 statement_timeout 参数(以毫秒为单位)。默认值为 0,这将禁用任何查询的超时。您还可以提高 lock_timeout 参数。默认值为 0,这将禁用锁定超时。

排查槽创建问题

如果您在 PostgreSQL 数据库中创建复制槽时发生超时,则会看到类似于以下内容的日志条目:

消息

"]E: test_decoding_create_replication_slot(...) - 无法创建插槽 'lrcyli7hfxcwkair_00016402_8917165c_29f0_4070_97dd_26e78336e01b' (在执行 (...) 阶段) [1022506] (postgres_test_decoding.c:392)"

您可以通过在 Task settings(任务设置)部分中配置 TransactionConsistencyTimeout 参数来增加此超时。默认值为 600 秒。

如果数据库用户表中存在任何活动锁定,PostgreSQL 将无法创建复制插槽。通过运行以下命令检查有无锁定:

select * from pg_locks;

然后,为了测试错误是否已解决,请运行以下命令以在源 PostgreSQL 数据库中手动创建复制槽:

select  xlog_position FROM pg_create_logical_replication_slot('<Slot name as per
    the task log>', 'test_decoding');

如果该命令仍然无法创建槽,则您可能需要使用 PostgreSQL DBA 来确定瓶颈和配置数据库。如果命令成功,则删除您刚刚创建作为测试的插槽:

select pg_drop_replication_slot(‘<slot name>');

最后,重新开始迁移任务。


相关信息

客户端连接默认设置的 PostgreSQL 文档

将 PostgreSQL 用作 AWS DMS 目标时的额外连接属性

将 PostgreSQL 用作 DMS 源时的额外连接属性

将 PostgreSQL 数据库用作 AWS DMS 的源

相关视频

AWS 官方
AWS 官方已更新 2 年前