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的更多相关文章

  1. Google关于Spanner的论文中分布式事务的实现

    Google关于Spanner的论文中分布式事务的实现 Google在Spanner相关的论文中详细的解释了Percolator分布式事务的实现方式, 而且用简洁的伪代码示例怎么实现分布式事务; Pe ...

  2. MVCC/分布式事务简介

    之前我们学习了RocksDB,但这还只是一个最基础的存储引擎.如果想把它在生产环境中用起来,还需要解决很多问题: 如何从单机扩展到分布式? 如何实现事务,并对事务进行并发控制? 用户接口能不能高级一点 ...

  3. 数据库分布式事务XA规范介绍及Mysql底层实现机制

    1. 引言 分布式事务主要应用领域主要体现在数据库领域.微服务应用领域.微服务应用领域一般是柔性事务,不完全满足ACID特性,特别是I隔离性,比如说saga不满足隔离性,主要是通过根据分支事务执行成功 ...

  4. 群集中的MS DTC分布式事务协调器

    MS DTC在大多数SQL 服务器下都需要安装,若只是安装数据库引擎或Analysis 服务可不安装DTC.如果后需要使用分布式事务,则可在SQL Server群集安装完成后再安装DTC. 一.群集M ...

  5. 事务使用中如何避免误用分布式事务(System.Transactions.TransactionScope)

    1:本地事务DbTransaction和分布式事务TransactionScope的区别: 1.1:System.Data.Common.DbTransaction: 本地事务:这个没什么好说了,就是 ...

  6. 没有活动事务 链接服务器的 OLE DB 访问接口 "SQLNCLI" 无法启动分布式事务

    在windows2003下执行分布式事务的时候出现如下情况. 一. 问题现象在执行分布式事务时,在sql server 2005下收到如下错误: 链接服务器"xxxxxxx"的 O ...

  7. 已禁用对分布式事务管理器(MSDTC)的网络访问的解决方法之一

    C# ASP.NET项目提示上述错误,在代码中使用分布式事务提示添加或修改到数据库的时候.添加数据到数据库时,不会设置实体类的主键字段.

  8. 【转】PostgreSQL分布式事务配置

    XA是open group提出的分布式事务处理规范,JTA支持XA规范,JTA只规定了接口,有些应用容器提供实现,也有一些三方的开源实现可用,比如Atomikos. 如果PostgreSQL参与分布式 ...

  9. 分布式事务(一)两阶段提交及JTA

    原创文章,同步发自作者个人博客 http://www.jasongj.com/big_data/two_phase_commit/ 分布式事务 分布式事务简介 分布式事务是指会涉及到操作多个数据库(或 ...

随机推荐

  1. Spring整合Mybatis原理简单分析

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" ...

  2. Redis Cluster高可用集群在线迁移操作记录

    之前介绍了redis cluster的结构及高可用集群部署过程,今天这里简单说下redis集群的迁移.由于之前的redis cluster集群环境部署的服务器性能有限,需要迁移到高配置的服务器上.考虑 ...

  3. MyBatis JavaType JdbcType

    MyBatis 通过包含的jdbcType类型 BIT FLOAT CHAR TIMESTAMP OTHER UNDEFINED TINYINT REAL VARCHAR BINARY BLOB NV ...

  4. UVA 1605 Building for UN(思维)

    题目链接: https://cn.vjudge.net/problem/UVA-1605#author=0 /* 问题 设计一个包含若干层的联合国大厦,其中每一层都是等大的网格,每个格子分配给一个国家 ...

  5. MVC实现更新数据库的数据

    经过一系列MVC的练习,如数据库的数据显示,添加,删除等,还差一个功能,就是更新,那本次练习的是MVC对数据库的数据进行更新. 写好更新的存过程: 有了存储过程,可以写实体(Entity)的方法了.写 ...

  6. 创建第一个MVC应用程序

    整个国庆期假,Insus.NET没有出门,在家静心修炼MVC.这意味着Insus.NET将来的日子里会以MVC为学习,开发,应用作为重点,不过现在才开始踏出第一步...... 路慢慢...... 下载 ...

  7. AE开发

    using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...

  8. asp.net错误记录

    //登录 jquery-ajax post请求后台无法获取数据,get就可以!!!原因:get方法,后台接收用Request.QueryString["para1"];post方法 ...

  9. 撩课-Web大前端每天5道面试题-Day29

    1.https协议的优点? 使用HTTPS协议可认证用户和服务器, 确保数据发送到正确的客户机和服务器: HTTPS协议是由SSL+HTTP协议构建的可进行加密传输. 身份认证的网络协议,要比http ...

  10. HDFS 命令大全

    目录 概要 用户命令 dfs 命令 追加文件内容 查看文件内容 得到文件的校验信息 修改用户组 修改文件权限 修改文件所属用户 本地拷贝到 hdfs hdfs 拷贝到本地 获取目录,文件数量及大小 h ...