春招Percolator分布式事务总结(个人向)

Percolator是什么

Percolator模型是谷歌在2012年提出的用于优化在Bigtable上存储大规模的网页索引信息的更新提出的基于2PC思想的分布式事务模型,是对2PC模式的优化。Perco-lator主要是用在对延迟要求不高的大规模数据集上的分布式事务模型,Percolator使用ACID快照隔离语义提供跨行跨表事务,它采用乐观的事务模型,即如果出现冲突,则将回滚代价较小的事务进行回滚。

Percolator的实现

Percolator建立在Bigtable分布式存储系统之上。Bigtable为用户呈现一个多维排序的映射:键是(行,列,时间戳)元组。 Bigtable在每一行上提供查找和更新操作,而Bigtable行事务可以对单个行进行原子读-修改-写操作。

Percolator使用Bigtable中的时间戳维度,对每个数据项都存储多版本,以实现快照隔离。在一个事务中,按照某个时间戳读取出来的某个版本的数据就是一个隔离的快照,然后再用一个较迟的时间戳写入新的数据。

比如说上面事务2看不到事务1,事务3能看到事务1, 2。

快照隔离的主要优势在于更高效的读取。因为任何时间戳都代表一个一致的快照,读取一个单元只需要在给定的时间戳上执行一个Bigtable查询,不需要获得锁。

传统的DBMS的事务主要是通过锁对硬盘数据读写的控制,但是在分布式的Bigtable上,任意的结点都可以提交数据,这就要维护一个显式的,持久化到文件系统中的锁。同时因为在集群中进行锁的访问的操作会有很多,所以锁必须轻量级以实现高吞吐量。借助Bigtable的单行事务,可以把锁和数据放在同一行中。访问某行数据时Percolator将在一个Bigtable行事务中对同行的锁执行读取和修改。

写操作

我们用论文中的一个图说明一下一个跨行事务的过程。


第一步:事务首先进入预写阶段(Prewrite)选一个Primary Line写入时间戳7和锁的记录,标记自己是Primary Lock,然后写入新值到数据中;
第二步:事务在另一个需要修改的行中写入锁信息,标记自己不是Primary Lock,并指出Primary Lock是Bob。写入新数据。引入Primary Lock的目的是把冲突点从多行变成单行。
第三步:写入了全部的锁之后,Percolator进入提交阶段(Commit),它会拿到一个新的commit时间戳8,然后写入在这个时刻提交的事务是时间戳7的事务。时间戳是8后面的事务可以看到最新的数据。
第四步:清理这两行上的锁。

现在我们来讨论一下冲突的出现。

Prewrite阶段:出现了写-写冲突,即另一个事务在访问这一行的时候发现了该行已经有写入标记了,且写入标记的时间戳在这个时间戳的事务之后,说明有事务正在写这一行。如果发现该行在任意时刻有锁,则说明有事务在提交之后推迟了锁的释放,或者其他事务仍在操作这一行,这个事务也会进行abort。如果都没有冲突,才进行锁和新数据的写入。从这里就能看出Percolator是乐观事务模型。
Commit阶段:Commit阶段主要是检查锁是否还存在,如果当前事务的时间戳的锁已经不存在了,Percolator将会取消提交。在Primary Lock提交之后,其他的行继续进行提交。提交之后的数据可以被它之后的事务可见。

读操作

读操作将检查目标行在它之前是否存在锁,如果存在,说明有比它更早事务正在修改,必须等待锁释放。然后读取最近时间戳的写记录,并返回这个时间戳的数据。

特殊情况的出现

相较于2PC,Percolator减少了协调者的节点,把客户端作为协调者,客户端的故障有可能引发问题。

如果一个客户端在提交阶段出故障导致锁不能被清除,这一行将永远被锁住。为了解决这个情况,Percolator将清理这些锁,Percolator使用的思路是等下一个写这行的事务检查这个锁是否有效,如果无效则清理这个锁。因此需要一种算法使得锁的状态可以被确定。

判断一个锁是不是有效时,我们需要指定一个同步点,由这个同步点确定事务是否正常,这个同步点就是上述的Primary Lock。操作Primary Lock由Bigtable的单行事务保证,另一个事务要清理时,会尝试操作Primary Lock,此时如事务仍在正常执行,另一个事务就会知道这个锁的时间戳不属于自己,就不进行清理。
如果这个事务的Primary Lock已经替换成了写记录,此时如果另外的事务读到了该事务的Primary Lock已经处于提交状态,它就会把该事务另外的锁也替换成写记录进行提交。如果Primary Lock已经没了,说明发生了回滚,则回滚剩余的数据并清除锁。

安全性

事务协议使用严格增加的时间戳来保证 Get 在事务的开始时间戳之前返回所有已提交的写写操作。举个例子,如果一个事务R在时间戳TR执行读操作,事务W在时间戳TR执行提交,并且TW < TR。此时W在R读取之前就写入了全部的锁,R事务不能读取数据,所以R事务要么看到锁,只能在这些锁释放之后才能读取数据,要么看到已提交的数据。

Reference

[1]https://www.cnblogs.com/luozhiyun/p/15376890.html
[2]https://zhuanlan.zhihu.com/p/307438297
[3]https://zhuanlan.zhihu.com/p/439305971

posted @   codexyz  阅读(296)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示