作者丨杨传辉(日照)
首先跟大家探讨一个问题:分布式技术的最高境界是什么?这个问题见仁见智,从个人的角度而言,我认为分布式技术的最高境界就是没有分布式。
通过分布式技术可以实现大数据的处理,通过分布式技术也可以把数据库由一台机器变成一百台一千台一万台,甚至 Google 的上百万台服务器。但是从用户的角度来看,我们需要做到让用户完全感知不到分布式,它可以像以前使用传统数据库一样来使用分布式数据库的企业级功能。
今天演讲的主题是《OceanBase:透明可扩展的企业级数据库》,我们会从四个部分展开:
什么是透明可扩展
透明可扩展的理论基础
透明可扩展的关键设计
蚂蚁金服 OceanBase 的业务实践
数据库是一个非常古老的行业,从计算机诞生之初数据库就存在了。Oracle 第一个版本在 1979 年发布,迄今为止已经超过 40 年的时间。今天数据库行业在全球范围内创造了超过 400 亿美金的产值,而且这还仅仅是数据库本身,不包括数据库上层的一系列应用。
上图是 2018 年 Gartner 的魔力四象限图所示,它跟过去几年相比发生了什么变化?我认为主要有两方面的变化:
首先看第一象限——LEADERS 领导者象限,以前的 Gartner 魔力四象限主要上榜的都是传统的企业级数据库,比如 Oracle,Microsoft SQL Server,IBM DB2。今天我们发现领导者象限已经多了几个比较新的选手,一个是 SAP,还有一个是云数据库 AWS。
再来看第四象限——VISIONARIES 远见者象限,只有两家公司上榜,一家是阿里云,还有一家公司是 Google。
这两家公司都是云计算公司,云计算公司过去其实不做数据库。但是今天我们发现随着云计算的发展,互联网公司和云计算公司已经有能力跟传统的企业级数据库公司做正面的抗衡。
企业级数据库发展超过了 40 多年的时间,很多方面都已经做得非常出色了,包括企业级数据库的功能,SQL 的优化,SQL 的执行效率,以及整个企业级数据库的生态体系等。
企业级数据库经过数十年的发展已经非常成熟了,但是有一个比较大的问题,也是企业级数据库从设计之初就没有考虑也不想解决的问题——企业级数据库是一个面向单机设计的数据库,没有解决可扩展性的问题。这跟企业数据库的技术有关,也跟企业级数据库的商业模式有关。
如果容量不足怎么办?可以采用垂直扩展的方式。通过不断扩展容量,虽然稳定性也能做得还不错,但是成本的代价会变得非常的高。我们都知道大型机的成本跟一个普通的 PC 服务器的成本完全不在一个数量级。
那么,云数据库是不是完全解决了透明可扩展的问题?云数据库的概念很时髦,可以称为云数据库,云时代的数据库,也可以叫做云原生的数据库。
从技术的角度来看,我们会发现云数据库的本质其实还是开源数据库加存储计算分离,不管是 AWS 还是阿里云或者其他的云计算公司,云数据库最主要的营收来自于开源数据库,尤其是 MySQL。
AWS 做了一项创新,除了支持本地存储,也可以支持远程的分布式存储,相当于给传统的开源数据库加了一块云盘。这种方式解决了存储可扩展的问题,而且非常适合公有云这种部署模式。因为公有云往往用户规模比较小,一台机器处理的能力已足够,但是它的存储是不够的。数据库的核心部件除了存储以外,还有两个更加关键的部件——一个叫事务处理,这是数据库的核心,还有一个是 SQL。云数据库的模式采用的是存储计算分离的方式,解决了存储可扩展的问题,但是没有解决更关键的问题,那就是事务与 SQL 可扩展的问题。
今天云数据库所使用的开源数据库的核心能力相比企业级数据库还有巨大的差距,不管是 SQL 优化器,SQL 的执行性能,甚至包括各种各样的安全数据管理的能力,存储优化的能力,都跟企业级数据库存在巨大的差距。
刚刚召开的一个 A 类国际会议 ICDE 里发生了一个很有意思的讨论——云数据库能否替代企业级数据库?参加讨论的都是世界上知名的学者,其中一位学者他是来自 IBM 的 C. Mohan,他认为云数据库肯定是不能替代企业级数据库的,至少今天还不行。今天云数据库不管是在存储架构、内存架构、数据管理架构,SQL 优化能力以及 SQL 执行能力跟现有的企业级数据库相比,都有很大的差距,未来需要的是一个分布式企业级 OLTP 数据库。
在互联网里我们还会用另外一个方案叫做分库分表。这个方案非常好,用一个形象的比喻来说它其实有点像狗皮膏药。如果哪里有扩展性问题,就把它往哪里贴就好了。但是这种方案有很多问题并没有解决,它没有实现透明可扩展。
数据库里有一个最基本的功能叫做全局索引,当实现分库分表以后,对用户来讲原来是一张表格,现在被划分为多张表格,表格的语义都发生了区别。分库分表的方案从理论上讲就永远不可能实现全区索引这个功能。另外整个分库分表方案往往会在上面架一层中间件,通过中间件做简单的 SQL 转发、路由、聚合,以及一些比较基础的数据查询功能。
通过中间件提供的 SQL 能力相比真正的企业级数据库的能力,有非常大的差距,它不支持很多功能,包括全局快照——跨多台机器的全局快照,包括复杂查询——跨服务器的复杂查询,跨服务器的写入操作,也包括一个很重要的能力——带容错能力的分布式事务。
很多中间件是支持分布式事务的,但是中间件支持的分布式事务是不带容错能力的分布式事务。当服务器出现故障的时候,整个事务会被夯住,需要人肉去做容错。这种方案跟真正的分布式数据库里带容错的分布式事务是两个方案,有本质的差别。后面会详细的讲这个问题。
透明可扩展的企业级分布式数据库需要具备一些基本的属性:
它需要像传统企业级数据库一样,无需业务修改,按需扩容
核心能力可扩展,包括存储,事务和 SQL。其中这里面存储可扩展是最容易实现的,事务可扩展是最难做到的,SQL 可扩展是工作量最大的。
持续可用,保持稳定:整个系统需要是持续可用的,不管服务器发生了什么故障,都必须做到系统稳定,整个系统对外体现一个持续稳定的输出,保证业务的连续性。
具备企业级数据库功能
通过核心业务和 benchmark 证明:数据库是对任何一家公司都非常关键的核心组件,需要在公司内部通过它的核心业务长时间的历练,至少数年的稳定性的验证以及核心的 benchmark 的验证,最终才能推向市场给外部客户使用。
事务是一个非常古老的概念,必须遵循 ACID 特性:
原子性(A):事务操作要么全部成功,要么全部失败
一致性(C):一个事务只能使数据库从一个一致的状态跳转到另一个一致的状态,不能破坏主键唯一或者所有列之和为固定值之类的约束
隔离性(I):多个并发事务互相不影响,就如同多个事务串行执行一般
持久性(D):一旦事务成功提交,它对数据库的影响是永久的
分布式事务不是一个新鲜的概念,分布式事务的协议是 1978 年由 Jim Gray 提出的两阶段提交协议。
两阶段提交协议本身并不复杂。当我们需要把多台机器连起来做协调的时候,所有机器都叫做参与者,然后其中有一台机器会选出来做协调者。当要进行事务提交的时候,协调者先给所有的参与者发送 prepare 消息,如果所有的参与者都 prepare 成功,最终协调者认为整个事务可以提交了,然后再发出 commit 消息,让每一个参与者都提交事务。如果其中某个参与者因为各种情况比如资源不足最后没法提交事务,整个事务提交失败,协调者给参与者发送回滚消息。
这个协议看起来很简单,但没有考虑容错,是一个理论上的协议,而不是一个工业级的工程实现。当我们去考虑工业级的工程实现的时候,我们必须考虑容错,这时候就会出现一个最关键的问题——阻塞。
假设协调者出现了故障,整个数据就会被 hung 住,即使是参与者出现故障,那参与者所在的那台机器也会被 hung 住。在一个高并发的系统里只要有一台机器被 hung 住,就意味着客户端被 hung 住。客户端被 hung 住就意味着整个系统被 hung 住。所以一台机器故障最终会导致整个集群的不可服务。
分布式事务不支持容错——这个是在工程应用时面临的最大的问题。那么支持容错其实有很多种方案。
其中的一种方案就是中间件 XA。中间件 XA 是一种分布式事务的实践方法, XA 的本质是把协调者跟参与者的状态持久化到数据库里,由数据库来支持容错,所以中间件是无状态的。但是我们自己是分布式事务数据库的设计者,不可能再把状态持久化到另外一个分布式数据库里来支持容错。
另外一个思路是 NOSQL 系统中的 CAP 理论。CAP 三者不可兼得。在一个需要考虑容错的系统设计里面,P(分区容错)是不可选择的,一定会出现网络分区的情况。C(一致性)跟 A(可用性)二者只能取其一,要么要一致性,要么要可用性。
其实 NOSQL 系统从理论上就已经比较“巧妙”的回避了一致性分布式问题。分布式事务的问题就不处理了,或者根本就不支持分布式事务。
身处云时代,作为一个有追求的技术人员,我们的方案应该不是去规避问题,而是直面问题,直接采用 Paxos 加上两阶段提交协议来解决带容错的分布式事务的问题。
其实这个协议也没有特别新鲜的内容,由两个图灵奖得主,一个是事务的图灵奖得主——Jim Gray,一个是 Paxos 的图灵奖得主——Leslie Lamport,他们在 2004 年发表了一篇关于 Paxos + 2PC 的论文。但是这个协议从理论走向工程实践,经过了十多年的时间。
CAP 理论跟 Paxos 是什么关系呢?CAP 理论中 P(分区容错)是没有办法规避的,所以 C 跟 A 两者是不可兼得的。CAP 理论告诉我们,要么强一致,要么高可用。Paxos 却能同时实现强一致和高可用,那么 Paxos 协议是不是违背了 CAP 理论呢?我认为其实是没有违背的,本质在于 Paxos 里的高可用跟 CAP 里的可用性是两个不同的概念。
在分布式系统里面经常会有一些概念容易引起混淆,比如这里讲的可用性和一致性,这两个概念在不同的场景的语义是不同的。Paxos 是从系统整体的角度来看的,哪怕出现单个节点故障的时候,只要多数派能够快速恢复使得整个系统继续服务,它就是高可用的。
但是 CAP 理论是从故障节点的角度来看的,当单个节点出现故障的时候,这个故障的节点能不能在有限的时间被访问到,这是 CAP 理论里可用性的意思。
所以虽然可能满足不了 CAP 的可用性,当出现了一个故障节点,有可能这个系统出现故障的节点永远没有办法恢复,所以永远满足不了 CAP 的高可用。但是这个系统仍然能够满足 Paxos 的高可用,因为系统中其他多数派的节点能够提供服务,整个系统就能够最终提供服务。Paxos 的高可用才是真正有工程意义的高可用。
Paxos 协议有很多的变种,其中一个比较著名协议叫做 raft 协议。我从 2007 年接触 Paxos 协议,前后花了至少三年多的时间才觉得自己开始慢慢理解它。
以前 Paxos 协议是一个贵族协议,但是自从诞生 raft 以后,他的出现把 Paxos 的协议变成一个平民协议。为什么这么说呢?
Paxos 协议有一个很大的设计假设,它要求支持多个投票,也就是数据库里的多条日志之间是可以乱序提交的,可以并行处理的。但是 raft 协议的做了一个约束,数据库的多个投票多条日志一定要按照顺序执行,只能前一个日志被确认了才能确认后一个日志。
这种简化使得 Paxos 协议走进了千家万户。但是有得必有失,他把这个约束变得更简单了以后,导致了两个问题,第一个问题是并发能力变得更差了。以前支持并发的提交,现在只能支持一个结束以后再来下一个,所以它的性能变差了。
第二个是可用性的问题。如果采用 Paxos 协议,当一台机器新上线的时候很快就能提供服务了,因为不需要等前面的数据确认它就能提供服务,但是如果使用的是 raft 协议,需要等前面的所有日志确认以后才能提供服务,所以说 raft 协议存在可用性的风险。在某些场景尤其是异地部署和比较差的网络环境下是有风险的。
在所有分布式系统里分为两个阵营,一个是 Paxos 的阵营,包括 Google Spanner,蚂蚁金服 OceanBase 1.0 以及 1.0 之后的版本,Amazon DynamoDB 等。Raft 阵营,包括蚂蚁金服 OceanBase 0.5 版本,也包括腾讯的 TDSQL 以及一系列的开源的系统,基于 mysql 的系统基本上都是通过 Raft 协议来实现的。
选择哪一个阵营其实也就说明了你想要实现的目标。如果说你想快速拿到业务结果,而且希望技术风险可控,我建议大家采用 Raft 协议。如果你希望追求极致,做世界一流的系统,那么我们应该尝试用 Paxos。
在 OceanBase 的设计过程中,我们遇到的第一个问题就是分区表。分布式要解决的第一件事就是如何对数据进行切片。在数据库里切片有两种方式,一种方式是分表,一种方式是分区表。
分表从逻辑上改变了表格的语义。用户原来是一张表格,如果说应用层做了一层分表以后,在数据库里有了多张表格,多张表格就意味着很多的特性其实丢掉了,包括全局索引这个非常重要的特性。
分区表是企业级数据库里一直都有的一个功能。以前的企业级数据库,它的分区表只能把每一个分区放在一台机器里,而分布式数据库可以把它的分区表按一定的规则,在后台把它分散到整个分布式的集群里。分区的模式能够实现全局的一致性,而且能够支持强一致的全局索引,这个很关键。分区表支持多种数据分布的方式,包括 NOSQL 或者存储系统里会用到的哈希分区,范围分区,列表分区以及两种分区方式的组合。
有了分区表,把整个数据打散成很多数据分片以后,我们接下来要做的一件事就是把这些数据分片均匀的分布到整个后台的分布式集群里,这个过程我们称为自动负载均衡。
负载均衡里有一点想特别强调一下,就是复制的方式。复制的方式有两种:一种方式叫逻辑复制,一种方式叫物理复制。
顾名思义,逻辑复制相当于把数据一行一行读出来再写,这叫逻辑复制。物理复制,就是直接拷贝最终的数据文件或者是数据块。物理复制的性能很好,但是实现难度却很高。按照以往经验来看,物理复制的性能可以做到逻辑复制的 5 到 10 倍。
在大部分的分布式存储系统里面,负载均衡都实现了自动化。但是目前绝大部分的分布式数据库的负载均衡都是人肉负载均衡。
分布式数据库里的自动负载均衡实现难度很大。因为分布式数据库里面临的负载均衡本质上是一个多因子负载均衡的问题,它需要考虑两种负载,一种负载叫做计算负载,主要考虑的是 CPU 跟内存。另外一种负载叫存储负载,主要考虑的是磁盘的占用量。
当计算负载比较高的时候,存储负载可能是比较低的。相反,当存储负载比较高的时候,计算负载又是比较低的。而且我们会发现计算存储的资源配比跟业务实际的计算存储负载是不一致的。同时,存储的迁移耗时很长。
当我们有了分区表,假设已经把负载自动均衡到所有的机器后,下面我们要考虑的就是如何做容错的问题。容错分为两种情况,一种是分区自身发生的故障如何容错,还有一种情况是外部的用户请求如何动态的处理故障。
当发生主备切换的时候,需要做到新的事务在新的分区里开启,老的事务还需要动态地由原来的主分区一行一行迁移到新的主分区,整个过程需要做到事务的在线迁移。大家可以想象这是一个分布式场景的并发处理问题,它的难点在于怎么做多机的并发问题以及如何做异常的处理。
分区分裂是我们内部的一个操作,这样的一个操作是不能杀事务的。如果杀事务用户就会感知到,感知到后台做了一些操作。而且数据库的事务可能是一个执行非常长的一个事务,有的甚至执行一到两天。我们需要做到新的事务在新的分区里执行,老的事务还能动态的一行一行迁移到新的分区里,整个过程需要做到对用户透明,这是其中最大的难点。
全链路的请求容错,难点在于请求涉及的环节特别多。从应用过来一个请求,首先会到一个叫 Proxy 的代理服务器,Proxy 再请求后端的分布式数据库的集群,整个过程是一台机器请求另外一台机器,一台机器再请求另外一台机器,任何一个过程都可能会发生故障。
在发生故障的时候都需要做到读写请求的重试,但是重试其实是一个很危险的操作。AWS 之前曾经因为重试产生了重试风暴导致大面积的故障。重试可能会产生连锁反应。原来用户发了一个请求,最后重试变成了一百个请求,整个系统就崩溃了,而且永远不可恢复,只能把用户的请求停掉,最后才能恢复。
重试也要做的,但是我们追求一点,就是需要做到任务级的重试。一个请求可能涉及的数据量很大,这个过程中会处理很多的数据分片,某一个数据分片出现故障的时候只重试这一个数据分片。整个请求的链路涉及到 Proxy 到数据库,当 Proxy 跟数据库做动态调整或者在线升级的时候,我们需要做到将它上面正在进行的请求动态的迁移到其他还能够工作的机器上。这是这件事情的难点,它需要做动态,但不能杀事务。
异常处理也有一个比较大的难点——是半死不活。当请求一个磁盘,它一会好一会不好,网络时好时坏。如何处理这种半死不活的状况。这个情况在大规模系统里面叫 hung 住。hung 住比失败要可怕得多。
企业级数据库里有一个很重要的功能叫优化器。优化器在企业级数据库里面都是基于代价来实现的。因为优化器带来的问题特别多,我这里面只提两个问题。
第一个是大小账号的问题,很多人在互联网公司都经历过,比如一张表格有很多的用户,有的用户数据量很大,有的数据量很小。假设一个企业级数据库,同样一条 SQL 进来的时候,能够动态的判断请求的用户是哪个,并且可以根据统计信息来选择执行计划。如果请求的是大账号,就选择一个全表扫描的执行计划,如果小账号选择一个索引回表的执行计划来达到最优。
数据库后台调整的时候,特别让人害怕的一点就是数据库后台调整以后执行计划变了,使得原来执行很快的执行计划变得很慢,这个时候该怎么办呢?在企业级数据库里,有执行计划演进这样的一个功能。
当有调整的时候也会生成新的执行计划,但是新的执行计划并不会立刻生效,而是把流量一点一点从老的执行计划切到新的执行计划,等到最终内部验证了整个新的执行计划的性能没有回退以后,我们再用新的执行计划完全替代老的执行计划。这是企业级数据库里面优化器的一些基本的功能。
分布式数据库相比企业级数据库又多了一个问题,主要是并行优化的问题。假设一个单机数据库,以 Oracle 为例,优化器的实现会把整个优化分成两个阶段,第一个阶段叫串行优化,不会考虑一些分布式的问题,也不会考虑网络开销的问题。第二个阶段它会对第一个阶段串行优化结果里部分的算子做局部的并行化。所以大家可以想象,分成了这两个阶段以后,它的搜索空间并不是那么的全面,有一些应该搜索的这样的一些执行计划就被忽略掉了。
但是如果是一个分布式数据库,我们一开始就应该考虑并行优化器,一开始就应该考虑所有的单机的开销以及分布式的开销,直接搜索全部的空间,然后生成一个涉及全部开销的并行执行计划,最终才可能达到一个最优。
最后简单的给大家介绍一下蚂蚁金服 OceanBase 的实践经验。OceanBase 从 2010 年立项,是由阿里巴巴和蚂蚁金服 100% 自主研发的具备完全自主知识产权的企业级的分布式数据库。
2014 年,OceanBase 第一次将 Paxos 协议引入到关系数据库领域。因为这项创新,最终 OceanBase 数据库成功替代了蚂蚁金服交易库中的 Oracle 数据库,实现了金融级的持续可用。这是金融行业过去没有的一项重大创新。
OceanBase 是一个工业级的 share-nothing 透明可扩展的分布式架构,可以无限扩展。OceanBase 可以给用户提供全局一致的数据库视图,并且能够支持跨服务器任意的复杂查询。OceanBase 对 MySQL 全兼容,还支持部分 Oracle 版本的兼容。
OceanBase 设计之初,其实就是一个原生的多租户支持的系统,当有多个业务同时使用 OceanBase 集群,一个业务有问题,它不会影响别的业务,这是面向云设计的一个系统。
OceanBase 在蚂蚁以及整个金融行业使用已经非常广泛了。蚂蚁金服几乎所有的业务都是由 OceanBase 所支撑,包括双 11 大促,618 以及春节红包等等各种类型的市场活动,其中支付交易账务百分之百的流量都是由 OceanBase 所承载。并且随着蚂蚁金服的国际化,OceanBase 已经全面进军国际业务。OceanBase 在浙商银行、南京银行、苏州银行、广东农信、人保健康险等外部客户的互联网核心系统中,承担了交易数据库的重要角色。
交易支付是蚂蚁金服最核心的一个业务,原来交易支付是按照 UserID 拆分成 N 份的,后来发现容量不够,要拆分成 M*N 份。以前做拆分都是中间件跟业务一起来改造,每一次拆分都需要技术部门几百人的开发花费一年的时候来完成改造。导致一方面耗时耗力,另外一方面技术风险非常高。
OceanBase 的解决方案:
OceanBase 解决的方案就是使用 OceanBase 分区表实现透明拆分。通过 OceanBase 分区表在数据库底层实现拆分,业务完全没有感知,也基本上不需要任何的改造。
每个公司无论大小,肯定都会有自己的会员系统,而且这一定是公司的核心系统,它存储了用户的重要信息。一个用户的信息是多维度的,除了根据 userID 还可能根据用户名,邮箱手机号码等进行查询。
这样的一个数据库,本质上就是全局索引的需求,但是我们都知道分库分表的方案是不支持全局索引的,带来的问题就是单机数据库只能垂直扩展,没有办法做到水平扩展。
OceanBase 的解决方案:
OceanBase 的解决方案就是 OceanBase 分区表 + 强一致的全局索引,通过这样的方案在数据库底层实现可扩展,而且对用户透明。
外部业务相比蚂蚁的业务对透明可扩展的要求更高,在蚂蚁内部我们有非常强大的 DBA ,有很强大的开发能力可以改造,但是在外部客户基本上是不能改造的。这里举一个金融机构例子,某金融机构有大量批处理场景,有多张大表关联的复杂计算,并且涉及到大量的数据更新。批处理意味着每一次处理的数据量很大,而且有很多张大表要做关联,经常要做一些比较复杂的查询,并且更新量也比较大。业务的痛点在于传统的集中式数据库,单点出现了瓶颈,并且小型机的成本很高。如果扩容只能扩容成大型机,成本就变得不可接受。
OceanBase 的解决方案:
OceanBase 的解决方案就是透明可扩展的 OceanBase,通过 OceanBase 的 HTAP 场景的并行处理能力,使得处理时间相比现有的时间缩短了一半,并且 TCO 得到了大幅度的降低。通过 OceanBase 迁移服务(又名 OMS)进行平滑迁移实现了可灰度可回滚。过去金融行业进行业务迁移都是停机迁移,OceanBase 做到了在线迁移并且可灰度可回滚在金融行业是一件非常了不起的事情。
OceanBase 是由蚂蚁金服、阿里巴巴完全自主研发的金融级分布式关系数据库,始创于 2010 年。OceanBase 对传统的关系数据库进行了开创性的革新。在普通硬件上实现金融级高可用,在金融行业首创“三地五中心”城市级故障自动无损容灾新标准,同时具备在线水平扩展能力。在 2017 年天猫双 11 中创造了 4200 万次 / 秒处理峰值的世界纪录。在 2018 年天猫双 11 中,OceanBase 2.0 版本支撑了支付宝的核心链路,性能比去年提升了 50%,真正实现了“零成本”支撑大促。欢迎关注“OceanBase”公众号,了解更多数据库干货,破解更多技术密码。
更多关于国内外一流技术团队的实践案例请持续关注 QCon 全球软件开发大会,上海站内容正在筹备中,涵盖大数据、架构、移动、微服务、工程效率、运维、前端等经典方向及 Cloud Native、中台、图数据库、下一代计算等新兴方向。目前早鸟 7 折报名最后一周,点击「阅读原文」或识别二维码立刻上车,有问题欢迎联系票务小姐姐 Ring,电话:17310043226,微信:qcon-0410。
点个在看少个 bug 👇