目前,云原生数据库已经被各行各业大规模投入到实际生产中,最终的目标都是「单机 + 分布式一体化」。但在演进路线上,当前主要有两个略有不同的路径。
一种是各大公有云厂商选择的优先保证上云兼容性的路线。它基于存算分离架构,对传统数据库进行改造,典型产品有 AWS Aurora、阿里云 PolarDB、腾讯云 TDSQL-C、百度智能云 GaiaDB。
数据库作为公有云上的核心基础设施,第一要务是实现用户上云的平滑性。目前像云网络、云主机,云盘都实现了完全透明兼容。云原生数据库也必须实现从语法、使用习惯、再到生态上的全面兼容。因此,基于现有生态做分布式化改造成为了一条首选的演进路线。使用存算分离路线的云原生数据库可以完美兼容传统的使用习惯,为交易类场景提供低延迟的写事务能力,同时读扩展性与存储扩展性借助了分布式存储的池化能力,也得到了很大增强。
另外一种路径是先搭建一套分布式框架,然后在其中填充数据库逻辑。OceanBase 和 TiDB 就是其中两个比较典型的产品。它们将事务的子系统和锁的子系统拆分为单独的模块。计算层通过与这些模块交互,可让多个节点均支持写请求。然后由统一的新事务 + 锁中心节点来进行仲裁。这样,对需要较多计算资源的写负载场景会有较好的提升。由于事务和锁都需要跨网络进行交互,因此事务延迟相对较高,在锁负载较重的情况下会成为一定的瓶颈。
目前这两个路线并不是泾渭分明,独立发展的,大家都在向着统一的目标演进。因此我们可以看到,存算分离路线在逐渐增强 SQL 的多级并行能力,同时也在探索和支持多个写节点的库表级/行级的多写能力。同时分布式事务路线也在积极探索在小数据规模下的单机部署架构。
所以在未来,这两个路线会不断融合。业务的数据规模不管多大,都可以平稳快速地运行在数据库系统上,而不需要用户去过分关注分区、索引、事务模型等信息。就像十年前如何在机器之间存储海量小文件还是一个后端研发工程师的必修课,而随着 S3 存储的出现,用户再也不需要考虑如何通过哈希等方式来保证单个文件夹不会保存太多文件一样。
GaiaDB 是从百度智能云多年数据库研发经验积累中逐渐迭代而来。GaiaDB 于 2020 年发布首个版本,首次实现了基于存算分离的大容量存储和快速弹性能力,解决了百度内部的历史库、归档库等大容量存储需求。
紧接着,为了满足集团内大部分核心业务的跨地域热活准入门槛和就近读性能需求,GaiaDB 于 2021 年发布了地域级热活功能。跨地域热活仍然使用存储层同步的方案,同步延迟与吞吐都相较逻辑同步有很大提升,从地域可以实现与主地域接近相同的同步能力,不会成为拖慢整体系统的短板,也不会像逻辑同步那样在大事务等场景下出现延迟飙升的问题。
所以 2.0 版本上线后,GaiaDB 逐渐接入了手百、贴吧、文库等多个核心产品线,解决了业务在跨地域场景下的延迟与性能痛点。
随着业务的逐渐上云,多可用区高可用的需求慢慢凸显,如何实现单机房故障不影响服务成为了很多业务上云的关注点。为此 GaiaDB 打造了可支持跨可用区热活的 3.0 版本,每个可用区都可以实时提供服务并且不增加额外的存储成本。而在今年, GaiaDB 推出了更加智能化的 4.0 架构,性能进一步提升,功能完整度也在持续完成覆盖。
接下来整体介绍一下 GaiaDB。目前 GaiaDB 已经实现了线上全行业场景覆盖,最大实例达到了数百 TB,不仅兼容开源生态,还实现了 RPO=0 的高可靠能力。在成本方面,由于在架构设计上采用了融合的技术理念,GaiaDB 不依赖特殊硬件和网络环境也可以保证性能,实现云上云下一套架构。
接下来我来分享一下 GaiaDB 的性能核心设计理念——通过融合和裁剪,将数据库和分布式存储进行深度融合,为全链路的同步转异步化提供条件,从而实现极致的性能与通用性。
我们可以看到,如果数据库简单使用通用分布式协议和单机存储引擎,如左图所示,那么数据库需要处理主从同步,需要有 CrashSafe 所需要的物理日志。同时,一致性协议也要有主从同步,要写自己的 WAL 以及持久化快照。而单机引擎同样需要 CrashSafe 以及一套日志系统和数据存储逻辑。
我们发现,多层日志的嵌套带来了层层延迟与写放大。更复杂的是,数据流中嵌套多层逻辑后,也给系统整体数据安全带来了一定挑战。同时由于多层之间需要串行等待,所以在加入了网络延迟后会给数据库带来很大的性能下降。虽然可以使用定制化硬件与网络来缩短网络和磁盘落盘的延迟以降低链路耗时,但这又引入了新的不确定性并导致了更高的成本。
GaiaDB 的解决思路是将事务和主从同步逻辑、日志逻辑、快照和存储持久化逻辑重新组合和排布。
首先是将分布式协议的主从同步逻辑融合进数据库计算节点中。由于计算层本身就需要处理主从同步、事务和一致性问题,相关的工作量增加并不大。这样一来,最直接的收益就是将两跳网络和 I/O 精简为一跳,直接降低了链路延迟。
其次 GaiaDB 将多层增量日志统一改为使用数据库 Redo 物理日志,由 LogService 日志服务统一负责其可用性与可靠性。
除此之外,GaiaDB 也将持久化、快照和数据库回放功能融合入存储节点。由于存储层支持了数据库回放能力,可以很轻松实现数据页级别的 MVCC。这样全链路只剩下了数据库语义,数据流简单可靠,逻辑大大简化。
下面我们一起来看下共识模型上的改变。
像 Raft 协议是需要两跳网络才能实现一次提交确认的,右上角就是 Raft 的数据流架构:CN 节点将写发送给 Leader 后,需要等待 Leader 发送给 Follower 并至少收到一个返回后才能成功。
这里就带来了两跳网络和 I/O 的同步等待问题。而 GaiaDB 则是计算节点直接发送给多个 Log 服务并等待多数派返回,这样不依赖任何特殊硬件与网络就降低了延迟。这样系统里不管是事务的一致性还是多副本一致性,统一由计算节点统筹维护,所有的增量日志也统一为数据库物理日志,整体数据流简单可控。
对于数据风险最高的 Crash Recovery 场景,由于统一使用了数据库语义,整体流程更加健壮,数据可靠性更高,降低了数据在多种日志逻辑之间转换和同步带来的复杂度风险。而在性能方面,由于存储层自身具备回放能力,可以充分利用 LogService 层的日志缓存能力。对于写操作来说,不需要每次更改都刷盘,可以批次回放刷盘,大大节省了磁盘吞吐与 I/O。
经过以上改造,线上吞吐性能可以提升 40% 。同时由于链路简化,也大大优化了长尾延迟。像之前计算节点与分布式主节点之间发生网络抖动的场景,就会被多数派的返回特性来优化。
分享完一致性协议层优化,接下来我们来探讨一下链路层优化。
我们知道,总吞吐与并发度成正比,与延迟成反比。一致性协议层改造并缩短了数据链路,可以通过降低延迟来增加吞吐。那么有没有办法通过提升数据流的并发度来提升吞吐呢?答案是可以。由于数据库的物理日志自带版本号与数据长度,所以不需要像通用存储一样实现块级别串行提交。之所以使用通用存储需要串行提交,是因为存储端只能根据请求到达的先后确定数据版本,如果乱序到达,最后生效的版本是不可知的。
而对于 GaiaDB 来说,由于 LogService 具备数据库语义的识别功能,所以计算节点只需要异步进行写入,日志服务就会自动根据数据版本选取最新数据,然后根据写入情况批量返回成功,这样链路就可以实现延迟与吞吐的解耦。
当然计算层依然会等待日志层批量返回的最新落盘版本后再返回事务提交成功,所以依然可以满足提交成功的事务一致性、持久化的要求。
另外针对高负载下 I/O 请求与数据库业务请求争抢 CPU 的问题,我们使用了 I/O 线程隔离技术,通过资源隔离的方式,将 I/O 线程与数据库业务线程进行隔离。这样即使在复杂负载场景下,I/O 延迟仍可以保持在较低水平。
在分析完前面两部分之后,可能会有同学有疑问:既然日志层到存储层不是同步写,是不是最终系统的一致性降低了?有没有可能发生数据丢失或不一致的问题呢?答案是不会。因为 GaiaDB 的存储是一套支持 MVCC 的多版本系统。所以即使回放实现上是异步,但是由于请求方会提供所需要的数据版本,存储层可以提供对应版本的强一致数据视图。
GaiaDB 的存储节点支持数据页的回放功能,可以动态回放至任意目标版本后再返回,在之前的版本里,假如由于异步的因素还没有获取到这部分增量日志,存储节点也会启用优先拉取的策略实时拉取一次日志后再回放,以此来提供较好的时效性。而在最新的 GaiaDB 版本中,我们也在计算层添加了同样的回放能力,存储节点尽力回放后仍不满足需求的,由计算节点进行剩余任务。
这样对于存储慢节点的兼容能力就大大增强了,同时由于存储节点会尽力回放,所以也可以最大化利用存储层的算力资源。对于刷脏逻辑目前也完全下沉到了存储层,存储节点可以自主控制刷盘策略和时机,尽量合并多次写后再进行落盘,大大节省了磁盘 I/O 负载,平均 I/O 延迟降低了 50%。
下图中我们可以看到,在综合了多项优化后,读写性能实现了最高 89% 的提升,其中写链路线路提升尤其明显。这些都是在使用普通存储介质和网络环境的情况下测试得出的,主要得益于数据链路的缩短与同步转异步的自适应高吞吐能力。
在讨论完性能后,再分享一下 GaiaDB 在高可用方面的思考和设计理念。
数据库作为底层数据存储环节,其可用性与可靠性直接影响系统整体。而线上情况是复杂多变的,机房里时时刻刻都可能有异常情况发生,小到单路电源故障,大到机房级网络异常,无时无刻不在给数据造成可用性隐患。
作为商业数据库,具备多级高可用能力是最核心的必备能力。这样才能抵御不同级别的异常情况,有力保障客户业务的平稳运行。GaiaDB 支持多副本、跨可用区、跨地域三级别高可用,创新性地实现了多可用区热活高可用、单个实例支持跨可用区部署。在不增加成本的情况下,每个可用区均可提供在线服务,任何可用区故障都不会打破存储一致性。下面我们来分别看一下每个级别高可用能力的实现。
首先是实例的多副本高可用能力。
GaiaDB 对整体的分布式架构进行了重新设计,系统共分为三层,即计算层、日志层、存储层。
其中计算层本身无状态,仅负责事务处理与一致性维护,所以获得了很强的弹性能力,实现了秒级切换、多节点容灾,同时扩缩容只需要内存启动即可。
日志层负责系统增量日志部分的持久化,实现了多数派高可用。同时由于一致性协调角色上移到了计算层,所以该层全对称,任意节点故障不需要进行等待选主,也不会有重新选主带来的风暴和业务中断问题。
再往下是存储层,负责数据页本身持久化与更新。由于上层保留了增量日志,所以存储层可以容忍 n-1 副本故障。简单来说就是只要有一个副本完好,加上上层提供的增量日志,即可回放出所有版本的完整数据,实现了相比传统多数派协议更高的可靠性能力。
其次是跨可用区与跨地域的高可用能力。
GaiaDB 的多级高可用都是基于存储层物理日志的直接复制。相比逻辑复制,数据链路大大缩短,同步延迟也不再受上层大事务或者 DDL 等操作影响,在主从同步延迟上具有很大优势。
对于跨可用区高可用来说,由于 GaiaDB 具有对称部署架构,所以可以很方便地进行跨可用区部署。这样可以在不增加存储成本的情况下实现多可用区热活,任一可用区故障都不影响数据可靠性。
写数据流可以自适应只跨一跳最短的机房间网络,不需要担心分布式主节点不在同机房带来的两跳跨机房网络和跨远端机房问题,而读依然是就近读取,提供与单机房部署接近的延迟体验。由于跨机房传输的网络环境更为复杂,GaiaDB 添加了数据流的链式自校验机制,使数据错误可以主动被发现,保障了复杂网络环境下的数据可靠性。
对于跨地域高可用来说,由于同样使用了异步并行加速的物理同步,及时在长距离传输上,吞吐依然可以追齐主集群,不会成为吞吐瓶颈,在计入网络延迟的情况下,国内可以实现数十毫秒的同步延迟,这是因为跨地域同样可以使用异步并行写加速,自动适应延迟和吞吐之间的关系。同时地域之间还可以实现主动快速切换和默认就近读取。
所以在使用了 GaiaDB 的情况下,业务可以不做复杂的数据同步逻辑就可以实现低成本的跨可用区与跨地域高可用。
介绍完高性能和高可用两部分的设计理念后,接下来再介绍一下我们正在内部灰度中的新功能:
以上功能预计都会在近期开放灰度试用。
以上是今天分享的全部内容。