关于后端:数据库分布式数据库历史变迁之旅

5次阅读

共计 17142 个字符,预计需要花费 43 分钟才能阅读完成。

咱们正式开始分布式数据库历史变迁之旅。

单机数据库的不可能三角

正如经济政策的不可能三角“不可能同时实现资本流动自在,货币政策的独立性和汇率的稳固”那样,单机数据库也有一个不可能三角,那就是:①长久化 ②事务隔离 ③高性能。

为什么不可能

  1. 长久化须要每一次写数据都要落到磁盘上,宕机再启动当前,数据库能够自修复。如果只要求这一条,很好实现。
  2. 事务隔离须要每一次会话 (session) 的事务都领有本人的数据库版本:既要多个并行的事务相互之间不会写到对方的虚构数据库上(读提交),又要不能读到对方的虚构数据库上(可反复读),还要在一个事务内不能读到别的事务曾经提交的新增的数据(幻读),终极需要则是齐全串行化:我的读 session 不完结,你就不能读。这个需要和长久化需要联合当前,会大幅减少日志治理的复杂度,但,还是能够治理的。
  3. 读写都要尽量地快:独自实现也很快,Redis 嘛,然而加上长久化和事务隔离,就很难做了:须要对前两项进行斗争。

MySQL 抉择了哪两个?

MySQL 首先抉择了长久化:失去人性,失去很多,失去长久化,失去所有。没有长久化能力,那还当个毛的外围数据库,所以这一条是所有磁盘数据库的刚需,齐全无奈舍弃。

而后 MySQL 抉择了一部分高性能:MyISAM 就是为了疾速读写而发明的,晚期 MySQL 在低配 PC 机上就有不错的性能。起初更高级的 InnoDB 呈现了,小数据量时它的读取性能不如 MyISAM,写性能更是彻底拉胯,然而在面对大数据量场景时,读性能爆棚,还能提供很多后端程序员梦寐以求的高级性能(例如丰盛的索引),承当了大部分互联网外围数据库的角色。

最初,MySQL 将事务隔离拆成了几个级别,任君筛选:你要强事务隔离,性能就差;你能承受弱事务隔离,性能就强。你说无事务隔离?那你用 MySQL 干什么,Redis 它不香吗。

所以 MySQL 其实抉择了 长久化 \_1 + 高性能 \_0.8 + 事务隔离 *0.5,算下来,还赚了 0.3 (~▽~)”

不过,从 MySQL 也能够看出,“数据库的不可能三角”并不是齐全互斥的,是能够互相斗争的。

在开始细数分布式数据库之前,咱们先看一个非分布式的晋升数据库性能的计划,读写拆散,主从同步。

读写拆散

因为 web 零碎中读写需要领有显著的二八分特色——读取流量占 80%,写入流量占 20%,所以如果咱们能把读性能拆分到多台机器上,在同样的硬件程度下,数据库总 QPS 也是能进步五倍的。

各种主从架构

无论是远古时代谷歌的 MMM(Multi-Master Replication Manager for MySQL) 还是中古时代的 MySQL 官网的 MGR(MySQL Group Replication),还是最近刚刚实现开发且免费的官网 InnoDB Cluster,这些主从架构的实现形式都是统一的:基于行同步或者语句同步,近实时 地从主节点向从节点同步新增和批改的数据。

因为这种办法必然会让主从之间存在有一段时间的提早(数百毫秒到数秒),所以个别在主从后面还要加一个网关进行语句散发:

  1. select等读语句默认发送到从节点,以尽量升高主节点负载
  2. 一旦呈现 updateinsert 等些语句,立即发送到主节点
  3. 并且,本次会话 (session) 内的所有后续语句,必须全副发送给主节点,不然就会呈现数据写入了然而读不到的状况

一主四从架构图

搭建一个一主四从的 MySQL 集群,总 QPS 就能从单节点的 1 万晋升到 5 万,顺便还能领有主节点故障后高可用的能力。主从架构比较简单,也没有什么数据抵触问题,就是有一个很大的弱点:

写入性能无奈晋升:因为数据库承载的单点性能切实是太多了(自增、工夫先后、事务),导致哪怕架构玩出了花,能写入数据的节点还是只能有一个,所有这些架构都只能晋升读性能。

那怎么晋升写性能呢?这个时候就要掏出分布式数据库了。

分布式数据库

因为数据库的单点性十分强,所以在谷歌搞出 GFS、MapReduce、Bigtable 三驾马车之前,业界对于高性能数据库的次要解决方案是买 IOE 套件:IBM 小型机 + Oracle + EMC 商业存储。而过后的需要也的确更加适宜商用解决方案。

起初搜索引擎成为了第一代全民网站,而搜索引擎的数据库却“不那么关系型”,所以谷歌搞出了本人的分布式 KV 数据库。起初谷歌发现 SQL 和事务隔离在很多状况下还是刚需,于是在 KV 层之上改了一个强统一反对事务隔离的 Spanner 分布式数据库。而随着云计算的衰亡,分布式数据库曾经成了云上的“刚需”:业务零碎全副上云,总不能还用 Oracle 物理服务器吧?于是云上数据库又开始大踏步倒退起来。

上面咱们依照工夫程序,逐个梳理分布式数据库的发展史。

第一代分布式数据库:中间件

在 MySQL 体系内演进

关系型数据库为了解决不可能三角需要,其根本架构 40 年没有变过。

MySQL 本人其实曾经是一个十分优良的满足互联网业务场景的单体数据库了,所以基于 MySQL 的根本逻辑进行架构改良,是最稳当的计划。

在没有分布式关系型数据库技术呈现的时代,后端开发者们往往只能抉择惟一的刀耕火种的路:在利用代码里调用多个数据库,以应答单个数据库性能有余的窘境。起初,有人把这些调用多个数据的代码抽出来作为独自的一层,称作数据库中间件。

数据库中间件

首先,对数据表进行纵向分表:依照肯定规定,将一张超多行数的表扩散到多个数据库中。

ShardingSphere 中的 Sharding-Proxy 工作形式

而后,无论是插入、更新还是查问,都通过一个 proxy 将 SQL 进行重定向和拆分,发送给多个数据库,再将后果聚合,返回。

赫赫有名的数据库中间件,其基本原理一句话就能形容:应用一个常驻内存的过程,伪装本人是个独立数据库,再提供全局惟一主键、跨分片查问、分布式事务等性能,将背地的多个数据库“包装”成一个数据库。

尽管“中间件”这个名字听起来像一个独立组件,但实际上它仍然是强业务亲和性的:没有几家公司会本人研发数据库,但每家公司都会研发本人的所谓中间件,因为中间件基本上就代表了其背地的一整套“多数据库分库分表开发标准”。所以,中间件也不属于“通用数据库”领域,在宏观架构层面,它仍然属于利用的一部分。我称这个时代为刀耕火种时代。

那该怎么脱离刀耕火种呢?人类的大脑是类似的:既然利用代码做数据布局和逻辑判断很容易失控,那咱们在数据库层面把这件事接管了行不行呢?当然能够,然而须要拿货色 找信息之神替换

历史上,第一个被放弃的是 事务隔离,而它带来的就是第二代分布式数据库:KV 数据库。

第二代分布式数据库:KV

分布式时代的“新·不可能三角”

在分布式数据库时代,长久化曾经不是分布式数据库“真正的长久化”了,取而代之的是“数据一致性”:因为数据存在了多台机器上,那机器之间数据的一致性就成了新时代的“长久化”。于是新不可能三角呈现了:①一致性 ②事务隔离 ③高性能。

你是不是在期待 CAP 实践呀?别着急,咱们前面会说。

分布式 KV 数据库放弃了事务隔离

数据库技术一共取得过四次图灵奖,前面三次都在关系型数据库畛域。事务隔离模型是关系型数据库的外围,十分地简洁、柔美、逻辑自恰。

Google 是第一个全民搜索引擎,零碎规模也达到了史上最大。然而,搜索引擎技术自身却不须要应用关系型数据库来存储:搜寻后果中的网页链接之间是离散的。这块我要挖个坑,本系列完结当前,我会写一篇如何本人开发搜索引擎的文章。

因为搜寻不须要关系型数据库,天然谷歌搞的分布式数据库就是 KV 模型。谷歌的三驾马车论文公布当前,业界迅速倒退出了一个新的数据库门类 NoSQL(Not Only SQL),专门针对非结构化和半结构化的海量数据。

目前,缓存(Redis)和文档 / 日志(MongoDB)大家个别都会用 NoSQL 来承载。在这个畛域,最胜利的莫过于基于 Hadoop 生态中 HDFS 构建的 HBase 了:它次要提供的是行级数据一致性,即 CAP 实践中的 CP,放弃了事务,能够高性能地存储海量数据。

KV 数据库构造简略,性能优异,扩展性无敌,然而它只能作为外围数据库的高性能补充,绝大多数场景下,外围数据库还是得用关系型。

第三代分布式数据库:以 Spanner 为代表的 NewSQL

从 2005 年开始,Google Adwords 开始基于 MySQL 搭建零碎,这也推动了 MySQL 在 Google 外部的大规模应用。随着业务的倒退,MySQL 集群越来越宏大,其中最苦楚的就是“数据再分片”,据说有一次谷歌对数据库的从新分片继续了 2 年才实现。于是谷歌痛定思痛,搞出了一个反对分布式事务和数据强一致性的分布式关系型数据库:Google Spanner。

2012 年,谷歌公布了 Spanner 论文¹,拉开了分布式强一致性关系型数据库的大幕。这个数据库是真的牛逼,当我第一次看到它机柜照片的时候间接震惊了:

这套零碎采纳了 GPS 授时 + 2 台原子钟 + 4 台工夫服务器,让散布在寰球多个数据中心的 Spanner 集群进行相当准确的工夫同步:基于 TrueTime 服务,时间差能够管制在 10ms 之内。这种真正的寰球数据库能够做到即便单个数据中心齐全生效,利用也齐全无感知。

当然,如此规模的寰球数据库全世界也没有几家公司有需要,如果咱们只在一个数据中心内署数据库集群,工夫同步能够很容易地做到 1ms 之内,原子钟这种高端货还用不到。

还记得上篇文章中数据持久性的关键步骤——redo log 吗?

为什么上篇文章要写一万多字,就是为本文打基础的,当初就用到了。

上文中咱们说过,写入型 SQL 会在写入缓存页 + 写入磁盘 redo log 之后返回胜利,此时,真正的 ibd 磁盘文件并未更新。所以,Spanner 应用 Paxos 协定在多个正本之间同步 redo log,只有 redo log 没问题,多正本数据的最终一致性就没有问题。

事务的两阶段提交

因为分布式场景下写申请须要所有节点都实现才算实现,所以两阶段提交是必须存在的。单机架构下的事务,也是某一旦一条 SQL 执行出错,整个事务都是要回滚的嘛。多机架构下这个需要所须要的老本又大幅减少了,两阶段提交的流程是这样的:

  1. 通知所有节点更新数据
  2. 收集所有节点的执行后果,如果有一台返回了失败,则再告诉所有节点,勾销执行该事务

这个简略模型领有十分恐怖的实践故障概率:一旦在第一步执行胜利后某台机器宕机,则集群间接卡死:大量节点会被锁住。

Spanner 应用 Paxos 化解了这个问题:只有 leader 节点的事务执行胜利了,即向客户端返回胜利,而后续数据的一致性则会基于 prepare timestampcommit timestamp加上 Paxos 算法来保障。

多版本并发管制(MVCC)

Spanner 应用工夫戳来进行事务之间的 MVCC:为每一次数据的变动调配一个寰球对立的工夫戳。这么做的实质仍然是“空间 + 工夫”换工夫,而且是拿过来的工夫换当初的工夫,特地像反对预先对焦的光场相机。

  1. 传统的单机 MVCC 是基于单机的原子性实现的事务程序,再实现的事务隔离,属于即时判断。
  2. Spanner 基于 TrueTime 记录下了每行数据的更新工夫,减少了每次写入的工夫老本,同时也减少了存储空间。
  3. 在进行多节点事务同步时,就不须要再和领有此行数据的所有节点进行网络通信,只依附 TrueTime 就能够用 Paxos 算法间接进行数据合并:基于工夫戳判断谁前谁后,属于预先判断。

Spanner 放弃了什么

Spanner 是一个强统一的寰球数据库,那他放弃了什么呢?这个时候就须要 CAP 实践退场了。

一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。

Google Spanner 数据库首先要保障的其实是分区容错性,这是“寰球数据库”的根本要求,也最影响他们赚钱;而后是一致性,“强统一”是外围设计指标,也是 Spanner 的外围价值;谷歌放弃的是可用性(A),只有 majority available。

除此之外,为了“内部一致性”,即客户端看到的全局强一致性,谷歌为每一个事务减少了 2 倍的时钟提早,换句话说就是减少了写操作的返回工夫,这就是分布式系统的代价:目前均匀 TrueTime 的提早为 3.5ms,所以对 Spanner 的每一次写操作都须要减少 7ms 的等待时间。

Spanner 一致性的基本起源

大家应该都发现了,其实 Spanner 是通过给 Paxos 分布式共识算法加了一个“本地外挂”TrueTime 实现的海量数据的分布式治理,它实现全局强一致性的基本起源是 PaxosTrueTime。而在一般单机房部署的分布式系统中,不须要 GPS 授时和原子钟,间接搞一个工夫同步服务就行。

NewSQL 时代

Google Spanner 的推出代表着一个新时代到来了:基于分布式技术的 SQL 兼容数据库(NewSQL),而兼容到什么境地就看各家的程度了。

NewSQL 最大的特点就是应用非 B 树磁盘存储构造(个别为 LSM-Tree),在下面构筑一个兼容 SQL 罕用语句和事务的兼容层,这样既能够享受大规模 LSM-Tree 集群带来的扩展性和高性能,也能够尽量少改变现有利用代码和开发习惯,把悲伤留给本人了属于是。

目前比拟常见的 NewSQL 有 ClustrixDB、NuoDB、VoltDB,国内的 TiDB 和 OceanBase 也属于 NewSQL,但他们俩有本质区别,咱们上面会具体探讨。

在 NewSQL 时代之后,随着云计算的衰亡,云上数据库忽然成为了市场的宠儿,市场占有率迅速上涨。它们其实都是对 MySQL 的革新,并不属于 NewSQL 领域,上面咱们认识一下他们。

第四代分布式数据库:云上数据库

我切实是不想用“云原生”这个风口浪尖上的词来形容漂亮的云上数据库们,它们就像 TCP/IP,简洁但有用。市场从来不会说谎,它们肯定是有过人之处的。

亚马逊 Aurora 开天辟地

2014 年 10 月,亚马逊公布了 Aurora 云上数据库,开创性地在云环境中将计算节点和存储节点拆散:基于云上资源的特点,将计算节点 scale up(增配),将存储节点 scale out(减少节点),实现了极佳的性能 / 老本均衡。Aurora 将云上关系型数据库产品推向了一个新的高度。

计算与存储拆散

Aurora 提出的计算与存储拆散能够说是目前数据库畛域最火的方向,然而它火的起因我置信大多数人都意识的不对:不是因为性能强,而是因为便宜。

开掘云计算的价值点

十年前我在 SAE 实习的时候,中午大家一起吃饭,组长说云计算就是云平安,这句话当然说的很对。从这句话推开,咱们很容易就能找到云计算真正的商业价值在哪里:传统托管式部署,哪些资源节约的最多,哪里就是云计算的商业价值所在。

为了满足业务稳定而多洽购的 CPU 和内存,可能节约了 50%;网络安全设施,能够说 95% 以上的资源都是节约;高端存储,这个曾经不能用资源节约来形容了,而是被云计算颠覆了:云厂商用海量的多地区多机房内便宜的 x86 服务器外面的便宜磁盘,基于软件,构建出了超级便宜、多正本、高可用的存储,惟一的问题是性能不是太好。亚马逊 S3 和阿里云 OSS 就是最佳代表,能够说这类对象存储服务,其单价曾经低于本地机房的 2.5 寸 SAS 机械磁盘了,更不要说本地机房还须要另外洽购低廉的存储控制器和 SAN 交换机了。

