跳到主要内容

综合概述

背景

随着互联网的不断普及特别是移动互联网的兴起,数据规模爆炸式增长,而硬件这些年的进步速度却在逐渐减慢,人们也在担心摩尔定律会失效。在此消彼长的情况下,单机数据库越来越难以满足用户需求,即使是将数据保存下来这个最基本的需求。

分布式数据库

所以 2005 年左右,人们开始探索分布式数据库,带起了 NoSQL 这波浪潮。这些数据库解决的首要问题是单机上无法保存全部数据,其中以 HBase/Cassadra/MongoDB 为代表。为了实现容量的水平扩展,这些数据库往往要放弃事务,或者是只提供简单的 KV 接口。存储模型的简化为存储系统的开发带来了便利,但是降低了对业务的支撑。

NoSQL的进击

HBase 是其中的典型代表。 HBase 是 Hadoop 生态中的重要产品,Google BigTable 的开源实现,所以这里先说一下 BigTable 。

BigTable 是 Google 内部使用的分布式数据库,构建在 GFS 的基础上,弥补了分布式文件系统对于小对象的插入、更新、随机读请求的缺陷。HBase 也按照这个架构实现,底层基于HDFS 。 HBase 本身并不实际存储数据,持久化的日志和 SST file 存储在 HDFS 上,Region Server 通过 MemTable 提供快速的查询,写入都是先写日志,后台进行Compact ,将随机写转换为顺序写。数据通过 Region 在逻辑上进行分割,负载均衡通过调节各个 Region Server 负责的Region区间实现,Region在 持续写入后,会进行分裂,然后被负载均衡策略调度到多个 Region Server 上。

前面提到了, HBase 本身并不存储数据,这里的 Region 仅是逻辑上的概念,数据还是以文件的形式存储在 HDFS 上,HBase 并不关心副本个数、位置以及水平扩展问题,这些都依赖于 HDFS 实现。和 BigTable 一样, HBase 提供行级的一致性,从 CAP 理论的角度来看,它是一个 CP 的系统,并且没有更进一步提供 ACID 的跨行事务,也是很遗憾。

HBase 的优势在于通过扩展 Region Server 可以几乎线性提升系统的吞吐,及 HDFS 本身就具有的水平扩展能力,且整个系统成熟稳定。但 HBase 依然有一些不足。首先, Hadoop 使用 Java 开发, GC 延迟是一个无法避免问题,这对系统的延迟造成一些影响。另外,由于HBase 本身并不存储数据,和 HDFS 之间的交互会多一层性能损耗。第三, HBase 和BigTable 一样,并不支持跨行事务,所以在 Google 内部有团队开发了 MegaStore 、 Percolator 这些基于 BigTable 的事务层。 Jeff Dean 承认很后悔没有在 BigTable 中加入跨行事务,这也是 Spanner 出现的一个原因。

RDMS 的救赎

除了 NoSQL 之外, RDMS 系统也做了不少努力来适应业务的变化,也就是关系型数据库的中间件和分库分表方案。做一款中间件需要考虑很多,比如解析 SQL ,解析出 ShardKey ,然后根据 ShardKey 分发请求,再合并结果。另外在中间件这层还需要维护 Session 及事务状态,而且大多数方案并不支持跨 shard 的事务,这就不可避免地导致了业务使用起来会比较麻烦,需要自己维护事务状态。此外,还有动态的扩容缩容和自动的故障恢复,在集群规模越来越大的情况下,运维和 DDL 的复杂度是指数级上升。

国内开发者在这个领域有过很多的著名的项目,比如阿里的 Cobar 、 TDDL ,后来社区基于Cobar 改进的 MyCAT , 360 开源的 Atlas 等,都属于这一类中间件产品。在中间件这个方案上有一个知名的开源项目是 Youtube 的 Vitess ,这是一个集大成的中间件产品,内置了热数据缓存、水平动态分片、读写分离等,但这也造成了整个项目非常复杂。

另外一个值得一提的是 PostgreSQL XC 这个项目,其整体的架构有点像早期版本的OceanBase ,由一个中央节点来处理协调分布式事务,数据分散在各个存储节点上,应该是目前 PG 社区最好的分布式扩展方案,不少人在基于这个项目做自己的系统。

关系型数据库中间件

RDMS的救赎就是关系型数据库中间件产生的原因。

NewSQL的发展

2012 ~ 2013 年 Google 相继发表了 Spanner 和 F1 两套系统的论文,让业界第一次看到了关系模型和 NoSQL 的扩展性在一个大规模生产系统上融合的可能性。 Spanner 通过使用硬件设备( GPS 时钟+原子钟)巧妙地解决时钟同步的问题,而在分布式系统里,时钟正是最让人头痛的问题。Spanner 的强大之处在于即使两个数据中心隔得非常远,也能保证通过TrueTime API 获取的时间误差在一个很小的范围内( 10ms ),并且不需要通讯。 Spanner 的底层仍然基于分布式文件系统,不过论文里也说是可以未来优化的点。

Google 的内部的数据库存储业务,大多是 3 ~ 5 副本,重要的数据需要 7 副本,且这些副本遍布全球各大洲的数据中心,由于普遍使用了Paxos ,延迟是可以缩短到一个可以接受的范围(写入延迟 100 ms以上),另外由 Paxos 带来的 Auto-Failover 能力,更是让整个集群即使数据中心瘫痪,业务层都是透明无感知的。 F1 是构建在 Spanner 之上,对外提供了 SQL 接口, F1 是一个分布式 MPP SQL 层,其本身并不存储数据,而是将客户端的 SQL 翻译成对KV 的操作,调用 Spanner 来完成请求。

Spanner 和 F1 的出现标志着第一个 NewSQL 在生产环境中提供服务,将下面几个功能在一套系统中提供:

  1. SQL 支持
  2. ACID 事务
  3. 水平扩展
  4. Auto Failover
  5. 多机房异地容灾

正因为具备如此多的诱人特性,在 Google 内部,大量的业务已经从原来的 BigTable 切换到Spanner 之上。相信这对业界的思路会有巨大的影响,就像当年的 Hadoop 一样, Google 的基础软件的技术趋势是走在社区前面的。 Spanner/F1 论文引起了社区的广泛的关注,很快开始出现了追随者。第一个团队是CockroachLabs 做的 CockroachDB 。 CockroachDB 的设计和 Spanner 很像,但是没有选择 TrueTime API ,而是使用 HLC( Hybrid logical clock ),也就是 NTP +逻辑时钟来代替 TrueTime 时间戳,另外 CockroachDB 选用 Raft 做数据复制协议,底层存储落地在RocksDB 中,对外的接口选择了 PG 协议。

CockroachDB 的技术选型比较激进,比如依赖了 HLC 来做事务,时间戳的精确度并没有办法做到 10 ms内的延迟,所以 Commit Wait 需要用户自己指定,其选择取决于用户的 NTP 服务时钟误差,这点对于用户来说非常不友好。当然 CockroachDB 的这些技术选择也带来了很好的易用性,所有逻辑都在一个组件中,部署非常简单,这个是非常大的优点。