天天看点

细说分布式数据库的过去、现在与未来

随着大数据这个概念的兴起以及真实需求在各个行业的落地,很多人都热衷于讨论分布式数据库,今天就这个话题,主要分为三部分:第一部分讲一下分布式数据库的过去和现状,希望大家能对这个领域有一个全面的了解;第二部分讲一下tidb的架构以及最近的一些进展;最后结合我们开发tidb过程中的一些思考讲一下分布式数据库未来可能的趋势。

一、分布式数据库的历史和现状

1、从单机数据库说起

关系型数据库起源自1970年代,其最基本的功能有两个:

把数据存下来;

满足用户对数据的计算需求。

第一点是最基本的要求,如果一个数据库没办法把数据安全完整存下来,那么后续的任何功能都没有意义。当满足第一点后,用户紧接着就会要求能够使用数据,可能是简单的查询,比如按照某个key来查找value;也可能是复杂的查询,比如要对数据做复杂的聚合操作、连表操作、分组操作。往往第二点是一个比第一点更难满足的需求。

在数据库发展早期阶段,这两个需求其实不难满足,比如有很多优秀的商业数据库产品,如oracle/db2。在1990年之后,出现了开源数据库mysql和postgresql。这些数据库不断地提升单机实例性能,再加上遵循摩尔定律的硬件提升速度,往往能够很好地支撑业务发展。

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

2、分布式数据库

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

(1)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出现的一个原因。

(2)rdms的救赎

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

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

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

3、newsql的发展

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

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

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

sql支持

acid事务

水平扩展

auto failover

多机房异地容灾

正因为具备如此多的诱人特性,在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来做事务,时间戳的精确度并没有办法做到10ms内的延迟,所以commit wait需要用户自己指定,其选择取决于用户的ntp服务时钟误差,这点对于用户来说非常不友好。当然 cockroachdb的这些技术选择也带来了很好的易用性,所有逻辑都在一个组件中,部署非常简单,这个是非常大的优点。

另一个追随者就是我们做的tidb。这个项目已经开发了两年时间,当然在开始动手前我们也准备了很长时间。接下来我会介绍一下这个项目。

二、tidb的架构和最近进展

tidb本质上是一个更加正统的spanner和f1实现,并不cockroachdb那样选择将sql和kv融合,而是像spanner和f1一样选择分离。

这样分层的思想也是贯穿整个tidb项目始终的,对于测试,滚动升级以及各层的复杂度控制会比较有优势,另外tidb选择了mysql协议和语法的兼容,mysql社区的orm框架、运维工具,直接可以应用在tidb上,另外和 spanner一样,tidb是一个无状态的mpp sql layer,整个系统的底层是依赖 tikv 来提供分布式存储和分布式事务的支持,tikv的分布式事务模型采用的是google percolator的模型,但是在此之上做了很多优化,percolator的优点是去中心化程度非常高,整个继续不需要一个独立的事务管理模块,事务提交状态这些信息其实是均匀分散在系统的各个key的meta中,整个模型唯一依赖的是一个授时服务器,在我们的系统上,极限情况这个授时服务器每秒能分配 400w以上个单调递增的时间戳,大多数情况基本够用了(毕竟有google量级的场景并不多见),同时在tikv中,这个授时服务本身是高可用的,也不存在单点故障的问题。

tikv和cockroachdb一样也是选择了raft作为整个数据库的基础,不一样的是,tikv整体采用rust语言开发,作为一个没有gc和 runtime的语言,在性能上可以挖掘的潜力会更大。不同tikv实例上的多个副本一起构成了一个raft group,pd负责对副本的位置进行调度,通过配置调度策略,可以保证一个raft group的多个副本不会保存在同一台机器/机架/机房中。

除了核心的tidb、tikv之外,我们还提供了不少易用的工具,便于用户做数据迁移和备份。比如我们提供的syncer,不但能将单个mysql实例中的数据同步到tidb,还能将多个mysql实例中的数据汇总到一个tidb集群中,甚至是将已经分库分表的数据再合库合表。这样数据的同步方式更加灵活好用。

tidb目前即将发布rc3版本,预计六月份能够发布ga版本。在即将到来的 rc3版本中,对mysql兼容性、sql优化器、系统稳定性、性能做了大量的工作。对于oltp场景,重点优化写入性能。另外提供了权限管理功能,用户可以按照mysql的权限管理方式控制数据访问权限。对于olap场景,也对优化器做了大量的工作,包括更多语句的优化、支持sortmergejoin算子、indexlookupjoin算子。另外对内存使用也做了大量的优化,一些场景下,内存使用下降75%。

除了tidb本身的优化之外,我们还在做一个新的工程,名字叫tispark。简单来讲,就是让spark更好地接入tidb。现在其实spark已经可以通过jdbc接口读取tidb中的数据,但是这里有两个问题:1. 只能通过单个tidb节点读取数据且数据需要从tikv中经过 tidb 中转。2. 不能和spark的优化器相结合,我们期望能和spark的优化器整合,将filter、聚合能通过tikv的分布式计算能力提速。这个项目已经开始开发,预计近期开源,五月份就能有第一个版本。

三、分布式数据库的未来趋势

关于未来,我觉得未来的数据库会有几个趋势,也是tidb项目追求的目标: