排查 Cloud Spanner 超出时限错误的问题

本页面简要介绍了 Cloud Spanner 的超出时限的错误消息:具体错误、错误原因以及如何排查和解决问题。

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

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

Cloud Spanner 的截止时间和重试理念

Spanner 的截止时间和重试理念与许多其他系统不同。 在 Spanner 中,您应将超时截止时间指定为响应可用的最长时间。不建议人为设置非常短的截止时间以立即立即重试同一操作,因为这会导致操作永远无法完成。在这种情况下,不建议使用以下策略和操作,它们会适得其反,并违背了 Spanner 的内部重试行为:

  • 设置的时间过短。这意味着,相关操作无法应对偶尔的尾延迟时间增加的情况,并且无法在超时之前完成。而是设置一个截止时间,该时限是响应有用的最长时间。

  • 设置的时限过长,并且在时限结束之前取消了操作。这会导致每次重试都浪费时间和工作量。总体而言,这可能会给实例造成大量的额外负载。

什么是超过时限的错误?

当您使用某个 Spanner 客户端库时,底层 gRPC 层负责通信、编组、取消编组和截止时间强制执行。通过时限,您的应用可以指定在多长时间后请求被终止,超过时限结束错误。

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

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

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

数据访问 API 问题

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

检查 Spanner 实例的 CPU 负载

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

解决方法

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

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

当请求从客户端传输到 Spanner 服务器并返回时,需要进行多次网络跳转:从客户端库到 Google 前端 (GFE);从 GFE 到 Spanner API 前端;最后从 Spanner API 前端到 Spanner 数据库。如果在上述任何阶段出现网络问题,您可能会看到超出时限的错误。

每个阶段都可以捕获延迟(请参阅延迟指南)。要详细了解如何使用诊断指南,请参阅如何诊断延迟问题

解决方法

获取延迟明细并诊断延迟问题后,您可以使用此问题排查延迟指南来确定延迟来源并了解发生的原因。

Data API 问题

Spanner 的某些非最佳使用模式可能会导致超过时限的错误。本部分介绍了如何检查这些非最佳使用模式。

检查代价高昂的查询

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

您可以使用查询统计信息表事务统计信息表检查成本高昂的查询。这些表格显示了运行缓慢的查询和事务的相关信息,例如平均读取行数、读取的平均字节数、扫描的平均行数等。此外,您可以生成查询执行计划,以进一步检查查询的执行情况。

解决方法

要优化查询,请参阅 SQL 查询最佳做法指南。 您还可以使用通过上述统计信息表和执行计划获得的数据来优化查询,以及对数据库进行架构更改。这些最佳做法有助于减少语句的执行时间,可能有助于避免超过时限的错误。

检查锁争用

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

您可以使用锁定统计信息表格并参阅以下博文,找到导致高延迟读写事务的根本原因。在锁定统计信息表中,您可以找到锁定时间最长的行键。

锁定冲突问题排查指南说明了如何查找正在访问锁定冲突相关列的事务。您还可以参照“使用事务代码进行问题排查”指南,了解锁定冲突涉及哪些事务。

解决方法

遵循这些最佳做法可减少锁争用。此外,对于普通的读取用例,请使用只读事务以避免与写入的锁定冲突。对于读写或混合读写工作流,应预留使用读写事务。遵循这些步骤应该能够缩短事务执行时间的总体延迟,并缩短超出时限的错误。

检查是否有未经优化的架构

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

解决方法

最佳架构设计取决于对数据库执行的读写操作。无论架构细节如何,均应遵循架构设计最佳做法SQL 最佳做法指南。遵循这些指南可避免最常见的架构设计问题。导致性能不佳的其他一些根本原因包括:选择主键、表布局(请参阅使用交错表以实现更快的访问速度)、架构设计(请参阅优化架构以实现性能)以及 Spanner 实例中配置的节点的性能(请参阅区域级限制多区域限制)。

检查热点

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

解决方法

如需解决此问题,请先参阅上一节检查未经优化的架构中列出的解决方案。重新设计数据库架构并使用交错索引以避免可能导致热点的问题。如果按上述步骤操作未能解决问题,请参阅“选择主键来阻止热点”指南。最后,应避免不太理想的流量模式,例如大范围读取,这样可能会导致基于负载的拆分。

检查配置有误的超时

客户端库为 Spanner 中的所有请求提供合理的超时默认值。但是,您可能需要针对您的特定工作负载调整这些默认配置。您需要注意查询成本,并根据您的特定用例调整截止时间。

解决方法

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

Admin API 问题

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

解决方法

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

Google Cloud Console 问题

从 Google Cloud Console 查询页面发出的查询不能超过五分钟。如果您创建的查询成本高昂,并且运行时间超过了五分钟,则会看到以下错误消息:

Cloud Console 超出时限的错误消息的屏幕截图

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

解决方法

您可以按照 SQL 查询最佳做法指南重写查询。

Dataflow 问题

在 Apache Beam 中,读取操作的默认超时配置为 2 小时,提交操作的默认超时配置为 15 秒。与独立客户端库的时限超时相比,这些配置可实现更长的操作。不过,如果工作项过大,可能仍会收到超时和截止时间错误。目前,只能在必要时自定义 Apache Beam 提交超时配置。

解决方法

如果步骤 ReadFromSpanner / Execute query / Read from Cloud 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)。如需了解详情,请参阅分区选项,以试用和缩减工作项的大小。有关如何执行此操作的示例可以在此 Dataflow 模板中找到。

超出问题排查期限

如果您在执行上述问题排查步骤后仍然看到截止期限错误,请使用以下细分来确定是否需要打开支持案例(请参阅问题排查延迟问题表中的完整支持列表)。总而言之,如果您遇到以下情况,请提交支持服务工单:

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

您还可以参阅以下问题排查资源: