排查 Spanner 超出截止日期的错误

本页面简要介绍了 Spanner 已超出期限错误:错误的定义、发生原因,以及如何排查和解决这些错误。

访问 Spanner API 时,请求可能会因 DEADLINE_EXCEEDED 错误而失败。此错误表示在配置的超时期限内未收到响应。

许多不同的原因都可能导致超出时限错误,例如 Spanner 实例过载、架构未优化或查询未优化。本页面介绍了会发生超出期限的常见情况,并提供了有关如何调查和解决这些问题的指南。

Spanner 的截止期限和重试原则

Spanner 的截止期限和重试理念与许多其他系统不同。在 Spanner 中,您应将超时截止期限指定为有用的响应的最长时间。建议不要人为设置较短的截止期限,只是为了立即再次执行相同的操作,否则会导致操作永远无法完成。在这种情况下,不建议采用以下策略和操作;它们会适得其反,会破坏 Spanner 的内部重试行为:

  • 设置的截止时间过短。这意味着操作对偶尔的尾延迟时间增加没有弹性,并且在超时之前无法完成。正确做法是设置截止时间,这是可以使用响应的最长时间。

  • 设置的截止时间过长,并在截止时间之前取消操作。这会导致不断重试,使每次尝试都白白浪费工作量。总体而言,这可能会给实例带来巨大的额外负载。

什么是“超出截止日期”错误?

当您使用某个 Spanner 客户端库时,底层 gRPC 层会负责通信、编组、解组和截止期限强制执行。借助截止日期,您的应用可以指定在请求结束且超出时限错误之前愿意等待请求完成的时间。

超时配置指南演示了如何在每个受支持的 Spanner 客户端库中指定截止期限(或超时)。Spanner 客户端库使用在以下配置文件中定义的默认超时和重试政策设置:

如需详细了解 gRPC 截止时间,请参阅 gRPC 截止时间

如何调查和解决常见的期限超出限制的错误

对于以下问题类型,您可能会遇到 DEADLINE_EXCEEDED 错误:

数据访问 API 问题

您必须为您的特定工作负载适当配置 Spanner 实例,以避免出现数据访问 API 问题。以下各部分介绍了如何调查和解决不同的数据访问 API 问题。

检查 Spanner 实例 CPU 负载

当 CPU 利用率超过建议的状况良好判断阈值时,请求延迟时间会显著增加。您可以通过 Google Cloud 控制台提供的监控控制台查看 Spanner CPU 利用率。您还可以根据实例的 CPU 利用率创建提醒

解决方法

如需了解减少实例 CPU 利用率的步骤,请参阅降低 CPU 利用率

查看请求的端到端延迟时间明细

当请求从客户端传输到 Spanner 服务器时,需要做出几个网络跃点:从客户端库到 Google Front End (GFE);从 GFE 前端到 Spanner API 前端,最后从 Spanner API 前端到 Spanner 数据库。如果其中任何阶段存在网络问题,您可能会看到“超出截止日期”错误。

您可以捕获每个阶段的延迟时间。如需了解详情,请参阅 Spanner 请求中的延迟时间点。如需了解 Spanner 中发生延迟的位置,请参阅确定 Spanner 中发生延迟的位置

解决方法

获得延迟时间细分数据后,您可以使用指标来诊断延迟时间,了解发生延迟时间的原因并寻找解决方案。

Data API 问题

Spanner 的 Data API 的某些非最佳使用模式可能会导致“超出期限”错误。本部分提供了有关如何检查这些非最佳使用模式的准则。

检查开销很高的查询

如果尝试运行成本高昂且未在客户端库中配置的超时期限内执行的查询,则可能会导致“超出期限”错误。开销很高的查询的一些示例包括但不限于:对大型表进行完整扫描、对多个大型表进行交叉联接,或对非键列使用谓词执行查询(也是全表扫描)。

您可以使用查询统计信息表事务统计信息表检查开销非常大的查询。这些表显示了有关运行缓慢的查询和事务的信息,例如平均读取的行数、平均读取的字节数、平均扫描的行数等。此外,您还可以生成查询执行计划,以进一步检查查询的执行方式。

解决方法

如需优化查询,请参阅 SQL 查询最佳实践指南。 您还可以使用通过前面提到的统计信息表和执行计划获取的数据来优化查询并对数据库进行架构更改。这些最佳实践有助于缩短语句的执行时间,进而可能有助于消除超出截止时间的错误。

检查锁争用

Spanner 事务需要获取才能提交。以高吞吐量运行的应用可能会导致事务争用相同的资源,从而导致获取锁的等待时间增加并影响整体性能。这可能会导致任何读取或写入请求的截止时间超出。

如需查找高延迟读写事务的根本原因,您可以使用锁定统计信息表并查看以下博文。在锁定统计信息表中,可以找到锁定等待时间最长的行键。

锁冲突问题排查指南介绍了如何查找正在访问锁冲突中涉及列的事务。您还可以使用使用交易代码进行问题排查的指南来了解哪些交易涉及锁定冲突。

解决方法

应用这些最佳实践来减少锁争用。此外,请为普通读取用例使用只读事务,以避免与写入发生锁冲突。使用读写事务应预留用于写入或混合读写工作流。遵循这些步骤可以缩短事务执行时间的总体延迟时间,并减少超出截止时间的错误。

检查未优化的架构

在为 Spanner 数据库设计最佳数据库架构之前,您应该考虑将在数据库中执行的查询类型。运行某些查询时,次优架构可能会导致性能问题。这些性能问题可能会导致请求无法在配置的截止期限内完成。

解决方法

最佳架构设计取决于对数据库进行的读写操作。无论架构的具体细节如何,都应遵循架构设计最佳实践SQL 最佳实践指南。遵循这些指南可以避免最常见的架构设计问题。其他一些导致性能不佳的根本原因可以归结为:您的主键选择、表布局(请参阅使用交错表提高访问速度)、架构设计(请参阅优化架构以提升性能),以及在 Spanner 实例中配置的节点的性能(请参阅 Spanner 性能概览)。

检查热点

由于 Spanner 是一个分布式数据库,因此架构设计需要考虑防止热点。例如,创建单调递增的列会限制 Spanner 可用于均匀分布工作负载的拆分数量。这些瓶颈可能会导致超时。此外,您还可以使用 Key Visualizer 排查热点导致的性能问题。

解决方法

如需解决此问题,首先请参阅上一部分检查未优化的架构中确定的解决方法。请重新设计数据库架构并使用交错索引,以避免可能引起热点的索引。如果上述步骤无法缓解问题,请参阅“选择主键以防止热点”指南。最后,应避免不理想的流量模式,例如大范围读取,因为此类读取可能会阻止基于负载的拆分。

检查是否存在配置有误的超时

客户端库为 Spanner 中的所有请求提供了合理的超时默认值。但是,您可能需要根据您的具体工作负载调整这些默认配置。您应观察查询的费用并根据具体使用场景调整截止时间。

解决方法

超时的默认设置适用于大多数用例。用户可以替换这些配置(请参阅自定义超时和重试指南),但不建议使用比默认超时更积极的超时。如果您决定更改超时时间,请将其设置为应用愿意等待结果的实际时长。您可以尝试使用更长的超时时间,但切勿将超时设置为短于应用愿意等待的实际时间,因为这会导致重试操作的频率更高。

Admin API 问题

与数据 API 请求相比,Admin API 请求的操作成本高昂。CreateInstanceCreateDatabaseCreateBackups 等管理请求可能需要几秒钟时间才能返回响应。Spanner 客户端库为实例数据库管理员请求设置了 60 分钟的时限。这是为了确保服务器在客户端重试或失败之前有机会完成请求。

解决方法

如果您使用 Google Spanner 客户端库访问管理员 API,请确保客户端库已更新且使用的是最新版本。如果您要直接通过您创建的客户端库访问 Spanner API,请确保您的截止期限设置不超出实例数据库管理员请求的默认设置(60 分钟)。

Google Cloud 控制台问题

从 Google Cloud 控制台的 Spanner Studio 页面发出的查询不能超过五分钟。如果您创建了一个成本高昂的查询,运行超过五分钟,则会看到以下错误消息:

“Google Cloud 控制台截止时间超出”错误消息的屏幕截图

后端将取消失败的查询,如有必要,事务可能会回滚。

解决方法

您可以按照 SQL 查询最佳实践指南重写查询。

Dataflow 问题

在 Apache Beam 中,默认超时配置为两小时(对于读取操作)和 15 秒(对于提交操作)。与独立客户端库截止时间超时相比,这些配置允许执行更长的操作。但是,如果工作项过大,仍有可能会出现超时和超出截止时间的错误。如有必要,您可以自定义 Apache Beam 提交超时配置。

解决方法

如果步骤 ReadFromSpanner / Execute query / Read from Spanner / Read from Partitions 中发生超出截止时间错误,请检查查询统计信息表,找出哪个查询扫描了很多行。然后,修改此类查询以尝试缩短执行时间。

以下异常消息中显示了另一个 Dataflow 超出时限错误示例:

exception:
     org.apache.beam.sdk.util.UserCodeException:
     com.google.cloud.spanner.SpannerException: DEADLINE_EXCEEDED:
     io.grpc.StatusRuntimeException: DEADLINE_EXCEEDED: deadline exceeded after
     3599.999905380s.
     [remote_addr=batch-spanner.googleapis.com/172.217.5.234:443] at
 org.apache.beam.runners.dataflow.worker.GroupAlsoByWindowsParDoFn$1.output(GroupAlsoByWindowsParDoFn.java:184)

由于工作项过大,导致了此超时。在前面的示例中,以下两条建议可能会有所帮助。首先,您可以尝试启用 shuffle 服务(如果尚未启用)。其次,您可以尝试调整数据库读取中的配置,例如 maxPartitionspartitionSizeBytes。如需了解详情,请参阅 PartitionOptions 来尝试缩减工作项大小。您可以在此 Dataflow 模板中找到如何执行此操作的示例。

问题排查资源方面的其他截止日期已过

如果您在完成问题排查步骤后仍会看到 DEADLINE_EXCEEDED 错误,如果您遇到以下情况,请创建支持请求

  • Google Front End 延迟时间较长,但 Spanner API 请求延迟时间较短
  • Spanner API 请求延迟时间较长,但查询延迟时间较短

您也可以参考以下问题排查资源: