【读点论文】What’s Really New with NewSQL?
本篇论文是 2016 年 CMU 发表的一篇介绍 NewSQL 发展的综述论文,主要对新兴 NewSQL 数据库的起源、分类以及主要技术原理做了介绍,其中对数据库发展历史、NewSQL 实现原理的介绍非常值得一读。
数据库发展简史
论文首先简要介绍了数据库的发展历史,我觉得这可能是论文最重要的一部分。通过了解历史我们可以深刻明白任何技术都不是凭空出现,而是在最初起源基础之上,根据现实条件和需求不断迭代出来的。
1. 1960 年代 ~ 1970 年代:数据库的诞生
早在 1960 年代,IBM 为了支持阿波罗计划,开发了 IMS 来存储数据,引入了代码与数据分离的思想,让开发者可以专注于操作数据,无需关心这些操作的底层实现细节。
在之后的 1970 年代,作为关系型数据库的先驱,IBM 的 System R 和加州大学的 INGRES 数据库诞生,后者被其他大学广泛使用,并在之后被商业化。与此同时,Oracle 发布了其第一版的 DBMS。
2. 1980-1990 年代:创新与开源
1980 年代,IBM 发布了 DB2 数据库,与此同时还有 Sybase、Informix 等商业产品进入市场,推动着关系型数据库的普及。
在 1980 年代末、1990 年代初,有一股面向对象数据库设计的浪潮,旨在克服关系型数据库和面向对象编程语言之间的不匹配。虽然此类数据库没有成为主流,但在此过程中的许多技术创新为后来 XML 数据存储、对象存储以及 NoSQL 文档数据库的设计奠定了基础。
到了 1990 年代,开源数据库项目兴起,当前流行的 MySQL 和 PostgreSQL 数据库均在此期间诞生。
3. 2000 年代:互联网推动数据库革新
互联网迅猛发展,互联网应用对高并发和高可用的需求,让传统数据库成为瓶颈。虽然可以通过垂直扩展来解决,但这种方法存在局限性,并且从低配机器向高配机器迁移数据的成本也非常高。
为了克服这些限制,Google、eBay 等公司开始采用 middleware 中间件的方式,将多台机器上的单点数据库组合起来,通过 middleware 做代理,实现跨机器的操作,但这种方式对复杂的查询和事务支持有限,有时候开发者需要自己来维护数据处理逻辑。像 eBay 的 middleware 组件就要求开发者自己实现事务和复杂查询。
总的来看,现阶段的关系型数据库面临三个问题:
- 关系型数据库的核心是 ACID,其关注重点在事务一致性和数据的正确性,而这是以可用性和性能为代价的,与互联网应用需要面对的高并发、高可用、高性能的需求不匹配。
- 与互联网应用一起而来的还有海量的数据,使用像 MySQL 这样的数据库存储海量数据是非常不明智的选择。
- 关系型数据库的数据建模和互联网应用所需的数据模型往往并不匹配,有时候需要更灵活、适配的建模方案。
以上问题最终催生了 NoSQL 数据库的诞生。
4. NoSQL 的崛起
NoSQL 数据库最大的特点就是放弃了对 ACID 强一致性的支持,转而追求最终一致性。数据模型也更加的灵活,比如可以是键值对、文档模型或者图数据库等。NoSQL 指的是 No only SQL,是对非关系型数据的数据存储服务的统称,包括键值存储、文档存储、列存储、图数据库等。
Google的 BigTable、Amazon 的 Dynamo,以及后来的 Cassandra、MongoDB、ElasticSearch 、Redis 等开源产品都可以归类为 NoSQL 数据库。这类数据库通常都是以分布式集群的形式存在,天然支持数据的分片、多副本存储。
5. NoSQL 的局限与 NewSQL 的诞生
NoSQL 数据库虽然解决了传统关系型数据库的很多问题,但同时也带来了新的问题。许多企业应用(如金融系统)要求必须做到强一致性,同时又需要 NoSQL 所带来的高性能、高可用、可扩展性。为此,结合了传统数据库的强一致性和 NoSQL 的高性能、高可用、可扩展特性的数据库应运而生,此类数据库被称为 NewSQL 数据库。
NewSQL 的定义与分类
NewSQL 的定义
论文中对 NewSQL 的定义如下:
They are a class of modern relational DBMSs that seek to provide the same scalable performance of NoSQL for OLTP read-write workloads while still maintaining ACID guarantees for transactions.
它们是一类现代关系型 DBMS,旨在为 OLTP 读写工作负载提供与NoSQL相同的可扩展性能,同时仍然为事务保持ACID保证。
简单来书就是,NewSQL 既有传统关系型数据库的 ACID 保证,又兼具了 NoSQL 的高可用、高性能、可扩展等特性。
NewSQL 针对的是 OLTP 类型的数据处理,强调的是对读写事务操作的支持。
还有一种更狭义的定义:
- a lock-free concurrency control scheme and
- a shared-nothing distributed architecture [57]
NewSQL 的分类
论文将 NewSQL 分为三类:
- 从 0 开发的新数据库
- 透明分片中间件
- DBaaS
- New Architecture
采用新的架构设计,从零开发的新数据库,该类数据库基本都采用了分布式架构,支持跨节点的并发控制和基于副本的容错处理。
大多数情况下,这类数据库不会依赖现成的存储系统或存储引擎,比如 HDFS、Apache Ignite,而是自己实现数据的分布式存储。这样做的好处在于可以让数据库 send the query to the data rather than bring the data to the query,在处理数据量巨大的场景时,可以极大的减少网络流量,提高吞吐性能。
通过自己管理数据存储,数据库还可以实现更加复杂、灵活的副本机制,比如 Aurora 实现的 3 可用区 6 副本的存储形式,这是那些采用现成存储方案的数据库做不到的(比如基于 HBase 的 Splice Machine,基于 Hadoop 的 Trafodion)。
这类采用新架构的 NewSQL 数据库的问题在于,因为是新的产品,使用的人数较少,相关的支持更具也比较缺乏,如果遇到问题可能不容易解决;同时新的数据库如果没有长久的支持,产品可能会中途夭折,导致在推广时阻力也会较大,因此很多数据库均采用了兼容已有数据库的方式,比如 MemSQL 等数据库均兼容 MySQL。
像 Google 的 Spanner 还有 VoltDB、MemSQL、H-Store 等数据库均属于此类 NewSQL。
- Transparent Sharding Middleware
另一种形式的 NewSQL 与之前的 middleware 处理类似,各个 DBMS 各自独立的部署在多个节点,然后通过实现一个中心化的 middleware 组件来管理数据的存储、查询、副本、事务处理等操作。通常在每个数据节点,还会有一个 shim 程序作为代理与 DBMS 交互,执行具体的查询返回等操作。整个架构和现在的 ServiceMesh 有些类似,通过 middleware、ship 组件的配合,整个集群作为一个逻辑上的数据库对外提供服务。
该种类型的 NewSQL 数据库的最大优势在于可以直接替代当前的数据库且不需要应用做任何的改动,应用层是感知不到数据库的变更的。比如 Oracle 实现的 MySQL proxy 以及 Fabric 工具集,可以帮助我们无缝迁移到 NewSQL。
此类 NewSQL 的问题在于其各个节点运行的依然是传统的 DBMS,比如 MySQL、Postgress 等,这些数据库都是面向磁盘的数据库,在现代高 CPU、高内存的机器下,其实现机制可能导致垂直扩展的能力不足,无法利用好机器的资源。
AgilData Scalable Cluster2, MariaDB MaxScale, ScaleArc, ScaleBase3 等都属于此类 NewSQL。
- Database-as-a-Service
最后就是云厂商作为云服务提供的 NewSQL,最典型的代表就是 AWS 对外提供的兼容 MySQL 的 Aurora 。
对于此类数据库,用户不需要自己维护,同时可以按需伸缩和付费,主打一个有钱可以为所欲为。需要明确的是,只有采用了新架构,同时支持 ACID 以及高可用、高性能、可扩展特性的数据库才会被视为 NewSQL,将 Azure SQL、Google Cloud SQL 这种仅仅提供传统关系型数据库节点管理的并不需要此列。
NewSQL 的基本原理
本部分重点介绍了 NewSQL 的关键技术点,包括主存存储、分片处理、并发控制、二级索引、副本以及崩溃恢复处理,我们来分别看一下。
主内存存储
传统的 DBMS 都是将数据库存储在 HDD/SSD 这种按块(block)存储的介质上,为了提高性能,这些数据库会使用内存来缓存读到的 block 以及事务的更新信息。因此内存有限,数据读写时经常需要去硬盘执行,这会导致事务阻塞,影响性能。
随着科技的发展,当前的内存架构已经大大降低。在某些情况下,将整个数据集在内存中存储从而实现更加高效的数据读写性能已经是一个可行的策略。像 MemSQL、H-Store 等 NewSQL 均采用在主存存储数据的方式。
主内存存储数据的方案并不是凭空而来的,早在 1980 年代威斯康星大学麦迪逊分校就针对用主内存来存储数据库开始了相关研究,到了 1990 年代,众多基于内存存储的数据库就已经崭露头角,像 Oracle 的 TimesTen 就是此类代表。
NewSQL 使用内存存储数据的一个新特点是,它可以将某一部分数据子集驱逐到硬盘,从而使 DBMS 所能存储的数据量远大于内存容量。通常是在内部实现一个追踪机制,比如 H-Store 的 anti-caching 组件,可以将某些长时间没有被读取多的冷数据移动到磁盘,并在原来的数据中添加一个墓碑(tombstone)标记。当事务需要这部分数据时,事务会被阻塞,数据库启动一个新的线程异步将数据取回内存。
对于支持 larger-than-memory 的 NewSQL 数据库,即使数据被驱逐回硬盘,数据库通常也会将 Key 留在内存中,这会导致不必要的内存浪费。一种参考的解决方案是 Microsoft’s Project Siberia 使用布隆过滤器来减少内存中对索引元素的跟踪数量。
MemSQL 采用了双存储模型的形式,默认是行存储,数据全部存在内存中。如果数据量超过了内存大小,则可以转为列存储模式,将某些数据写入到硬盘中。
二级索引
除了主键索引外,DBMS 通常需要针对某些字段创建二级索引以提升性能。通常需要解决两个问题:
- 如何存储二级索引
- 如何在事务中维护二级索引
对于使用分片中间件实现的数据库集群,通常采用中心化的方式,每个节点都有一份完整的二级索引副本。而对于采用新架构的 NewSQL,基本都采用非中心化的方式,将二级索引也进行分片,每个节点只存储节点的一部分。二者各有利弊:
- 对于中心化的方式,节点包含了所有索引,因此在一个节点上执行就可以查询到所有的数据;但在数据更新时,需要更新所有节点的二级索引。
- 对于非中心化的方式,可能需要遍历所有节点才能完成整个查询;而对于数据更新,则只需要更新索引所在的节点即可,不需要更新所有节点。
有一个特例是 Clustrix,其混合了上述两种方式,首先每个节点都有一份粗粒度(range-based)索引,每次数据查询时,通过该索引将查询路由到数据所在节点,然后每个节点维护各自的二级分片索引,帮助完成数据查询。
对于不支持二级索引的 NewSQL,通常需要引入外部存储来实现,比如 Memcached,但需要在应用层实现缓存更新逻辑,避免数据过时。