Spanner要满足的external consistency 是指:后开始的事务一定可以看到先提交的事务的修改。所有事务的读写都加锁可以解决这个问题,缺点是性能较差。特别是对于一些workload中只读事务占比较大的系统来说不可接受。为了让只读事务不加任何锁,需要引入多版本。在单机系统中,维护一个递增的时间戳作为版本号很好办。分布式系统中,机器和机器之间的时钟有误差,并且误差范围不确定,带来的问题就是很难判断事件(在本文,事件指分布式事务版本号)发生的前后关系。反应在Spanner中,就是很难给事务赋予一个时间戳作为版本号,以满足external consistency。在这样一个误差范围不确定的分布式系统时,通常,获得两个事件发生的先后关系主要通过在节点之间进行通信分析其中的因果关系(casual relationship),经典算法包括Lamport时钟等算法。然后,Spanner采用不同的思路,通过在数据中心配备原子钟和GPS接收器来解决这个误差范围不确定的问题,进而解决分布式事务时序这个问题。基于此,Spanner提供了TrueTime API,返回值实际为一个区间[t-ε,t+ε],ε为时间误差,毫秒级,保证当前的真实时间位于这个区间。

Spanner是一个支持分布式读写事务,只读事务的分布式存储系统,只读事务不加任何锁。和其他分布式存储系统一样,通过维护多副本来提高系统的可用性。一份数据的多个副本组成一个paxos group,通过paxos协议维护副本之间的一致性。对于涉及到跨机的分布式事务,涉及到的每个paxos group中都会选出一个leader,来参与分布式事务的协调。这些个leader又会选出一个大leader,称为coordinator leader,作为两阶段提交的coordinator,记作coordinator leader。其他leader作为participant。

数据库事务系统的核心挑战之一是并发控制协议。Spanner的读写事务使用两阶段锁来处理。分布式读写事务请求到达coordinator leader后,coordinator leader运行两阶段提交协议,将读写请求发给participant,pariticpant和coordinator leader开始加读,写锁。最后commit的时候,读写锁解除。

如第一段所述,给事务赋予一个时间戳版本号是这样一个分布式存储系统的核心。下面先说如何确定读写事务的版本号,再说只读事务。

前面已经说了两阶段提交过程中两阶段锁的过程,这里就省略这些,只讨论两阶段提交过程中如何确定最后的读写事务的时间戳版本号。

读写事务

读写事务开始时,coordinator leader 首先调用TrueTime API,获得一个时间区间[t1-ε1,t1+ε1],然后给所有的participants发送prepare消息,participants收到prepare消息后,调TrueTime API返回区间[PB,PE],然后取PB和这个participants维护的已commit的事务版本号的最大值。记participant维护的已commit的最大事务时间戳为maxtimestamp,那么将max(maxtimestamp+1, PB)返回给coordinator leader。coordinator leader收集到所有prepare的时间戳后,从中选出一个最大的,记作maxpreparetimestamp,同时coordinator需要再次调用一次TrueTime API,获得时间区间[t2-ε2,t2+ε2],为了保证这个分布式事务的时间戳确实位于这个分布式事务执行过程中的某个点,coordinator leader必须为这个分布式事务选择一个介于[t1+ε1,t2-ε2]的时间戳。显然这需要t1+ε1 < t2-ε2.可以看出,Spanner必须等到t1+ε1 < t2-ε2成立之后,才能提交这个事务。另外,这个分布式事务的时间戳还必须满足一个条件,就是大于maxpreparetimestamp。从B的角度来看,如果本地已提交事务版本号比要读的版本号大,就可以读。这就要保证后面提交的单机事务和分布式事务版本号都要比现在已提交事务的版本号更大。否则,读的时候可能会有事务插进来,导致都到的数据可能不是一个快照。

另外,一台机器在收到快照读时,有可能需要阻塞。举个例子,在分布式系统中,即有分布式事务也有单机事务,以A,B,C为例,A为coordinator leader,B和C为participant,以B为例,假设B当前维护的本机最大的commit时间戳为100,现在从A来了一个分布式事务T1的prepare请求,B返回了101给A,在这个分布式事务commit之前,B机器来了一个单机事务T2,并且先于T1提交,时间戳为105,而A可能为这个分布式事务指定的版本号为104. 显然,如果在T1提交前来了一个大于101比如110的快照读事务,这个快照读事务必须被阻塞住直到T1提交才能向客户端返回结果,因为B不知道T1这个还未commit的事务最后的时间戳是多少。

只读事务

一种方法是询问一边所有的participants,从所有的commit timestamp中拿出最大的作为时间戳去读即可。或者调用TrueTime API,将右区间作为只读事务的版本号即可。

下面说一下两阶段提交的错误处理。

