时间戳边界

简介

在 Spanner 的 只读事务单次读取调用,您可以设置时间戳边界, 告知 Spanner 如何选择读取数据的时间戳。

为什么要设置时间戳边界?如果您的数据库分布在不同地理位置(即,您使用多区域实例配置创建 Spanner 实例),并且您的应用在读取数据时可以容忍过时,那么您可以通过执行过时读取而非强读来获取延迟优势。(参阅读取了解更多关于这些读取类型的信息。)

时间戳边界类型

时间戳边界有以下几个类型:

  • 强(默认):读取最新数据。
  • 有界限过时:读取未超过过时界限的数据版本。
  • 精确过时:读取具有精确时间戳的数据版本,例如过去的某个时间点,您也可以将时间戳指定为尚未过去的时间。(如果您指定未来时间戳,Spanner 将在执行读取之前等待该时间戳。)

注意:

  • 尽管使用这些时间戳边界模式的读取操作不是读写事务的一部分,但它们可以阻塞等待提交并发读写事务。有界限过时读取尝试选择时间戳以避免阻塞,但阻塞仍会发生。

  • 过时读取(即使用有界限或精确过时类型)在最长过期间隔内具有最大性能优势。使用最小 10 秒的过时以获得优势。

  • Spanner 跟踪数据库的 earliest_version_time,用于指定可以读取过往版本数据的最早时间。您无法在最早版本时间之前的时间戳读取。

下文更详细地介绍了 Spanner 时间戳边界类型。

强一致性

Spanner 提供了强读的边界类型。强读可以保证在读取开始之前观察到已提交的所有事务的影响。此外,由单次读取产生的所有行彼此一致 - 如果读取的任何部分观察到事务,则读取的所有部分均会观察到事务。

强读不可重复:如果存在并发写入,则两个连续强只读事务可能会返回不一致的结果。如果需要跨读取的一致性,则读取应该在同一事务中或在精确读取时间戳执行。

有界限过时

Spanner 为有界限过时提供了一种边界类型。通过有界限过时模式,Spanner 可以根据用户提供的过时界限选择读取时间戳。Spanner 会在 过时边界,它允许在距离最近的可用时间 副本数量。

产生的所有行彼此一致 - 如果读取的任何部分观察到事务,则读取的所有部分均会观察到事务。有界限过时的读取不可重复:两个过时读取即使使用相同的过时界限,也可以在不同的时间戳执行读取,并返回不一致的结果。

与精确过时读取相比,有界限过时读取通常会慢一点。

精确过时

Spanner 提供精确过时的边界类型。这些时间戳边界在用户指定的时间戳执行读取操作。在时间戳读取可确保观察到全局事务记录的一致前缀:它们观察所有提交时间戳小于或等于读取时间戳的事务所做的修改,并且不观察具有较大提交时间戳的事务所做的修改。读取将阻塞,直到所有可能被分配的提交时间戳小于或等于读取时间戳的冲突事务完成。

时间戳可以表示为绝对的 Spanner 提交时间戳,或相对于当前时间的过时。

这些模式不需要“协商阶段”来选择时间戳。因此,它们的执行速度要比等效的有界限过时并发模式稍快一些。另一方面,有界限过时读取通常会返回更新的结果。

最大时间戳过时

Spanner 不断对已删除和覆盖的数据进行垃圾回收 以回收存储空间。此过程称为版本 GC。版本 GC 会在超过数据库的 version_retention_period(默认为 1 小时,但最长可配置为 1 周)而到期后回收版本。此限制也适用于那些仍在进行中,但时间戳在执行过程中已超时的读取和/或 SQL 查询。使用超时的读取时间戳的读取和 SQL 查询会失败,并显示错误 FAILED_PRECONDITION。唯一的例外情况是使用分区令牌分区读取/查询,这有助于防止会话活动期间对过期数据进行垃圾回收。