一 简介
F1是Google提出的分布式关系型数据库,支持便捷的水平伸缩。这篇论文是NewSQL分布式数据库架构的基石。论文首先定义了F1分布式数据库设计的关键方向:
- 可伸缩性:数据库要提供对业务透明的水平扩展能力,并支持数据迁移、数据rebalance
- 可用性:提供高可用的数据服务
- 一致性:这里特指强一致性
- 易用性:需要支持索引、ad-hoc类查询接口
F1的设计理念是兼顾传统SQL数据库的功能完备于NoSQL数据库的灵活伸缩能力。
F1采用Spanner作为基础数据库(Google提出的分布式NoSQL数据库,后文介绍),并继承了Spanner数据库的特性。在此基础上,F1扩展出了分布式关系型数据库关键能力:
为了缓解分布式数据库引入到高时延,F1做了一些性能优化的工作,使得F1能在性能上和传统数据库持平。
- 通过数据schema定义让数据内聚,内举的数据相邻存放,提高了访存局部性,减少了RPC访问次数
- 由于F1的使用者大量使用批处理、并行处理、异步读取等操作,F1设计了新的ORM接口,可以限定一次查询内部RPC访问次数的上界
二 整体架构
Load Balancer 查询时,默认访问最近DataCenter,并在必要时执行负载均衡。 F1 Server F1 Server无状态(几乎)的数据查询服务,不存放任何数据,而是通过访问Spanner查询数据。 Slave Pool Slave Pool由F1进程组成,整个集群共享Slave Pool中的进程。 F1 Master 当计算并发度较高影响时延时,F1 Master会从Slave Pool中分配进程交给F1 Server管理。Slave进程会分担部分查询工作。F1 Master会监听Slave进程的状态。
三 数据模型
表层级结构
广告场景中“customer->canpaign->adgroup”的逐层一对多的表层级关系,抽象为root表和子表的模型。其中customer表为root表,campaign是customer的子表,adgroup是campaign的子表。
子表与其父表存放在一起(就好像子表是父表中的一列),这样存放有几点好处:
- 当想查询一个customer下的的所有adgroup时,只需要简单的range查找即可
- 当需要进行双表Join操作时,只需要利用有序数组合并的算法即可
- 更新时,由于同一个customer的数据存放在一起,可以避免单个更新操作引起Spanner集群事物同步
protobuf列类型
F1中对protobuf列类型做了很多扩展,可以将protobuf列看作是可嵌套的schema结构。F1在SQL语法上也做了相关的支持。 索引 支持本地索引和全局索引。 本地索引:在建立索引时,必须确定root表的主键值(如CustomerId),这样的设计是为了限定索引的覆盖范围,避免跨机器构建与查询。 全剧索引:无需指定root表主键值,但是性能会比较差,尤其是面对大批量事务操作时
四 Schema变更
F1支持schema变更有很大挑战,有如下几个原因:
- F1是一个庞大的分布式数据库,其数据中心扩地域分布
- schema结构加载在本地内存中,很难保证跨机器原子更新
- 在schema变更时,需要保证查询和事务持续进行
- 系统的可用性和时延不能收到schema变更的影响
为了避免造成不可接受的影响,schema变更采用分批更新模式,即不同F1 Server上使用的schema可能不一样。 同时,为了解决schema不兼容变更导致数据库崩溃的问题,F1也做了一些设计:
- 每个Server至少加载两个schema版本,但是只使用其中一个对外提供服务;当时机合适的时候,会释放旧版本schema
- 两阶段提交:先更新schema,然后准备好数据,最后再提供服务
五 事务
F1支持三种事务:
- 快照
这是一种只读事务,使用方可以指定时间戳获取特定的数据版本。 - 悲观事务
- 乐观事务
F1在每行数据中隐式插入了一个行锁,行写入时会记录当前更新的时间戳;当执行批量事务时,会加一个短周期的悲观锁,用来依次校验时间戳是否重冲突,一旦冲突,则事务提交失败
F1默认使用乐观锁,但是乐观锁有两个问题:
- 乐观锁依赖于行锁,而只有已经存在的行,才能加锁;当数据中出现新增行时,可能出现数据覆盖
- 当并发度比较高时,吞吐量低
支持使用方自定义列簇锁
行锁本质上是对一行中的所有列加锁。F1也支持使用方通过自定义“列子集锁”,这样可以增加并发吞吐。
六 修改历史记录
F1会记录所有的变更操作,这写记录有很多变种用法:
- 用于通知变更
类似于DB的bin log。 - 用于更新Client缓存
客户端会缓存数据库的部分状态。客户端可以通过监听变更记录来更新缓存。
七 客户端设计
F1客户端支持ORM接口、SQL接口和NoSQL接口。
八 查询处理
F1查询时会根据Query执行中心查询或者分布式查询,上述例子是一个分布式查询的例子。F1会将SQL解析成多个步骤,执行类似于MapReduce的拆解和聚合。在查询时,所有的数据访问均为远程访问。
在访问时,时延主要来源于两个地方:网络和磁盘吞吐。其中网络的延迟可以通过批访问和流水线访问来缓解;磁盘延迟通常是因为硬件吞吐量限制,而F1底层使用的CFS分布式存储,吞吐量量得到了保障。
|