分布式事务实现-Percolator
Google为了解决网页索引的增量处理,以及维护数据表和索引表的一致性问题,基于BigTable实现了一个支持分布式事务的存储系统。这里重点讨论这个系统的分布式事务实现,不讨论percolator中为了支持增量计算而实现的Notifications机制。
该系统基于BigTable,支持snapshot isolation隔离级别,这个隔离级别不在ANSI定义的隔离级别范围内。简单来说,就是一个事务看到的是一个stable的数据库的快照。快照隔离相对于可串行化隔离级别的优点是更高的读性能,不需要加锁,MVCC基于BigTable的多版本机制。缺点是有write skew问题,简单来说,对于两个事务T1:b=a+1和T2:a=b+1,初始化a=b=0。串行化的情况下,结果只可能是(a=2,b=1)或者(a=1,b=2),而在快照隔离级别下,结果可能是(a=1,b=1)。这在某些业务场景下是不能接受的。既然有多版本,就需要有版本号,percolator系统使用一个全局递增时间戳服务器来为事务产生时间戳,每个事务开始时拿一个时间戳t1,那么这个事务执行过程中可以读t1之前的数据。提交时再取一下时间戳t2,作为这个事务的提交时间戳。
现在说分布式事务。说起分布式事务第一个想到的就是两阶段提交,这个系统也不例外。客户端作为协调者coordinator,BigTable的tablet server作为参与者participant。 除了实际的表的每个Cell的数据存在BigTable中外,coordinator还将Cell锁信息,事务版本号存在BigTable中。简单来说,如果需要写列C,在BigTable中实际存在三列,分别为C:data,C:lock,C:write。由于BigTable实际上定位一个Value需要三个信息,rowkey,column和timestamp,所以实际上一个 column本身内部可以看成一个timestamp->value的map。那么:
1. c:write中存事务提交时间戳commit_ts=>start_ts。
2. c:data这个map中存事务开始时间戳start_ts=>实际列数据
3. c:lock存start_ts=>(primary cell),primary cell是rowkey和列名的组合,它在两阶段提交容错处理和事务冲突时使用,用来清理由于coordinator失败导致的分布式事务失败留下的锁信息。
举个没有任何冲突例子,假设一个分布式事务T1需要修改两个Cell,C1(Rowkey1:C1)和C2(Rowkey2:C2),C1为primary cell,Value分别为Value1和Value2,并且两个Cell处于不同的tablet server,serverA和serverB。客户端commit之前首先将两个Cell都加入到客户端本地的一个数组中,最后事务commit(包括两阶段的prepare和commit)的时候才将所有Cell发向tablet server。
没有检测到冲突的写事务流程:
prepare阶段:
1. 分布式事务T1启动,从全局时间戳服务器获取事务启动时间戳记作t1_start_ts。
2. 首先写primary cell C1,往C1:data中写入t1_start_ts=>value1,往C1:lock中写入t1_start_ts=>primary cell 表示加锁,同理,写serverB,往C2:data中写入t1_start_ts=>value2, 往C2:lock中写入t1_start_ts=>primary cell
commit阶段:
1. 从全局时间戳服务器获取事务提交时间戳记作t1_commit_ts。
2. 启动一个C1所在的BigTable行事务,包含以下两个操作
2.1 往primary cell C1:write写入t1_commit_ts=>t1_start_ts(这步是关键)
2.2 将primary cell的lock release(delete C1:lock,时间戳为t1_start_ts)
3. Commit这个BigTable 事务,这一步实际上将这个事务的数据对外可见,因为随后的一个读事务(事务启动时间戳记作t2_start_ts)读C1之前,会首先读C1:write的小于t2_start_ts的最大的版本的数据获得t1_start_ts,然后拿着t1_start_ts才能去C1:data中读取真正的数据。
4. 将其他secondary cell C2:write中写入t1_commit_ts=>t1_start_ts,release C2的lock
没有检测到冲突的读C1和C2的事务T3流程:
1. 从全局时间戳服务器获取事务提交时间戳记作t3_start_ts
2. 分别读C1和C2,读C:write的比t3_start_ts小的最大的一个事务提交时间戳的事务启动时间,然后拿这个事务启动时间去C:data中读真正的数据。
可以看出,一个Cell对外可见是通过写C:write来达到的,t1_commit_ts为事务提交版本号,t1_start_ts为t1这个事务修改后的数据版本号,真正读数据需要拿到t1_start_ts,而读t1_start_ts又需要首先拿到t1_commit_ts。
协调者(Client)宕机容错
假设C1上锁失败,C2上锁成功,那么分布式事务失败会将C2的锁残留在BigTable中。这个残留的锁由后续第一个读或写C2的事务来清除,满足什么样的条件才能清除?满足以下两个条件中的一个即可:1. 写这个lock的客户端在chubby上的结点没了,即客户端死了 2. C2:lock这把锁滞留时间太长了(lock内部保存最后更新时间即可)。 cleanup的操作就是直接delete C2:lock即可,时间戳为t2_start_ts_(percolator论文中此处有笔误)。但是如何知道残留下这个锁的事务是否已经提交?这就需要去读C2的primary cell的write字段,在这个例子里就是读C1:write,记残留下来的锁C2:lock的时间戳为lock_ts(percolator论文这里说的不清楚),那么具体的判断事务是否提交的操作就是读取C1:write的[lock_ts,正无穷)的所有版本,判断是否有一个版本的值是lock_ts,如果有,则说明残留锁的事务已经提交。
事务冲突
Prepare阶段冲突:写C1之前需要首先读取C1:lock,如果有任何一个版本被加上了锁,那么这次分布式事务失败。还有一种冲突是,有其他事务在本事务开始之后commit修改了C1,从而修改了C1:write,这是一种Snapshot isolation需要避免的写写冲突。
Commit阶段冲突:分布式事务提交需要先提交primary cell,再提交其他cell,再提交primary cell时需要先检查自己是否还拿住了primary cell的锁,在这里是C1:lock,即t1_start_ts_版本是否已经被删除。做这个判断的原因是其他事务可以cleanup这个lock,如果它认为这个事务握有锁时间过长或者写入lock的客户端宕机太慢等原因。在这里,primary cell的lock字段是其他事务进行cleanup操作和当前事务提交操作的同步点。
参考资料:
http://static.googleusercontent.com/media/research.google.com/en/us/pubs/archive/36726.pdf
https://github.com/XiaoMi/themis/
分布式事务实现-Percolator的更多相关文章
- Google关于Spanner的论文中分布式事务的实现
Google关于Spanner的论文中分布式事务的实现 Google在Spanner相关的论文中详细的解释了Percolator分布式事务的实现方式, 而且用简洁的伪代码示例怎么实现分布式事务; Pe ...
- MVCC/分布式事务简介
之前我们学习了RocksDB,但这还只是一个最基础的存储引擎.如果想把它在生产环境中用起来,还需要解决很多问题: 如何从单机扩展到分布式? 如何实现事务,并对事务进行并发控制? 用户接口能不能高级一点 ...
- 数据库分布式事务XA规范介绍及Mysql底层实现机制
1. 引言 分布式事务主要应用领域主要体现在数据库领域.微服务应用领域.微服务应用领域一般是柔性事务,不完全满足ACID特性,特别是I隔离性,比如说saga不满足隔离性,主要是通过根据分支事务执行成功 ...
- 群集中的MS DTC分布式事务协调器
MS DTC在大多数SQL 服务器下都需要安装,若只是安装数据库引擎或Analysis 服务可不安装DTC.如果后需要使用分布式事务,则可在SQL Server群集安装完成后再安装DTC. 一.群集M ...
- 事务使用中如何避免误用分布式事务(System.Transactions.TransactionScope)
1:本地事务DbTransaction和分布式事务TransactionScope的区别: 1.1:System.Data.Common.DbTransaction: 本地事务:这个没什么好说了,就是 ...
- 没有活动事务 链接服务器的 OLE DB 访问接口 "SQLNCLI" 无法启动分布式事务
在windows2003下执行分布式事务的时候出现如下情况. 一. 问题现象在执行分布式事务时,在sql server 2005下收到如下错误: 链接服务器"xxxxxxx"的 O ...
- 已禁用对分布式事务管理器(MSDTC)的网络访问的解决方法之一
C# ASP.NET项目提示上述错误,在代码中使用分布式事务提示添加或修改到数据库的时候.添加数据到数据库时,不会设置实体类的主键字段.
- 【转】PostgreSQL分布式事务配置
XA是open group提出的分布式事务处理规范,JTA支持XA规范,JTA只规定了接口,有些应用容器提供实现,也有一些三方的开源实现可用,比如Atomikos. 如果PostgreSQL参与分布式 ...
- 分布式事务(一)两阶段提交及JTA
原创文章,同步发自作者个人博客 http://www.jasongj.com/big_data/two_phase_commit/ 分布式事务 分布式事务简介 分布式事务是指会涉及到操作多个数据库(或 ...
随机推荐
- idea terminal 修改为git bash 不支持中文
1.idea terminal 修改为git bash 由于IDEA自带的Terminal工具是Windows命令窗口cmd,在开发过程中需要用到一些常用的命令操作时要不断的在IDEA和git bas ...
- Vue + Element UI 实现权限管理系统 前端篇(二):Vue + Element 案例
导入项目 打开 Visual Studio Code,File --> add Folder to Workspace,导入我们的项目. 安装 Element 安装依赖 Element 是国内饿 ...
- 简单Demo 使用Code Fisrt步骤
使用Code Fisrt步骤 1.开启VS,创建控制台项目:CodeFirstDemo1 2.利用NuGet引进 Entity Framework类库 图住:右击项目名称,在弹出的选 ...
- spring StopWatch用法
背景 有时我们在做开发的时候需要记录每个任务执行时间,或者记录一段代码执行时间,最简单的方法就是打印当前时间与执行完时间的差值,然后这样如果执行大量测试的话就很麻烦,并且不直观,如果想对执行的时间做进 ...
- 【转】CSS选择器笔记
作者: 阮一峰 日期: 2009年3月12日 来源:http://www.ruanyifeng.com/blog/2009/03/css_selectors.html 去年我学jQuery的时候,曾经 ...
- PBN飞越转弯Flyover衔接DF航段保护区组图
PBN飞越转弯Flyover衔接DF航段,是飞越转弯中最常用的形态. Flyover-DF保护区叠加图: Flyover-DF保护区分解图:
- UIKit 框架之UIActionSheet
UIAlertView和UIActionSheet相似,区别很小, 很容易理解. // // ViewController.m // UIActionSheet // // Created by Ci ...
- C# 四舍五入 保留两位小数(转载)
一.C#默认四舍五入 1 Math.Round(45.367,2) //Returns 45.372 Math.Round(45.365,2) //Returns 45.36二.C#中的Round() ...
- Redis哨兵(sentinel)模式搭建
一.Sentinel介绍 之前骚了一波Redis的简介及应用场景,今天试了下他的哨兵模式: Sentinel是Redis的高可用性(HA)解决方案,由一个或多个Sentinel实例组成的Sentine ...
- redis服务部署脚本
yum install -y gcc jemalloc-devel cd /usr/local/src curl -L -O http://download.redis.io/releases/red ...