Spanner

Summary

spanner最大的特点就是两个: 1. 利用2 phase commit与 2 phase locking的策略,保证了写事务的一致性。同时在做2 phase commit的时候又利用了Paxos的High Available的特点 2. 只读的时候利用了True Time可以轻量的从replica读出来。

2-phase commit 与 paxos

spanner

图片描述 我们有一个xaction需要执行。

   BEGIN
   x = 3
   y = 4
   END

如图所示,我们有三个数据中心DC1, DC2, DC3. 以及有两个group x,y 分别横跨这3个DC. 我们不妨同时把 Y group的 Leader作为 two-phase commit的Coordinator 写事务

  1. Client 发送写请求给各个group的leader,不妨把Y的leader设为Coordinator,并把这个消息告诉所有leader。
  2. 除了Coodinator之外的其它leader,获取写锁,replica之间按照paxos协议,把写请求的log给写到replica去。
  3. 各个leader把自己的执行情况返回给Coordinator。
  4. 当Coordinator收到了所有leader的commit之后,获取写锁,然后paxos协议尝试把log写到replica。
  5. coordinator这组commit之后,就发送commit信息给其他leader与client。(这里用到了two-phase commit 里的 early commit, 否则应该在收到其他的leader的第二次回复的YES之后才发送commit给client。)释放所有的锁。

2PC 2PL保证事务的ACID,同时利用paxos,防止万一leader挂了,还能自己选出一个新的leader保证了HA.

其实如果不考虑读的问题,只考虑写的问题的话,锁就足够满足ACID这些特性了。但是如何做到可以从replica读取可靠数据呢?直接读?那就会存在如果那个replica是一个minority,那么就可能读到过期的数据。那么就需要利用时间戳来处理,但是spanner是一个分布式存储。不像单机很容易可以构造出一个单调递增的数来作为TimeStamp,为了解决这个问题,spanner引入了TrueTime,作为时间戳。下文将会粗略的介绍一下True Time与如何利用他来保证读的可靠性。

True Time

TrueTime的具体原理先忽略它,总之是利用了GPS以及原子钟等技术,暂且当做一个黑盒。就假设每个机房有一个机子T有一个准确的TrueTime的程序,对于其它的单独的某一台机器,我想知道一个具体时间,就得向T发送请求,然后T把请求发回来,但是由于可能T的程序是异步的,以及网络延迟等理由,当T返回的时间被收到的时候,实际时间可能已经流走了。所以就每次请求了之后,都是返回一个区间[earliest, lastest] 按照论文的写法TrueTime有3个API:

method Returns
TT.now() TT interval: [earliest, lastest]
TT.after(t) true if t has definitey passed,我的理解是 t < TT.now().earliest
TT.before(t) true if t has definitely not arrived; t > TT.now().latest

read only

为了read 的时候能够利用上TimeStamp,我们就需要在写的时候给事务打上TS,以及读的时候也给读这个事务打上TS,才可以根据TS的先后关系,读取出正确的数据。