Percolator的流程

Percolator的流程

Content #

使用 Percolator 模型的前提是事务的参与者,即数据库,要支持多版本并发控制(MVCC)。

在转账事务开始前,小明和小红的账户分别存储在分片 P1 和 P2 上。

上图中的 Ming 代表小明,Hong 代表小红。在分片的账户表中各有两条记录,第一行记录的指针(write)指向第二行记录,实际的账户余额存储在第二行记录的 Bal. data 字段中。

Bal.data 分为两个部分,冒号前面的是时间戳,代表记录的先后次序;后面的是真正的账户余额。我们可以看到,现在小明的账户上有 4,900 元,小红的账户上有 300 元。

我们来看下 Percolator 的流程。

第一,准备阶段,事务管理器向分片发送 Prepare 请求,包含了具体的数据操作要求。

分片接到请求后要做两件事,写日志和添加私有版本。关于私有版本,你可以简单理解为,在 lock 字段上写入了标识信息的记录就是私有版本,只有当前事务能够操作,通常其他事务不能读写这条记录。

你可能注意到了,两个分片上的 lock 内容并不一样。

主锁的选择是随机的,参与事务的记录都可能拥有主锁,但一个事务只能有一条记录拥有主锁,其他参与事务的记录在 lock 字段记录了指针信息“primary@Ming.bal”,指向主锁记录。

准备阶段结束的时候,两个分片都增加了私有版本记录,余额正好是转账顺利执行后的数字。

第二,提交阶段,事务管理器只需要和拥有主锁的分片通讯,发送 Commit 指令,且不用附带其他信息。

分片 P1 增加了一条新记录时间戳为 8,指向时间戳为 7 的记录,后者在准备阶段写入的主锁也被抹去。这时候 7、8 两条记录不再是私有版本,所有事务都可以看到小明的余额变为 2,700 元,事务结束。

你或许要问,为什么在提交阶段不用更新小红的记录?

Percolator 最有趣的设计就是这里,因为分片 P2 的最后一条记录,保存了指向主锁的指针。其他事务读取到 Hong7 这条记录时,会根据指针去查找 Ming.bal,发现记录已经提交,所以小红的记录虽然是私有版本格式,但仍然可视为已经生效了。

当然,这种通过指针查找的方式,会给读操作增加额外的工作。如果每个事务都照做,性能损耗就太大了。所以,还会有其他异步线程来更新小红的余额记录,最终变成下面的样子。

Viewpoints #

From #

09|原子性:2PC还是原子性协议的王者吗?