如何在Spanner中有效地创建强有序序列?

时间:2018-12-05 12:33:27

标签: database-design google-cloud-platform google-cloud-spanner

Google Spanner建议不要将时间戳记或序号之类的内容用作主键或索引的初始部分,这从架构上来说很有意义。但是,根据我的要求,我确实需要某种方法来确保严格的“仅追加”行排序。

我正在使用Spanner对事件进行建模(与事件来源一样)。每个事件都有一个类别,一个流ID标识一个序列,在该序列中,事件之间必须严格进行相互排序,还有一些有效负载字段-从这里开始,我将忽略实际的有效负载。

天真的,可以这样建模:

| Category    | STRING       |
| Stream Id   | STRING       |
| Sequence Nr | INT64        |

(具有由类别,流ID,序列号组成的主键。)这将确保一个流的事件有很强的顺序。现在,由于某些类别具有许多与之相关的事件,而Spanner的最佳做法是使高位发生变化,因此最好将其翻转。每个“流”将包含相当少量的事件(数千个而不是数百万个),并将它们一起读取,以便于更好地分配数据并鼓励属于一个流的事件的局部性:

| Stream Id   | STRING       |
| Category    | STRING       |
| Sequence Nr | INT64        |

但是,由于我希望能够添加事件而不必读取当前状态来查找当前序列号,因此我希望使用时间戳记。

| Aggregate Id | STRING      |                         | 
| Category     | STRING      |                         |
| Timestamp    | TIMESTAMP   | allow_commit_timestamp  |

Spanner内置了一个提交时间戳,它将在实际处理事务时对其进行标记。但是最后一个问题是:

即使我在一个事务中提交多个事件,也可以如上所述表示数据并获得唯一的提交时间戳吗?

如果没有,是否可以通过添加其他列以确保顺序来确保采用其他严格的排序方式?

documentation指出:“提交时间戳记值不能保证唯一。写入非重叠字段集的事务可能具有相同的时间戳。写入重叠字段集的事务具有唯一的时间戳。 ” -但在这种情况下,我不清楚什么是“字段集”。

文档还指出,“提交时间戳使创建更改日志更加容易,因为时间戳可以强制更改日志条目的排序。”但是尚不清楚在多个并发写入者或同时写入多个事件的情况下,提交时间戳具有强制顺序的保证是什么。

1 个答案:

答案 0 :(得分:2)

如果您在同一个 transaction 中有多个事件,那么它们都将具有相同的提交时间戳。

字段是一个表格单元格(一行中有一个col值)。因此,在此上下文中,“非重叠字段集”基本上意味着单独的行,因为其中一个字段提交时间戳!

理论上,两个独立的事务(在同一张表上的一个更新行“ R1”和一个更新行“ R2”)可以具有相同的提交时间戳,因为它们不重叠。

  

即使我在一个事务中提交多个事件,也可以如上所述表示数据并获得唯一的提交时间戳吗?

在示例中,您在主键中提供了使用提交时间戳的位置,然后,没有,您将无法在单个事务中将多个事件添加到同一stream_id / category对中,因为它们将具有相同的时间戳-因此也是相同的主键。

  

如果没有,是否可以通过添加其他列以确保顺序来确保采用其他严格的排序方式?

如果您为每个(stream_id,category,timestamp)元组使用了提交时间戳一个序列号的组合,则可以在单个事务中保持严格的顺序:

为同一事务中的每个(stream_id,类别)对增加一个从0开始的序列号。 然后,提交时间戳将确保跨不同事务的顺序,而序号将确保在事务内的订单 ...