会话

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

会话概览

本页面介绍了 Spanner 中会话的高级概念,包括创建客户端库、使用 REST 或 RPC API 或使用 Google 客户端库时会话的最佳做法。

会话表示与 Spanner 数据库服务的通信通道。会话用于执行在 Spanner 数据库中读取、写入或修改数据的事务。每个会话只应用于单个数据库。

会话一次只能执行一个事务。独立读取、写入和查询在内部使用事务,并计入一个事务限制。

会话缓存的性能优势

创建会话的开销很大。为了避免每次进行数据库操作时影响性能,客户端应该保留“会话缓存”,这是准备就绪可供使用的可用会话池。缓存应存储现有会话,并响应请求返回适当类型的会话,以及清理未使用的会话。如需查看有关如何实现会话缓存的示例,请参阅其中一个 Spanner 客户端库(例如 Go 客户端库Java 客户端库)的源代码。

会话设计为长期有效,因此在某会话用于数据库操作之后,客户端应将该会话返回到缓存,以供重复使用。

使用 Google 客户端库时的最佳做法

下面介绍了在 Spanner 中使用 Google 客户端库的最佳做法。

配置会话数

一般来说,我们不建议修改客户端库使用的默认会话数。

如果您有一个特殊的工作负载,我们建议将下限设置为预期的并发事务数,并将上限设置为初始测试数,例如 100。如果上限不够,请提高上限。增加活跃会话的数量会在 Spanner 数据库服务上使用额外的资源,因此不清理未使用的会话可能会降低性能。我们还建议每个 gRPC 通道的会话数不超过 100。

管理写入会话比例

对于大多数客户端库,Spanner 会为读写事务保留一部分会话,称为“写入会话比例”。如果您的应用用尽所有读取会话,则 Spanner 会使用读写会话,甚至适用于只读事务。读写会话需要 spanner.databases.beginOrRollbackReadWriteTransaction 权限。如果用户具有 spanner.databaseReader IAM 角色,则调用失败,并且 Spanner 会返回以下错误消息:

generic::permission_denied: Resource %resource% is missing IAM permission:
spanner.databases.beginOrRollbackReadWriteTransaction

对于维持写入会话比例的客户端库,您可以对其进行设置。

C++

所有 C ++ 会话都相同。没有只读或只读写会话。

C#

C# 的默认写入会话比例是 0.2。您可以使用 SessionPoolOptions 的 WriteSessionsFraction 字段更改比例。

Go

Go 的默认写入会话比例为 0.2。您可以使用 SessionPoolConfig 的 WriteSessions 字段更改比例。

Java

所有 Java 会话都相同。没有只读或只读写会话。

Node.js

Node.js 的默认写入会话比例是 0(零)。您可以使用 writes 字段来更改比例。

PHP

所有 PHP 会话都是相同的。没有只读或只读写会话。

Python

Python 支持四种不同的会话池类型,可用于管理读取和读写会话。

Ruby

Ruby 的默认写入会话比例是 0.3。您可以使用 client 初始化方法更改比例。

创建客户端库或使用 REST/RPC 时的最佳做法

下面介绍了在 Spanner 的客户端库中实现会话或者通过 RESTRPC API 使用会话的最佳做法。

这些最佳做法仅在您开发客户端库或使用 REST/RPC API 的情况下适用。如果您使用的是 Cloud Spanner 的 Google Cloud 客户端库之一,请参阅使用 Google 客户端库时的最佳做法

创建会话缓存并确定其大小

要确定某客户端进程的会话缓存的最佳大小,请将下限设置为预期的并发事务数,并将上限设置为初始测试数(例如 100)如果上限不够,请提高上限。增加活跃会话的数量会在 Spanner 数据库服务上使用额外的资源,因此不清理未使用的会话可能会降低性能。对于使用 RPC API 的用户,我们建议每个 gRPC 通道的会话数不超过 100。

处理已删除的会话

可以通过以下三种方式删除会话:

  • 客户端可以删除会话。
  • Spanner 数据库服务可以在会话处于空闲状态超过 1 小时时删除会话。
  • 如果某个会话的存在时间超过 28 天,Spanner 数据库服务可能会删除该会话。

尝试使用已删除的会话会导致 NOT_FOUND 错误。如果您遇到此错误,请创建和使用新会话,将新会话添加到缓存中,并从缓存中移除已删除的会话。

使空闲会话保持活跃状态

Spanner 数据库服务保留丢弃未使用的会话的权利。如果您确实需要让空闲会话保持活跃状态,例如,在预计数据库使用近期内会显著增长的情况下,您可以防止会话被删除。执行开销较小的操作(例如,执行 SQL 查询 SELECT 1)可使会话保持活跃状态。如果您有近期不需要的空闲会话,可以让 Spanner 丢弃该会话,然后在下次需要会话时创建新会话。

让会话保持活动状态的一种情况是应对数据库上的常规高峰需求。如果每天的上午 9:00 到下午 6:00 大量使用数据库,则应在这段时间内保留一些空闲会话,因为高峰使用期间可能需要这些会话。下午 6:00 以后,您可以让 Spanner 丢弃空闲会话。在每天上午 9:00 之前,请创建一些新会话,以便它们能够满足预期需求。

另一种情况是,如果您的应用使用 Spanner,但必须在使用时避免连接开销,您可以将一组会话保持活动状态以避免连接开销。

向客户端库用户隐藏会话详细信息

如果您正在创建客户端库,请勿将会话曝露给客户端库使用者。让客户端能够进行数据库调用,但无需涉及会话创建和维护的复杂性。如需查看对客户端库使用方隐藏会话详细信息的客户端库示例,请参阅适用于 Java 的 Spanner 客户端库。

处理非幂等写入事务的错误

没有重试保护的写入事务可能会多次应用变更。 如果某一变更不具有幂等性,则多次应用变更可能会导致失败。例如,即使在写入尝试之前某行不存在,插入操作也可能会失败并出现 ALREADY_EXISTS 错误。如果后端服务器提交了变更但无法将成功信息传达给客户端,则可能发生这种情况。在这种情况下,可能会重试变更,导致 ALREADY_EXISTS 失败。

在实现您自己的客户端库或使用 REST API 时,可以采用以下方法来应对这种情况:

  • 设计您的写入代码结构,使其具有幂等性。
  • 对写入使用重试保护。
  • 实现一个执行“upsert”逻辑的方法:若是新的则插入,若已存在则更新。
  • 代替客户端处理错误。

保持稳定连接

为获得最佳性能,用于承载会话的连接应保持稳定。当托管会话的连接发生更改时,Spanner 可能会中止会话中的活跃事务,并在更新会话元数据时对数据库产生少量额外负载。少数连接偶尔发生变化是无关紧要的,但应避免同时更改大量连接的情况。如果您在客户端和 Spanner 之间使用代理,则应保持每个会话的连接稳定性。

监控活跃会话

您可以从命令行、通过 REST APIRPC API 使用 ListSessions 命令,监控数据库中的活跃会话。ListSessions 可显示给定数据库的活跃会话。如果您需要查明会话泄漏的原因,这一命令非常有用。(会话泄漏是指系统创建会话,但未将其返回到会话缓存以重复使用的突发事件。)

借助 ListSessions,您能够查看有关活跃会话的元数据,包括创建会话的时间以及上次使用会话的时间。在排查会话问题时,分析此数据可以为您指明正确的方向。如果大多数活跃会话没有最近的 approximate_last_use_time,这可能表明会话没有被您的应用合理地重复使用。如需详细了解 approximate_last_use_time 字段,请参阅 RPC API 参考文档

如需详细了解如何使用 ListSessions,请参阅 REST API 参考文档RPC API 参考文档gcloud 命令行工具参考文档