有网友反馈,作为一家科技公司的知乎号,平时发文不要太水,还是应该发一些干货类的东西。
喏。你看看,干不干。
2018年4月20日,苹果宣布开源FoundationDB,一款支持多种数据模型、高性能、高可用、可扩展,且具备ACID事务的分布式KV NoSQL系统。FoundationDB已在苹果公司内部的生产环境使用三年,主要用于iCloud上的云存储服务。
苹果于2015年收购开源的FoundationDB并将其闭源。此次再次开源,是因为苹果预见到:FoundationDB有潜力成为下一代分布式数据库系统的底层基础设施。同时,也希望借助社区的力量,利用FoundationDB设计的分层机制,开发以其为底层核心且符合各种应用定制需求的存储系统。这也间接使得苹果的底层基础设施更安全、更可靠,而终实现公司和社区双赢的结果。
抛开苹果开源FoundationDB背后的商业利益不谈,FoundationDB在技术上有两点值得关注:
- NoSQL+ACID+SQL Layer=NewSQL
在独立的KV存储服务上实现事务ACID语义,再通过分层设计在应用层支持文档、图、SQL等多种数据模型。
- MVCC+OCC=SSI
基于多版本/乐观并发控制技术实现可串行化的快照隔离级别。
NoSQL的没落
提起NoSQL,大家一定会想到Google的Bigtable(2008年)和Amazon的Dynamo(2007年),前者出于互联网企业数据量爆发的扩展性需求,实现了一个CP系统;而后者则出于商业用户的写高可用需求,实现了一个AP系统。
Bigtable & Dynamo
在CAP定理(2000年)的推波助澜下,NoSQL运动发展的如火如荼(AP系统如Cassandra、Voldemort、Tokyo Cabinet、Riak,CP系统如Hbase、Hypertable、MongoDB、Redis),并总结出了自己的设计哲学:
- no SQL
- no ACID
- no schema
- high performance
- high scalability
- high availability
- low latency
- relaxed consistency
然而,随着NoSQL系统在应用中的广泛使用,系统设计中抛弃的技术债务成了应用开发人员的负担,开发接口千奇百怪,数据不一致问题状况百出,事务一致性无法保证,正如 Eric Brewer 所说:
The hidden cost of forfeiting consistency, which is the need to know the system's invariants. The subtle beauty of a consistent system is that the invariants tend to hold even when the designer does not know what they are.
尤其是在互联网业内具备神级存在的Google公开的Spanner(2012),成为压垮NoSQL的后一根稻草,又一次改变了分布式数据库系统发展的方向。
Google从NoSQL转向NewSQL的心路历程
Google内部的存储系统,在自身业务需求的推动下,经历了几代系统的演变,Bigtable、Percolator、Megastore、NoSQL Spanner、F1、SQL Spanner,本质上是一个NoSQL到NoSQL+APP ACID到NoSQL+ACID到NoSQL with ACID到NoSQL with ACID + SQL到SQL的过程。
- Percolator(2010,NoSQL+APP ACID)
该系统实现为一个基于Bigtable的业务系统,用于搜索索引的构建,作者在论文中指出了Bigtable对应用需求的限制:
Distributed storage systems like Bigtable can scale to the size of our repository but don't provide tools to help programmers maintain data invariants in the face of concurrent updates.
同时也描述了支持事务语义的好处:
...make it more tractable for the user to reason about the state of the system and to avoid the introduction of errors into a long-lived repository.
Percolator通过2PL技术实现了多行ACID事务:
...stores its locks in special in-memory columns in the same Bigtable that stores data and reads or modifies the locks in a Bigtable row transaction when accessing data in that row...
- Megastore(2011,NoSQL+ACID)
该系统用于内部交互式在线NoSQL系统,作者在论文中也指出了实现事务语义的好处:
Despite the operational advantages of eventually consistent systems, it is currently too difficult to give up the read-modify-write idiom in rapid application development.
Megastore通过OCC技术实现了单分区上的ACID事务,但论文中并没有详细描述实现细节。
- Spanner(2012,NoSQL with ACID)
该系统是个不依赖Bigtable,从头打造的分布式数据库系统,作者在论文中也强调了支持事务语义的好处:
...it is better to have application programmers deal with performance problems due to overuse of transactions as bottlenecks arise, rather than always coding around the lack of transactions.
Spanner通过2PL技术实现了跨分区的多行ACID事务。
- F1(2012,NoSQL with ACID + SQL)
该系统基于NoSQL Spanner实现为AdWords的存储系统,作者在论文中从业务视角直接陈述了事务和SQL的缺失对业务开发造成的影响:
...the complexity of dealing with a non-ACID data store in every part of our business logic would be too great, and there was simply no way our business could function without SQL queries.
F1借助Spanner基于乐观锁实现了乐观事务,并详尽描述了优缺点(无法避免幻读),这个和数据库层面基于OCC技术实现的事务有本质的区别.
- Spanner(2017,SQL)
该系统是一个全功能的SQL系统,作者在论文中再次强调了支持事务和SQL的重要性:
...developers of many OLTP applications found it difficult to build these applications without a strong schema system, cross-row transactions, consistent replication and a powerful query language.
如果没有强表达能力的查询语言:
...developers had to write complex code to process and aggregate the data in their applications.
与此同时,作者对NoSQL with ACID + SQL的技术架构也寄予了高度的肯定:
A scalable, manageable, transactional key-value store is perhaps the lowest common denominator for building enterprise-strength global storage systems. It has been demonstrated by our colleagues from the F1 team that a transactional NoSQL core can be used to build a scalable SQL DBMS.
并且,在存储系统中松耦合还是紧耦合实现SQL还是一个需要认真讨论的问题:
both the loosely coupled (in case of F1) and tightly coupled SQL designs can be deployed successfully, and even simultaneously, on a transactional NoSQL core. A detailed exploration of the pros and cons of these designs is still outstanding. But it is perhaps fair to say that from the perspective of many engineers working on the Google infrastructure, the SQL vs NoSQL dichotomy may no longer be relevant.
NewSQL的繁荣
根据论文中的定义,NewSQL的核心特性如下:
- 支持SQL接口
- 支持ACID事务语义
- 在OLTP场景下具备NoSQL的高性能、高可用、高扩展性
Spanner和F1论文发表至今,催生了一些的NewSQL开源项目:
- 2015年6月4日,前Google员工创办CockroachDB;2015年融资600万美元;2016年融资2000万美元;2017年融资2700万美元
- 2015年中,前豌豆荚员工发布TiDB;2017年融资1500万美元
- 2015年5月24日,HP开源Trafodion,一款基于Hbase,支持ACID事务、SI隔离级别的SQL数据库;2018年1月10日,Apache宣布Trafodion成为项目
- 2017年11月2日,前Facebook员工创办YugaByte DB;2017年融资800万美元;2018年融资1600万美元
从这些项目的实现架构来看,主要分为两种:
- 原生实现
如:CockroachDB、YugaByteDB
- NoSQL+ACID+SQL
如:TiDB、Trafodion
论文[3]和VoltDB[5]在评价FoundationDB的博文中都对NoSQL+ACID+SQL架构下SQL实现的性能表示了质疑,这种架构的主要技术缺陷是计算无法下沉到存储节点会导致大量的网络传输开销。
然而,2017年Google的Spanner论文中已经将类似这种架构的F1与SQL Spanner相提并论,两种架构的优劣性仍然有待观察和研究,但它们的共同点是都依赖于一个支持事务的NoSQL基础系统。从这个视角来看,以下这些支持事务的NoSQL系统也具备演变成NewSQL的可能性:
- 2009年,FoundationDB开源,基于MVCC NoSQL,支持SSI隔离级别;2015年闭源;2018年4月开源
- 2016年3月28日,Yahoo开源Omid,基于Hbase,支持SI隔离级别;后续闭源,商业化为LeanXscale,同时支持SQL
- 2016年3月7日,Tephra开源,基于Hbase,支持SI隔离级别;由Cask公司商业化运作
- 2018年2月15日,MongoDB宣布将在今年夏季发布的4.0版本中支持多文档ACID事务,基于WiredTiger存储引擎改造
事务的心脏——并发控制
从上述章节NewSQL的发展趋势来看,ACID事务的回归是必然的,而且在分布式场景下,均致力于实现可扩展、高性能的串行化隔离级别,这在传统数据库的实现中是难以达到的。事务管理的核心技术是并发控制,原子性、一致性、隔离性都与它相关,本章简单科普一下事务并发控制技术。
事务的并发控制是为了实现事务的调度,一个正确、高效的事务调度应满足如下属性:
- 可串行化
多个并发事务的调度S与一个串行化的调度产生相同的结果,则称这个调度S是可串行化的;在数据库实现中,一般使用冲突可串行化技术。
- 可恢复性
已经提交的事务没有读过被终止的事务写过的数据,防止脏读异常。
- 避免级联终止
避免由于事务T1的终止而导致事务T2的终止。
- 严格性
先发生写操作的事务的提交或终止应先于其它冲突事务的提交或终止。
并发控制从实现思路维度可以分为如下三类:
1. 乐观
重在事后检测,在事务提交时检查是否满足隔离级别。满足,则提交;否则回滚并自动重新执行。
2. 悲观
重在事前预防,在事务执行时检查是否满足隔离级别。满足,则继续执行;否则等待或回滚。
3. 半乐观
混合使用乐观和悲观技术实现事务并发控制。
并发控制从实现方式维度可以分为如下几种(网上的分类方法很多也很混乱,新的并发控制技术也层出不穷,这里仅列举几个重要的做简单介绍):
1. 基于锁的并发控制
- 2PL(two-phase locking)
事务在执行期间被明确的划分为growing和shrinking阶段,growing阶段只能持有锁不能释放锁;shrinking阶段只能释放锁不能持有锁,仅满足可恢复性
- S2PL(strict two-phase locking)
在满足2PL的前提下,要求持有的排它锁必须在事务提交后才释放,避免了级联回滚
- SS2PL(strong strict two-phase locking)
在满足2PL的前提下,要求事务提交之前不得释放任何锁,保证了严格性
2. 基于时间戳的并发控制
在事务开始时生成一个单调递增的时间戳,数据项上维护近读时间戳和近写时间戳。每次读写操作,系统都会将事务时间戳与数据项上的时间戳进行检查,对于任意读写操作,如果事务时间戳小于数据项的近写时间戳,则将事务回滚;对于写操作,如果事务时间戳小于数据项的近读时间戳,则将事务回滚;如果都满足,则继续访问下一个数据项。
3. 基于OCC的并发控制
事务的生命周期被划分为三个阶段,将串行化检测推迟到提交阶段:
- 读阶段
事务写操作仅是对事务私有空间中数据的更新,并不对数据库中的数据项进行真实的更新,保证读阶段没有任何事务冲突及锁开销
- 验证阶段
检测事务是否满足串行化隔离级别
- 写阶段
将事务私有空间中的更新数据写入数据库
4. 基于多版本的并发控制
每一次写操作会生成一个新的数据项版本,数据项的版本号可以使用事务的时间戳或事务号;系统维护多个数据版本,读操作根据所在事务的时间戳或事务号能够读到指定的版本,做到 读-写 或 写-读 操作不阻塞,写-写 操作的冲突依赖2PL实现。
上述只是传统数据库时代总结的并发控制技术,在分布式场景下一般会采用MVCC与其它并发控制技术的组合,目的是提高并发度,减小同步开销。
悲观还是乐观
在了解了数据库的基本并发控制技术后,本文针对现今感兴趣的生产级NewSQL分布式数据库使用的并发控制技术进行了简单的总结:
由上表可以看出,FoundationDB是个使用OCC技术实现ACID事务的生产级数据库系统(严格地说,Google的MegaStore也使用了OCC并用于Google APP Engine等业务,但它的ACID事务实现仅作用于单个分区)。
当然,FoundationDB的OCC实现也有一些限制,比如官方文档对KV和事务的大小及时长做出了如下限制:
- key不超过10K;value不超过100K;事务不超过10M(包括所有读、写涉及的KV)
- 仅支持运行时间不超过5s的读写事务
这些限制在OLTP场景下是完全可以接受的,若要在其Layer机制上实现OLAP场景,需要做适配性改造。
不管怎样,FoundationDB通过OCC技术实现了NoSQL + ACID,并经过了苹果企业级生产环境的检验,NewSQL的设计者到底是该使用悲观还是乐观并发控制技术,现在看来是一个需要认真考虑的问题了。
作者:龙逢 ,现任蚂蚁金服OceanBase团队产品组专家,从事了3年阿里巴巴搜索事业部大数据开发的工作