spanner 的前世今生

本文涉及的产品
对象存储 OSS,20GB 3个月
阿里云盘企业版 CDE,企业版用户数5人 500GB空间
对象存储 OSS,恶意文件检测 1000次 1年
简介: spanner的前身是big table,让我们先来看看big table这个老子的方方面面,然后再来看看儿子spanner为啥一出世就吸引了全球技术人员的眼球。 2006年,google 发表了big table [1]的文章,为什么要做big table,下面有一个简短的总结[2]: 就

spanner的前身是big table,让我们先来看看big table这个老子的方方面面,然后再来看看儿子spanner为啥一出世就吸引了全球技术人员的眼球。

2006年,google 发表了big table [1]的文章,为什么要做big table,下面有一个简短的总结[2]:


就是一个问题:数据太多,访问量太大,规模问题出现。规模是问题的源泉,是后续故事的核心,在此基础上才碰到了动态schema(semi-structure带来的问题,比如big table支持的schema change),全局可用,数据一致读写等问题。

big table的数据模型是 <row, column, timestamp> -> cell content ,每个cell都是一个三维空间中的一个点,每个维度都是动态可配置的(行可以随意增加,列可以随意增加,时间序列可以随意增加),非常灵活自由。

big table 的系统架构,解决数据和访问在一个cluster内部如何分配:将数据分片,每台tablet server load 若干分片,有一个核心节点master来做全局信息同步。



在big table 论文发布之后,big table一直在改进,主要是致力于提供更好的scalability;加入了跨cluster(一般是跨机房的cluster)的数据异步复制以及Coprocessor(HBase的coprocess应该也是从这里引入)。

 

google 大哥在成长,工程师需要更好用的结构化存储,big table 看来在以下几个方面做的不够好:

1. 分布式transaction:比如A给B发送了一个消息,那么A的发件箱和B的收件箱应该同时有一封信件,这是一个完整的事务,应该遵循事务的ACID原则,但是big table无法支持,其只支持single-row-transactions。这也也好理解,在啥都没有的情况下,big table的出世就足以让人兴奋,谁会为分布式transaction伤脑筋呢?不过日子越过越好,人们的要求也越来越高,这件事情就逃避不掉了。

2. 强一致性数据同步:即使某些用户不要求分布式transaction,那么强一致性也是希望提供的,也就是说在数据没有同时主、备集群写入之前,不要返回client成功的消息。应用有此需求也容易理解,如果你主集群写完就返回,然后主集群挂了,我最新的数据不是丢了吗?

3. SQL语言支持:大家都很懒

4. 全球负载均衡:负载均衡是个很大的话题,包括存储负载(存储空间全球数据中心共享)、调度负载(在全球数据中心内平衡CPU/MEM利用)、网络负载(在全球数据中心内平衡网络流量)、距离负载(让数据紧贴应用进行全球移动)

 

不得不说,系统真的是一步步进步的,人们的需求真的是一步步提高的,如果不是big table做出来,这些问题估计没人敢想。也正是因为这些问题的存在,Spanner[3]横空出世。

看看spanner解决了哪些问题:

Spanner is Google’s scalable, multi-version, globally distributed, and synchronously-replicated database

Spanner’s main focus is managing cross-datacenter replicated data, providing externally consistent [16] reads and writes, and
globally-consistent reads across the database.

最核心的是两点:

1. 分布式transaction

2. 全球自动化负载均衡(细粒度切分和全球数据复制都是为这个目的服务的)

Spanner 体系架构:

A Spanner deployment is called a universe. 全球只有三个spanner,分别用于测试、开发/生产(VS dark launching from Facebook ?)和生产。

Spanner is organized as a set of zones, where each zone is the rough analog of a deployment of Bigtable. 全球big table 集群(类比)被统一管理,统一调度起来就是spanner。

The universe master is primarily a console that displays status information about all the zones for interactive debugging. universe master并不是用来服务系统的,更像是个管理工具。

 

 

 tablet和paxos state machine共存,多个互为replica的tablet和paxos state machine形成了paxos group,其中有一个是leader,也就是用于写的tablet,保管lock table等。该leader同时也是一个transaction manager,用于实现分布式transaction。当实现分布式transaction时候,有不止一个paxos group参与进来,这时候有一个group会被选作coordinator group,则该group的leader就是coordinator leader,该group的slave就是coordinator slave。(这部分跟Spanner没多少关系,是distributed transaction的经典内容)

在big table中,tablet只是行数据的容器,tablet内部的行都是一视同仁的;而spanner对tablet进行了进一步的结构划分,多了一层dictionary结构,用以区分那些PK前缀相同的行(比如,所有以Alice开头的行都在一个dictionary里面)。dictionary是数据复制和placement配置的基本单位,比如某个dictionary要分布在亚洲和美洲,共4份拷贝。

spanner中负载均衡的最小单位也是dictionary,同时提供方法MoveDir可以手动将一个dictionary移动到指定的zone。文中提到dictionary只是一层抽象目录,下面还有fragment才是真正的物理目录,有点诧异。细粒度当然可以更加优化负载均衡以及数据恢复,但是太细的粒度也意味着复杂度成倍增加,这是不是值得呢?可能的原因是某些用户的dictionary目录里面数据还是太多,而同时反正分布式transaction已经实现,不同fragment之间交互也顺便可以借点光,没有增加太多的实现负担,不过我仍然感觉到这点做的太复杂了。

另外,文中虽然没写,根据之前的一些资料,dictionary应该也是权限控制的最小单元。

 

关于数据模型:

关于big table 不实现传统transaction的理由是:我们认为这些transaction太复杂,程序员会过度使用transaction从而导致性能太差,所以不实现。