两阶段提交协议由于协调者和参与者的故障可能会有严重的可用性问题。Spanner的两阶段提交实现基于Paxos协议,每个participant和coordinator本身产生的日志都会通过Paxos协议复制到自身的Paxos group中,从而解决可用性问题。同样以A,B,C三份数据为例,他们分别有三个副本,记作(A1,A2,A3),(B1,B2,B3),(C1,C2,C3),每组作为一个Paxos group,内部通过paxos协议保证一致性。假设,A1,B1,C1分别为各自paxos group的leader,A1为coordinator leader。

 

Prepare阶段:A1给B1和C1发送prepare消息后,假设B1挂了,A1等待超时,A1给C1发送rollback。B1后续回滚分为两种情况:1. B1在持久化prepare消息之前挂了,B1恢复后可自行回滚 2. 如果B1持久化prepare消息之后挂了,B1自身可以回放日志得知事务未决,主动联系(A1,A2,A3)。A1给B1,C1发送prepare消息之后,自己挂了,同样,A1通过回放日志可以得知。实际上,A1本身挂了之后,A2和A3通过选主协议马上会选出一个新的leader,不至于影响到可用性。

Commit阶段:A1给B1,C1发送commit消息,B1 commit成功,C1挂了,C1起来后,如果C1之前没有持久化commit消息,则A1主动要求C1继续commit。如果C1之前已经持久化了commit消息,则自己commit。如果C1由于某些原因,始终commit不成功,则由上层业务进行回补操作

分布式事务实现-Spanner的更多相关文章

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

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

  2. 分布式数据库Google Spanner原理分析

    Spanner 是Google的全球级的分布式数据库 (Globally-Distributed Database) .Spanner的扩展性达到了令人咋舌的全球级,可以扩展到数百万的机器,数已百计的 ...

  3. 全球级的分布式数据库 Google Spanner原理

    开发四年只会写业务代码,分布式高并发都不会还做程序员?->>>    Google Spanner简介 Spanner 是Google的全球级的分布式数据库 (Globally-Di ...

  4. DTCC 2019 | 深度解码阿里数据库实现 数据库内核——基于HLC的分布式事务实现深度剖析

    摘要:分布式事务是分布式数据库最难攻克的技术之一,分布式事务为分布式数据库提供一致性数据访问的支持,保证全局读写原子性和隔离性,提供一体化分布式数据库的用户体验.本文主要分享分布式数据库中的时钟解决方 ...

  5. 数据库内核——基于HLC的分布式事务实现深度剖析

    DTCC 2019 | 深度解码阿里数据库实现 数据库内核--基于HLC的分布式事务实现深度剖析-阿里云开发者社区 https://developer.aliyun.com/article/70355 ...

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

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

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

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

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

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

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

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

随机推荐

  1. HDU Herding

    F - Herding Time Limit:1000MS       Memory Limit:32768KB      64bit IO Format:%I64d & %I64u Subm ...

  2. day01(RESTful Web Service、SVN)

    今日大纲 搭建SSM环境 基于SSM环境实现用户管理系统 学习RESTful Web Service 学习SVN 统一开发环境 JDK1.7 32? 64? -- 64 Eclipse 使用4.4.1 ...

  3. 第13天 JSTL标签、MVC设计模式、BeanUtils工具类

    第13天 JSTL标签.MVC设计模式.BeanUtils工具类 目录 1.    JSTL的核心标签库使用必须会使用    1 1.1.    c:if标签    1 1.2.    c:choos ...

  4. 4-jQuery - AJAX post()

    说明 POST 一般用于向后台发送数据,但也可用于从服务器获取数据.不过,POST 方法不会缓存数据,并且常用于连同请求一起发送数据. 格式 $.post(URL,data,callback); // ...

  5. iOS二维码条形码的制作

    - (IBAction)creatQRImage:(id)sender { [self.textField resignFirstResponder]; //这里是我放了个TextField的控件,但 ...

  6. 区块链Readme.md

    #Welcome to Azure Blockchain Projects This Repo host Azure related blockchain and distributed ledger ...

  7. WEB前端开发中的图片压缩

    web前端开发中,图片的重要性不言而喻,而由于一些图片的大小加上现在国内的网速不给力等种种原因,我们非常有必要对网站使用的图片进行压缩,压缩图片必然会带来图片质量的损失,我们要尽可能的在质量降低很小的 ...

  8. 设置 SSH 免密码登陆——仍提示输入密码

    1)生成密钥:在根目录下(cd  ~/   用户根目录)执行如下语句: ssh-keygen -t dsa -P ' ' -f ~/.ssh/id_dsa 以上是两个单引号. 2)将id_dsa.pu ...

  9. 双击td字段,出现编辑文本框(更改之后发送数据请求) jsp

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head ...

  10. struts入门学习(二)

    一  struts的各种视图的转发与重定向 1 struts跳转到指定的JSP页面,只需要修改配置文件 <package name="user" namespace=&quo ...