云计算与特斯拉

云数据库能够算是云服务厂商最重要的产品:受众足够广,老本足够低,性能足够高。这一点很像特斯拉汽车,时至今日,特斯拉仍然在疯狂地想各种方法压低生产成本,尽管在提价,然而单车毛利仍然维持在 30% 以上,是 BBA 的 2-3 倍。

Aurora 和 PolarDB 的外围价值是用一种低成本的形式,制作了一个 Oracle 要高老本能力做进去的软件和服务,这才是真的“发明价值”。

计算与存储拆散是一种“低成本”技术

计算与存储拆散并不是什么“高性能”技术,而是一种“低成本”技术:关系型数据的存储引擎 InnoDB 自身就是面向低性能的磁盘而设计的,而 CPU 和内存却是越快越好、越大越好,如果还把磁盘和 MySQL 过程部署在同一台物理机内,肯定会造成磁盘性能的节约。计算与存储拆散的真正价值在于大幅升高了存储的老本。

计算与存储拆散的技术劣势

尽管说这个架构的次要价值在于便宜,然而在技术上,它也是有劣势的:

它显著升高了传统 MySQL 主从同步的提早。传统架构下,无论是语句同步还是行同步,都要等到事务提交后,能力开始同步,这就必然带来很长时间的提早,影响利用代码的编写。而计算和存储拆散之后,基于 redo log 传递的主从同步就要快得多了,从 1-2s 升高到了 100ms 以下。因为主从提早升高,集群中从节点的个数能够晋升,总体性能能够达到更高。

Aurora 的主从同步机制

看了上篇文章的人应该都晓得,在更新数据时,主节点在实现了 redo log 写入,并对内存缓存 Buffer Pool 中相应的数据页进行批改之后,就会返回胜利。这个内存缓存给 Aurora 从节点的数据更新造成了不小的影响:

  1. 主从节点之间只有 redo log 传递
  2. 从节点在拿到 redo log 之后,会刷新本人 Buffer Pool 中存在的数据页,其它不存在的页的信息会抛弃
  3. 这带来了两个问题:

    1. 从节点的客户端在主从不同步的一段时间内,读到的是旧数据,这个须要网关或者利用代码来解决
    2. 从节点的 Buffer Pool 有效性变差,命中率降落,引发性能降落

Aurora 的架构局限

Aurora 的呈现的确独具慧眼,然而也会被时代所局限。

在 Aurora 论文²中,开篇就提到Instead, the bottleneck moves to the network between the database tier requesting I/Os and the storage tier that performs these I/Os。Aurora 认为网络速度会成为云数据库的瓶颈,而在它研发的 2012-2013 年也的确如此,过后万兆网卡刚刚遍及,CPU 单核性能也有余,软件也没有跟上,能够说速度比千兆网卡也快不了多少,所以亚马逊又搞了神奇的技术:存储节点具备本人将 redo log 写入 ibd 文件的能力。

因为这个神奇能力的存在,Aurora 的多机之间采纳传输 redo log 的形式来同步数据,并用一种明天看起来不太靠谱的协定来保障最终一致性:consul 应用的那个 gossip 协定。因为 Aurora 采纳六正本技术,所以每次写入都须要发动六次不怎么快的网络 IO,并且在其中 4 个胜利当前才给客户端返回胜利。Aurora 的确便宜,然而单节点的性能也的确捉鸡,这代表的就是写入性能差,进而限度了整个集群的性能下限。而且,通过比拟长的工夫 (100ms) 能力保障从 从节点 上读到的数据是最新的,这会让主节点压力增大影响集群性能下限,或者让利用代码做长时间的期待,重大的会引起利用代码的执行逻辑变更,引入长久的技术债权。

那该怎么晋升计算存储拆散状况下的集群性能呢?咱们看阿里云是怎么做的。

阿里云 PolarDB 青出于蓝

阿里云 RDS 集群的老本曾经够低了,不须要再用计算存储拆散技术降低成本了,而中国市场的用户,广泛须要高性能的 MySQL 数据库:ECS 价格太低了,如果不是运维不便和性能压力过大,谁违心用你低廉的数据库服务啊。

2015 年,PolarDB 开始研发,过后 25Gb RDMA 网络曾经逐步遍及,所以阿里云将视角放在了网络速度之外:在 IO 速度没有瓶颈当前,基于内核提供的 syscall 所编写的旧代码将会成为新的性能瓶颈。

站在 2023 年初回头看,阿里云的判断是十分精确的。

计算存储拆散架构下的整体性能极限

因为所有节点都应用了同一块“逻辑磁盘”,所以 双主可写 想都不要想,一个计算存储拆散的数据库集群的性能下限就是 主节点的写入性能下限。(Aurora 有多主可写数据库,对 ID 进行主动切分,应用时有一堆限度;PolarDB 也有多主可写数据库,然而更绝:每个库 / 表只反对绑定到一个可写节点,感情就是对多个数据库做了个逻辑聚合,还不如中间件呢。)

在主节点不承受读的状况下,主节点只承接写入操作,以及和写入操作在同一个会话 session 中的后续的读申请。

那 PolarDB 是如何晋升主节点性能的呢?

1. 共享的不是 redo log,而是 ibd 文件

主从之间并不是依附纯属 redo log 来同步数据的,而是间接共享同一个 ibd 文件,即真正的共享磁盘。而且,基于块设施的 Raft 算法也比基于文件的 gossip 协定要快很多。

2. 绕过内核和网路栈:大幅晋升存储性能,升高提早,缩小 CPU 耗费

尽管对 redo log 的解析这一步在 Aurora 那边是存储做的,PolarDB 这边是主节点做的,看似减少了 CPU 耗费,然而这并不是真正的性能瓶颈所在,真正的瓶颈是网络栈和 UNIX 过程模型。看过我《性能之殇》系列文章的人应该都比拟相熟了,这是陈词滥调了。那 PolarDB 是怎么优化的呢?

  1. 跳过 TCP/IP 网络栈,间接应用 RDMA 网络从存储节点读取数据,提早暴降
  2. 跳过 kernel 的线程调度,自行开发绑定 CPU 外围的状态机,采纳非阻塞 IO,在 CPU 占用降落的状况下,提早进一步升高

3. 提出 ParallelRaft 协定,容许局部乱序提交

ParallelRaft 协定让 Aurora 那边须要执行六次的网络 IO 变成了一次:只须要向 leader 节点写入胜利,剩下的数据同步由 Raft 算法来执行,这和 Google Spanner 的两阶段提交优化是一个思路。

原始的 Raft 协定的确逻辑齐备,实现简略,就是一个一个地协商太慢了。ParallelRaft 让收敛协商可能并行起来,减速 redo log 落入 ibd 文件的过程。

4. 主从之间基于低提早的共享存储同步 redo log 数据以刷新 Buffer Pool

基于共享存储的低提早劣势,PolarDB 主从之间应用共享存储来同步 redo log 以刷新缓存,这一点逻辑上和 Aurora 统一,然而理论体现比拟好,我实测主从同步工夫在 20~70ms 范畴内。

5. 单机性能比规范 MySQL 更强

RDMA 存储比本地存储更快,因为缩小了计算和存储争抢中断的问题:IO 这个 CPU 不善于的货色齐全卸载给了 RDMA 网卡。同配置下 PolarDB 比规范 MySQL 的性能要高几倍。

PolarDB 有这么多的劣势,那它付出了什么代价呢?

在各种实测外面,PolarDB 在雷同规格下对其余的云上数据库都领有 2 倍的性能劣势,然而它基于 RDMA 存储的特点也让它付出了两个代价:1. 硬件老本昂扬 2. 扩展性有下限。

是不是感觉很相熟?Shared-Disk 的代表 Oracle RAC 也有这两个毛病。不晓得大家有没有发现,PolarDB 就是云时代的 RAC 数据库:看起来是 Shared-Disk,其实是共享缓存让他们的性能变的超强。

各代分布式数据库的兼容性 / 扩展性比照

一句话概括 PolarDB:利用了高性能云存储并且做了性能优化的一主多从 MySQL 集群。

简略讨论一下 CAP 实践

一个分布式系统中,不可能齐全满足①一致性、②可用性、③分区容错性。咱们以一个两地三核心的数据库为例:

  1. 一致性:同一个时刻发送到三个机房的同一个读申请返回的数据必须统一(强统一读),而且磁盘上的数据也必须在一段时间后变的齐全逻辑统一(最终统一)
  2. 可用性:肯定比例的机器宕机,其它未宕机服务器必须可能响应客户端的申请(必须是正确格局的胜利或失败),这个比例的大小就是可用性级别
  3. 分区容错性:一个集群因为通信故障决裂成两个集群后,不能变成两个数据不统一的集群(脑裂),对外必须仍然体现为一个逻辑集群

在一个分布式数据库系统中,到底什么是能够放弃的呢?我感觉能够从分布式系统带来了什么劣势这个问题开始思考。

相比于单体零碎,一个分布式的数据库,在一致性上提高了吗?齐全没有。在可用性上提高了吗?提高了很多。在分区容错性上呢?单体零碎没有分区,不须要容错。所以,论断曾经高深莫测了:

①和③都是分布式系统带来的新问题,只有②是提高,那就舍短取长,抉择就义可用性来解决本人引发的一致性和分区容错性两个新问题。这也正是目前常见分布式数据库系统的规范做法。

TiDB 和 OceanBase 该怎么选?

TiDB 和 OceanBase 是目前中国 NewSQL 数据库的绝代双骄,争执始终不绝于耳。

TiDB 是承继 Spanner 思维的 NewSQL,对 MySQL 的兼容性个别,基于 key+ 版本号 的事务管制也比拟弱,据说性能比拟好,特地是写入性能。

OceanBase 是基于 Shared-Nothing 思维原生开发的分区存储数据库,其每个节点都反对残缺的 SQL 查问,相互之间无需频繁通信。OceanBase 还反对多租户隔离,这显著就是为了云服务筹备的 (无论是私有云还是公有云),和绝大多数企业无关。另外,OceanBase 对于 MySQL 的兼容性也简直是 NewSQL 外面最高的,毕竟它须要反对支付宝的实在业务,兼容性是硬性要求,业务屎山可没人移得动 (づ。◕‿‿◕。) づ

上面咱们具体比照一下两者的设计思路。

TiDB 的设计思路

我画的架构图如下:

上图中的“SQL 层”就是解析 SQL 语句并将其转化为 KV 命令的一层,是无状态的,上面的存储层才是外围,它叫 TiKV。

TiKV 如何存储数据

TiKV 官网原理图如下:

TiKV 是 TiDB 的外围组件,一致性和事务隔离都是基于它的能力得以实现的。每个 TiKV 领有两个独立的 RocksDB 实例,一个用于存储 Raft Log,另一个用于存储用户数据和多版本隔离数据(基于 key+ 版本号 实现),从这里能够看出,TiDB 的存储存在大量冗余,所以 TiDB 的测试性能才会如此的高,合乎空间换工夫的基本原理。

和 TiKV 并列的还有一个 TiFlash 列存储引擎,是为了 OLAP 在线数据分析用的,咱们在此不做具体探讨。

TiKV 数据分片

除此之外,TiKV 还创造了一层虚构的“分片”(Region),将数据切分成 96MB~144MB 的多个分片,并且用 Raft 算法将其扩散到多个节点上存储。留神,在 TiKV 外部存储用户数据的那个 RocksDB 外部,多个分片是致密存储的,分片之间并没有逻辑关系。

TiDB 的实现格调比拟狂野,所以不兼容的局部比拟多:

TiDB 和 MySQL 不兼容的局部

TiDB 对 CAP 和不可能三角的抉择

TiDB 放弃了新不可能三角中的事务隔离,和 Spanner 一样放弃了 CAP 实践中的“齐全可用性”:一旦呈现脑裂,就会出现意外的返回后果(如超时),因为 TiDB 抉择了保障一致性:如果无奈达到数据强统一,就要进行服务。

一句话概括 TiDB:①搭建在 KV 数据库集群之上的②兼容局部 MySQL 语法的③有一些事务处理能力的高性能数据库。

OceanBase 设计思路

咱们以最新的 OceanBase 4.0 版本的架构为指标进行探讨。

TiDB 底层数据叫分片,那 OceanBase 为什么叫分区呢?因为分片的意思只是数据被离开了(自身 KV 数据之间也没关系),但分区示意的是分区外部的数据之间是有分割的:OceanBase 的每个节点自身,仍然是一个关系型数据库,领有本人的 SQL 引擎、存储引擎和事务引擎。

简略的分区

OceanBase 在建表时就须要设定数据分区规定,之后每一行数据都属于且仅属于某个分区。在数据插入和查问的时候,须要找到这一行数据所在的区,进行针对性地路由。这和第一代分布式——中间件的思维统一。这么做相当于简略地并行执行多条 SQL,以数据切分和数据聚合为代价,让数据库并行起来。而这个数据切分和数据聚合的代价,能够很小,也能够很大,须要 OceanBase 进行精密的性能优化,咱们上面还会说到。

分区之间,通过 Multi-Paxos 协定来同步数据:每一个逻辑分区都会有多个正本散布在多台机器上,只有其中一个正本会成为 leader,并承受写申请。这里的架构和 PolarDB 一样了,此时,客户端的一致性读须要网关 (OBProxy) 来判断,主从之间的同步是有可感知的提早的。

节点存储架构

官网存储架构图

OceanBase 数据库的存储引擎基于 LSM Tree 架构,将数据分为动态基线数据(放在 SSTable 中)和动静增量数据(放在 MemTable 中)两局部,其中 SSTable 是只读的,一旦生成就不再被批改,存储于磁盘;MemTable 反对读写,存储于内存。数据库 DML 操作插入、更新、删除等首先写入 MemTable,等到 MemTable 达到肯定大小时转储到磁盘成为 SSTable。在进行查问时,须要别离对 SSTable 和 MemTable 进行查问,并将查问后果进行归并,返回给 SQL 层归并后的查问后果。同时在内存实现了 Block Cache 和 Row cache,来防止对基线数据的随机读。

当内存的增量数据达到肯定规模的时候,会触发增量数据和基线数据的合并,把增量数据落盘。同时每天晚上的闲暇时刻,零碎也会主动每日合并。

OceanBase 数据库实质上是一个基线加增量的存储引擎,在放弃 LSM-Tree 架构长处的同时也借鉴了局部传统关系数据库存储引擎的长处。

以上是官网形容,我原本想简化一下,读了一遍感觉还是放原文吧,原文形容的就十分的清晰精炼了:OceanBase 用内存 B+ 树和磁盘 LSM-Tree 独特形成了数据读写体系,和上一篇文章中的 InnoDB 是如许像啊!只是 OceanBase 做的更细:跟 TiDB 相比,就像是在 TiKV 下面加了一层 Buffer Pool 一样。

还有一个细节:OceanBase 除了记录日志 (Redo Log) 并批改内存缓存 (MemTable) 之外,只有内存短缺,白天 OceanBase 不会被动将内存缓存中的数据刷洗到 SSTable 里的,官网更举荐每天凌晨定时刷洗。这是什么思维?能够说是空间 (内存) 换工夫,也能够说是拿将来的工夫换当初的工夫。

OceanBase 性能起源之一——充沛的内存缓存

从根底电气属性上讲,磁盘肯定是慢的,内存肯定是快的,所以在数据量大于机器的内存容量时,各种数据库的性能差异能够聚焦到一个点上:内存利用效率,即热数据命中内存缓存的概率。

为了晋升缓存命中率,OceanBase 设计了很多层内存缓存,尽全力防止了对磁盘的随机读取,只让 LSM-Tree 的磁盘承当它善于的间断读工作,包子有肉不在褶上,商用环境中捶打过的软件就是不一样,功夫都在细节里:

  1. BloomFilter Cache:布隆过滤器缓存
  2. MemTable:同时应用 B+ 树和 HashTable 作为内存引擎,别离解决不同的场景
  3. Row Cache:存储 Get/MultiGet 查问的后果
  4. Block Index Cache:当须要拜访某个宏块的微块时,提前装载这个宏块的微块索引
  5. Block Cache:像 Buffer Pool 一样缓存数据块(InnoDB 页)
  6. Fuse Row Cache:在 LSM-Tree 架构中, 同一行的批改可能存在于不同的 SSTable 中,在查问时须要对各个 SSTable 查问的后果进行熔合,对于熔合后果缓存能够更大幅度地反对热点行查问
  7. Partition Location Cache:用于缓存 Partition 的地位信息,帮忙对一个查问进行路由
  8. Schema Cache:缓存数据表的元信息,用于执行打算的生成以及后续的查问
  9. Clog Cache:缓存 clog 数据,用于减速某些状况下 Paxos 日志的拉取

OceanBase 性能起源之二——间接变身内存数据库

为了极致的性能,OceanBase 间接勾销了 MySQL 中“后盾过程每秒将 redo log 刷写到 ibd 文件”这一步,等于放大了集群宕机重启后复原数据的工夫(重启后须要大量的工夫和磁盘 IO 将 redo log 刷写入磁盘),而后把这件事放到中午去做:

当内存的增量数据达到肯定规模的时候,会触发增量数据和基线数据的合并,把增量数据落盘。同时每天晚上的闲暇时刻,零碎也会主动每日合并。

把一整天的新增和批改的数据全副放到内存里,相当于间接变身成了内存数据库(还会用 B 树和 Hashtable 存两份),的确是一种终极的性能优化伎俩,OceanBase 真有你的。

填坑:OceanBase 如何晋升并行查问和数据聚合的性能

传统的中间件 Sharding 技术中,也会做一些并行查问,然而他们做的都是纯客户端的查问:proxy 作为规范客户端,别离从多台机器拿到数据之后,用本人的内存进行数据处理,这个逻辑十分清晰,但有两个问题:1. 只能做简略的并行和聚合,简单的做不了 2. 后端数据库相互之间无通信,没有很好地利用资源,总响应工夫很长。

OceanBase 让所有尽可能地并行起来了:在某台机器上的 proxy(OBServer) 接到申请当前,它会负责协调者的角色,将工作并行地散发到多个其余的 OBServer 上执行;同时,将多个子打算划分到各个节点上当前,会在各节点之间建设 M*N 个网络通信 channel,并行地传输信息;此外,OceanBase 还对传统数据库的执行打算优化做了具体的拆分,对特定的关键词一个一个地做分布式优化,才最终达成了地表最强的成就。

因为自身就是为了兼容 MySQL 而设计的一种新技术实现,所以它领有十分优良的兼容性:

OceanBase 和 MySQL 不兼容的局部

OceanBase 对 CAP 和不可能三角的抉择

因为数据是分区的,所以当脑裂时,两个大脑的数据必定曾经不残缺了,相当于两万行的表只剩一万行数据能够进行查问和更新,此时,如果 OceanBase 梗着脖子非要谋求数据强统一,也是能够让所有的 OBProxy 拒绝服务的,然而 OceanBase 抉择了持续苟着:互联网公司嘛,能实现最终一致性就行了,要啥自行车。

OceanBase 放弃了 CAP 和新不可能三角中的一致性,只能做到最终一致性:为了事务隔离和性能,哥忍了。

其实,不谋求强统一和咱们下一篇《站在地球表面》中的终极高并发架构在思想上是统一的,我想这就是经验过大规模生产利用的数据库,被事实世界毒打过后的痕迹吧。

一句话概括 OceanBase:①世界第一性能的②高度兼容 MySQL 的③经验过生产零碎考验的高性能分布式关系型数据库。

分布式数据库,应该怎么选?

其实,分布式数据库基本就轮不到你来选:利用筹备好了吗?有足够的研发资源吗?性能问题曾经大到压倒其余需要了吗?

如果你有一个正在成长的业务,影响最小、老本最低的计划就是抉择 Aurora/PolarDB 这种高兼容性数据库,等到这类云数据库的主节点达到性能下限了,再对利用做逐渐革新,滚动式地替换每个局部的数据库依赖。

如果压力大到必须换分布式数据库技术计划了,再看看你能取得什么样的分布式数据库呢?无非是在哪个云平台就用哪家呗。

番外篇

Shared-Nothing、Shared-Memory 和 Shared-Disk

Shared-Nothing 只是一种思维,并不是一种明确的数据库架构,它十分抽象,只是形容了一种状态。在这里咱们简略讨论一下 Shared-Nothing。

Shared-Nothing 形容的是一种分布式数据库的运行状态:两台物理机,除了网络通信之外,不进行任何资源共享,CPU、内存、磁盘都是独立的。这样,整个零碎的实践性能就能够达到单机的二倍。

怎么了解 Shared-Nothing 思维呢?把它和 Shared-Disk 放到一起就明确了:

Shared-Disk:多台机器通过共享 SAN 磁盘的形式协同工作,让零碎整体性能冲破单机的极限。Oracle RAC 是这个架构的佼佼者,不过它的胜利并不在于磁盘,而在于它的分布式锁(CACHE FUSION):RAC 利用工夫戳和分布式锁实现了分布式事务和多台机器同时可写,大幅晋升了集群的性能。留神,工夫戳在这里又呈现了。CACHE FUSION 其实曾经能够被称作 Shared-Memory 了。感兴趣的能够本人理解,咱们不再深刻。

21 世纪初,Oracle 推出了 Shared-Disk 的 RAC,IBM 推出了 Shared-Nothing 的 DB2 ICE。十年后,Oracle RAC 倒退的热火朝天,而 DB2 ICE 曾经隐没在了历史的长河中。

然而,2012 年 Google 公布了 Spanner 论文,在十分成熟的世界上最大规模的 KV 数据库之上,构建 SQL 层,实现长久化、事务和多版本并发管制,扛起了 Shared-Nothing 技术方向的大旗,直到明天。

MongoDB 小故事

十年前我在新浪云 (SAE) 实习的时候,听过一个对于 MongoDB 的技术小故事:过后,SAE 的 KV 服务是应用 MongoDB 实现的,在规模大到肯定水平当前,性能会忽然降落,SAE 本人解决不了这个问题,就给 MongoDB 开发组的各位大哥买机票请他们到北京现实国内大厦 17 层现场来帮忙,钻研了几天,MongoDB 开发组的人说:你们换技术吧,MongoDB 解决不了你们这个规模的问题,而后 SAE 的 KV 就更换技术计划来实现了。

DBA 晕倒砸烂花盆

也是在 SAE,我坐在厕所左近临过道的工位(上厕所很不便),某天早上刚下班,我亲眼看到 SAE 的一名 MySQL DBA 从厕所里进去后,晕倒在我背后,砸烂了一个大花盆。数据库作为零碎架构中最重要的那个单点的残暴,可见一斑。

列存储思维

与其将列存储认定为数据库的一种,我倒感觉它更应该被称作一种思维:察看数据到底是被如何读取,并加以针对性地优化。

列存储有点像第一性原理在数据库畛域的利用:不被事实世界所解放,没有屈服于 B 树和它亲戚们的淫威,怯懦地向更底层看去,思考着在咱们大量读取数据时,数据怎么组织能力读的更快。

在读取一行数据时,显然 B+ 树的效率无人能及,然而当咱们须要读取 100 万行数据中的某一列时,B+ 树就须要把这 100 万行数据全副载入内存:每次将一页 16KB 载入内存,循环这一页内的 14 行数据,把这个特定的字段复制进去;反复执行这个操作 71429 次,能力失去咱们想要的后果。这显然是 B+ 树十分不善于的需要。

而列存储将数据基于行的排布翻转过去了:所有数据基于列,致密地排列在磁盘上,这样对某一列的读取就变成了磁盘程序读,即使是机械磁盘,程序读也十分快。

列存储数据库 clickhouse 颇有毛子暴力美学的榜样,和 Nginx 的气质很像

clickhouse 举荐应用尽量多的 CPU 外围,对单核性能无要求,我拿 E5-V2 旧服务器测过,速度的确十分惊人,8000 万行的表,查问起来不仅比 MySQL 快,比 Hadoop 也快特地多。

还记得咱们的指标吗?五百万数据库 QPS

在中国,咱们当初有上面两种计划能够抉择:

  1. OceanBase 曾经蝉联 TPC-C 数年的寰球冠军了,每分钟能够解决 7.07 亿个订单,每秒订单数都曾经过千万了,更不要说 QPS 500 万了,所以,如果你用 OceanBase,你的百万 QPS 的高并发零碎曾经搭建实现了!:-D
  2. 如果你用阿里云,那 1 主 4 从,88 vCore 710 GB * 5 个节点的 PolarDB 集群能够跑到大概 200 万 QPS³。那离 500 万还有不小的间隔呢,不要焦急,咱们下篇文章解决这个问题。

接下来

接下来就是本系列最初一篇文章了:咱们不仅要用架构顶住五百万数据库 QPS,还会找出一个哲学♂方法,打造可能服务全人类的零碎。

参考资料

  1. Google Spanner 论文(中文版)[](https://ying-zhang.github.io/time/2013-Spanner-cn.pdf)[](https://ying-zhang.github.io/time/2013-Spanner-cn.pdf)[](https://ying-zhang.github.io/time/2013-Spanner-cn.pdf)[](https://ying-zhang.github.io/time/2013-Spanner-cn.pdf)[](https://ying-zhang.github.io/time/2013-Spanner-cn.pdf)[](https://ying-zhang.github.io/time/2013-Spanner-cn.pdf)[](https://ying-zhang.github.io/time/2013-Spanner-cn.pdf)https://ying-zhang.github.io/time/2013-Spanner-cn.pdf
  2. 亚马逊 Aurora 论文 [](https://web.stanford.edu/class/cs245/readings/aurora.pdf)[](https://web.stanford.edu/class/cs245/readings/aurora.pdf)[](https://web.stanford.edu/class/cs245/readings/aurora.pdf)[](https://web.stanford.edu/class/cs245/readings/aurora.pdf)[](https://web.stanford.edu/class/cs245/readings/aurora.pdf)[](https://web.stanford.edu/class/cs245/readings/aurora.pdf)[](https://web.stanford.edu/class/cs245/readings/aurora.pdf)https://web.stanford.edu/class/cs245/readings/aurora.pdf
  3. 复盘:我在实在场景下对几款支流云原生数据库进行极限性能压测的一次总结 [](https://cloud.tencent.com/developer/article/2066823)[](https://cloud.tencent.com/developer/article/2066823)[](https://cloud.tencent.com/developer/article/2066823)[](https://cloud.tencent.com/developer/article/2066823)[](https://cloud.tencent.com/developer/article/2066823)[](https://cloud.tencent.com/developer/article/2066823)[](https://cloud.tencent.com/developer/article/2066823)https://cloud.tencent.com/developer/article/2066823

本文由 mdnice 多平台公布

正文完
 0