而这里spanner实现传统的transaction的理由是:系统的职责是实现应该有的功能,如果程序员用错了,那么改正就行了;但是如果系统不实现,谁也没办法用。

上面应该是经典的需求实现问题,不同的人会有不同的理解。

spanner的行模型是 (key:string, timestamp:int64) -> row content,可以看到跟big table的模型最大的不同是这里强化了row的概念,不再突出column;这样spanner的timestamp是赋给整行数据的,是有物理意义的,这使得spanner更像一个实现多版本并发的数据库,而在big table中,timestamp仅仅用于保存多个版本的key-value,跟并发完全无关;我觉得这也是为什么spanner称自己为semi-relational 数据库,而big table只称自己是semi-structure 数据库的原因。

下面是spanner的数据表模式,其中user是一张父亲表,album一张子表(不存在没有user的album),这非常像一个树形结构,user树枝,blbum是树叶,多么清晰,好的东西都是易于理解的,大部分时候也是难于实现的。

 

关于TrueTime:只要知道两点就可以了:

1. 一堆机器投票来决定当前时间应该是多少,然后按人头计数,人多者胜。

2. 跟传统投票不同的是,每个人不是报来一个数字,而是根据一般误差报上一个范围来,比如A报[3-4], B 报[4-5], C报[3-5],结果就会变成4,因为每人都同意现在是4点。再详细的话请看原论文吧。

 

并发控制:

1. 对于什么是external consistency, 我理解不深,觉得就当成serializable transaction的一种实现协议,和基于lock的、基于MVCC啥的并列,就可以了。解释:provides the illusion that each operation applied by concurrent processes takes effect instantaneously at some point between its invocation and its response, implying that the meaning of a concurrent object's operations can be given by pre- and post-conditions. 

2. 一个paxos group内的leader通过投票选出来,通过不停的延长lease继续担当leader的角色,文中提到paxos group内任何两个paxos leader必须保证disjointness invariant,这是为什么呢?因为每个leader都要给自己这个group内执行的transaction分配一个timestamp, 如果两个leader的interval有重叠,那么就不能保证所有leader在分配timestamp时候全局单调递增。其实就是说,咱们俩一人一个时间段,这个时间段内的时间点随便我们分配,只要我们各自保证分配的时间单调递增,则咱俩都是单调递增的。

3. 文中一堆时间,简单抽象一下就是:spanner不依靠事件通信来保证transaction一致性,而是依靠严格的时间序列。

一个极端简单的例子:某个partition内部最新commit的一个transaction的完成时间是3点,当前还有两个transaction继续在执行,不知道什么时候结束,那么如果这时候有一个读请求过来,那么我们只能认让这个读的请求看到(visible)3点之前的数据,因为3点之后的数据可能只写了一半,是不允许读的。那么文中那么多的时间序列和假设就是为了保证读请求过来的时候,我们能准确的找到3点这个数字。很容易?如果是单机当然容易,如果有一堆机器参与了分布式transaction,找到3这个数字并不是轻而易举。

4. 几种操作

读写操作:最典型的操作,基于锁的并发控制,只不过使用乐观锁,如果出现冲突,某些低优先级的transaction先终止(系统会自动再重试),高优先级的先完成。在准备写之前,依然是决定timestamp,如果不是分布式transaction,则自己选一个时间就可以了;如果是分布式transaction,则同时收取所有participant的建议,选一个最大的,再跟cooperator自己的now比较选个大的,继续向下进行。

只读操作:跟上面举的例子类似,就是找个最近刚commit的transaction的时间点,然后返回该时间点之前写入的数据。值得注意的是,这时候,因为所有的replica都已经完成了写入,所以该时间点只要找到了之后,可以随便挑一个replica进行读。

SnapshotRead:这就不用说了,时间点都省的找了,client会提供;不过如果client提供的时间点还未到来呢?根据系统实现可以选择报错或者block,不过我想报错更合理吧,读取未来数据的业务没见过。

 

这部分transaction看起来复杂,因为主要是细节问题,宏观问题都是清楚明白的。

 

不得不说,Google的创新力很可怕,Spanner恐怕两年内不会有开源的实现,因为其不仅依靠软件、而且依靠硬件,更主要的是,开源界可能没有那么紧迫的需求推动。


逐步搬之前的文章过来:http://www.cnblogs.com/raymondshiquan/articles/2697956.html


[1] Bigtable: A Distributed Storage System for Structured Data

[2] jeff notes 2009

[3] Spanner

相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
XML Java 数据格式
常用的xpath
常用的xpath
114 0
|
4月前
|
SQL Java 数据库
什么是 PagingAndSortingRepository?
【8月更文挑战第21天】
100 0
|
5月前
|
存储 Java 数据库
JPA中@ElementCollection使用
JPA中@ElementCollection使用
72 0
|
6月前
PAT 1001 和 1002 A+B问题
PAT 1001 和 1002 A+B问题
|
7月前
|
机器学习/深度学习 人工智能 算法
PAI-TorchAcc
AI加速引擎PAI-TorchAcc
78 5
|
7月前
|
SQL 分布式计算 数据库
ApacheHudi使用问题汇总(二)
ApacheHudi使用问题汇总(二)
120 0
|
7月前
|
缓存 Java API
深入理解JPA
深入理解JPA
209 0
3.3 Path
3.3 Path
84 0
|
XML Java 数据库连接
parameterType是必须写的吗?
xml中没有配置parameterType,但是这是正确的,因为mybatis能自动识别,但返回值类型不能不写,因为mybatis需要将获得结果封装到相应的类中,查询的字段与类的属性需要一致。
419 0
parameterType是必须写的吗?