本页面简要介绍了 Cloud Spanner 截止时间超出错误,包括错误、错误原因以及如何排查和解决错误。
访问 Spanner API 时,请求可能会因 DEADLINE_EXCEEDED
错误而失败。此错误表示在配置的超时期限内未收到响应。
可能会因为许多不同的原因(例如过载的 Spanner 实例、未优化的架构或未经优化的查询)导致超出截止时间的错误。本页面介绍了截止期限超过错误的常见情况,并针对如何调查和解决这些问题提供了指南。
Cloud 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 和截止时间。
如何调查和解决超出时限的常见错误
数据访问 API 问题
您必须针对您的特定工作负载正确配置 Spanner 实例,以避免数据访问 API 问题。以下部分介绍了如何调查和解决不同的数据访问 API 问题。
检查 Spanner 实例的 CPU 负载
当 CPU 利用率超过建议的状况良好判断阈值时,请求延迟时间会明显增加。您可以在 Google Cloud 控制台提供的监控控制台中检查 Spanner CPU 的利用率。您还可以根据实例的 CPU 利用率创建提醒。
解决方法
如需了解降低实例的 CPU 利用率的步骤,请参阅降低 CPU 利用率。
检查请求的端到端延迟时间细分
当请求从客户端传输到 Spanner 服务器并返回时,需要进行多个网络跳转:从客户端库到 Google 前端 (GFE);从 GFE 到 Spanner API 前端;最后从 Spanner API 前端到 Spanner 数据库。如果在上述任何阶段出现网络问题,您可能会看到截止期限错误。
可以在每个阶段捕获延迟时间(请参阅延迟时间指南)。如需详细了解如何使用诊断指南,请参阅如何诊断延迟时间问题。
解决方法
获取延迟明细并诊断延迟问题后,您可以参考此问题排查延迟问题指南来找出延迟的原因并了解发生的原因。
数据 API 问题
Spanner 的数据 API 的某些非最佳使用模式可能会导致超出期限错误。本部分将指导您如何检查这些非最佳使用模式。
检查成本高昂的查询
如果尝试运行未在客户端库的已配置超时期限内执行且成本高昂的查询,可能会导致超出时限错误。开销大的查询的一些示例包括但不限于:对大型表进行完整扫描、对多个大型表进行交叉联接,或者对谓词对非键列执行查询(也称执行全表扫描)。
您可以使用查询统计信息表和事务统计信息表检查费用高昂的查询。这些表格显示了运行缓慢的查询和事务的相关信息,例如读取的平均行数、平均读取的字节数、扫描的平均行数等等。此外,您可以生成查询执行计划,以进一步检查查询的执行情况。
解决方法
如需优化查询,请参阅 SQL 查询最佳做法指南。 您还可以使用通过上述统计信息表和执行计划获得的数据来优化查询并更改数据库的架构。这些最佳做法有助于缩短语句的执行时间,并有助于消除超出截止时间的错误。
检查锁争用
Spanner 事务需要获取锁定才能提交。以高吞吐量运行的应用可能导致事务争用相同的资源,从而导致等待锁的等待时间增加,并影响整体性能。这可能会导致任何读取或写入请求的截止时间超过。
您可以使用锁定统计信息表并参阅以下博文,找到导致高读写读写操作的根本原因。在锁定统计信息表格中,您可以找到最长锁定等待时间的行键。
此锁定冲突问题排查指南说明了如何查找正在访问锁冲突中涉及的列的事务。您还可以参阅使用事务标记进行问题排查指南,了解锁定冲突中涉及哪些事务。
解决方法
应用这些最佳做法以减少锁争用。此外,对于普通的读取用例,请使用只读事务以避免与写入的锁定冲突。应为读写或混合读写工作流预留使用读写事务。遵循这些步骤应该能够缩短事务执行时间的总体延迟时间,并减少超出时限的错误。
检查未优化的架构
在为 Spanner 数据库设计最佳数据库架构之前,应考虑要在数据库中执行的查询类型。次优架构可能会导致在运行某些查询时出现性能问题。这些性能问题可能会导致请求无法在配置的时限内完成。
解决方法
最佳架构设计将取决于对数据库执行的读写操作。无论架构细节如何,都应遵循架构设计最佳做法和 SQL 最佳做法指南。遵循这些指南可以避免最常见的架构设计问题。导致性能不佳的其他一些根本原因是以下原因:您的主键选择、表布局(请参阅使用交错表加快访问速度)、架构设计(请参阅优化架构以实现性能)以及 Spanner 实例中配置的节点的性能(请参阅单区域限制或多区域限制)。
检查热点
由于 Spanner 是一个分布式数据库,因此架构设计需要考虑以防止出现热点。例如,创建单调递增的列会限制 Spanner 能够均匀分配工作负载的分片数量。这些瓶颈可能会导致超时。此外,您还可以利用 Key Visualizer 排查热点导致的性能问题。
解决方法
如需解决此问题,请参阅上一部分中检查未优化的架构部分中列出的解决方法。请重新设计您的数据库架构,并使用交错索引来避免可能导致热点的更改的索引。如果按照上述步骤操作后仍无法解决问题,请参阅“选择主键以防使用热点”指南。 最后,避免使用不太理想的流量模式,例如大范围读取,这样可能会阻止基于负载的拆分。
检查是否有配置有误的超时
客户端库为 Spanner 中的所有请求提供了合理的超时默认值。但是,可能需要根据您的具体工作负载调整这些默认配置。您需要考虑查询费用,并根据您的具体使用场景调整截止期限。
解决方法
超时默认设置适用于大多数用例。用户可以覆盖这些配置(请参阅自定义超时和重试指南),但建议不要使用比默认超时更积极的超时。如果您决定更改超时,请将其设置为应用愿意等待结果的实际时间。您可以尝试更长的超时时间,但不要设置比应用愿意等待的实际时间短的超时时间,否则会导致该操作的重试频率更高。
Admin API 问题
与数据 API 请求相比,Admin API 请求成本高昂。CreateInstance
、CreateDatabase
或 CreateBackups
等管理员请求可能需要几秒钟才能返回响应。Spanner 客户端库为实例和数据库管理员请求设置的时限为 60 分钟。这是为了确保服务器有机会在客户端重试或失败之前完成请求。
解决方法
如果您使用 Google Spanner 客户端库访问 Admin API,请确保该客户端库已更新并使用最新版本。如果您是直接通过您创建的客户端库访问 Spanner API,请确保没有针对实例和数据库管理员请求的默认设置(60 分钟)设置过于激进。
Google Cloud 控制台问题
从 Google Cloud 控制台查询页面发出的查询不能超过五分钟。如果您创建的运行成本高昂的查询运行时间超过五分钟,您将看到以下错误消息:
后端将取消失败的查询,并且事务可能会在必要时回滚。
解决方法
您可以遵循 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 服务(如果尚未启用)。其次,您可以尝试调整数据库读取操作中的配置,例如 maxPartitions
和 partitionSizeBytes
。如需了解详情,请参阅 PartitionOptions 以尝试缩减工作项的大小。您可以在此 Dataflow 模板中找到关于如何执行此操作的示例。
超出问题排查问题排查截止日期
如果您在执行上述问题排查步骤后仍然看到截止期限错误,请使用以下细分来确定是否需要打开支持请求(请参阅问题排查延迟问题表中的完整支持请求列表)。总而言之,如果您遇到以下情况,请创建支持服务工单:
- Google Front End 延迟时间较长,但 Spanner API 请求延迟时间较短
- Spanner API 请求延迟时间较长,但查询延迟时间较短
您还可以参阅以下问题排查资源: