本页概述了 Spanner“已超出截止期限”错误:此类错误是什么、为什么会发生,以及如何排查和解决这些错误。
在访问 Spanner API 时,请求可能会因 DEADLINE_EXCEEDED
错误而失败。此错误表示在配置的超时期限内未收到响应。
“已超出截止期限”错误可能由多种原因引起,例如 Spanner 实例过载、架构未优化或查询未优化。本页面介绍了发生“已超出截止期限”错误的常见场景,并提供了有关如何调查和解决这些问题的指南。
Spanner 的截止期限和重试理念
Spanner 的截止期限和重试理念不同于许多其他系统。在 Spanner 中,您应将超时截止期限指定为响应仍然有效的最长时间。不建议人为设置过短的截止期限,以便立即重试同一操作,因为这会导致操作永远无法完成。在这种情况下,不建议采用以下策略和操作;它们不仅适得其反,还会破坏 Spanner 的内部重试机制:
设置过短的截止期限。这意味着该操作无法应对偶发的尾部延迟时间增加,因此无法在超时之前完成。应改为设置一个截止期限,即响应仍然有效的最长时间。
设置过长的截止期限,但在截止期限到达前就取消操作。这会导致每次尝试都触发重试,造成资源浪费。总而言之,这可能会给您的实例带来显著的额外负载。
什么是“已超出截止期限”错误?
当您使用某个 Spanner 客户端库时,底层 gRPC 层会负责通信、编组、解组和截止期限强制执行。截止期限机制允许应用指定请求的最长等待时间,若超时未完成,系统将终止相应请求并返回“已超出截止期限”错误。
超时配置指南演示了如何在每个受支持的 Spanner 客户端库中指定截止期限(或超时时间)。Spanner 客户端库使用在以下配置文件中定义的默认超时和重试策略设置:
- spanner_grpc_service_config.json
- spanner_admin_instance_grpc_service_config.json
- spanner_admin_database_grpc_service_config.json
如需详细了解 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 问题
与 Data API 请求相比,Admin API 请求属于开销较大的操作。CreateInstance
、CreateDatabase
或 CreateBackups
等管理员请求可能需要等待许多秒才能返回响应。Spanner 客户端库为实例和数据库管理员请求设置了 60 分钟的截止期限。这是为了确保服务器有机会在客户端重试或失败之前完成请求。
解决方法
如果您使用 Google Spanner 客户端库来访问管理员 API,请确保该客户端库已更新并使用最新版本。如果您通过自己创建的客户端库直接访问 Spanner API,请确保您的实例和数据库管理员请求的截止期限设置不比默认设置(60 分钟)更激进。
Google Cloud 控制台问题
从 Google Cloud 控制台 Spanner Studio 页面发出的查询的运行时间不得超过 5 分钟。如果您创建的查询开销较大,其运行时间超过 5 分钟,系统将显示以下错误消息:
后端会取消失败的查询,并可能会在必要时回滚事务。
解决方法
您可以按照 SQL 查询最佳实践指南重写查询。
Dataflow 问题
在 Apache Beam 中,读取操作的默认超时时间配置为 2 小时,提交操作的默认超时时间配置为 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 服务(如果尚未启用)。其次,您可以尝试调整数据库的读取配置,例如 maxPartitions
和 partitionSizeBytes
。如需了解详情,请参阅 PartitionOptions
,尝试减小工作项大小。如需查看相关示例,请参阅此 Dataflow 模板。
其他有关排查“已超出截止期限”问题的资源
如果在完成问题排查步骤后仍看到 DEADLINE_EXCEEDED
错误,并遇到以下情况,请创建支持请求:
- Google Front End 的延迟时间较长,但 Spanner API 请求延迟时间较短
- Spanner API 请求延迟时间较长,但查询延迟时间较短
您还可以参阅以下问题排查资源: