从单机到分布式数据库存储系统的演进

存储系统概览

存储系统是指能高效存储,持久化用户数据的一系列系统软件。在众多的存储系统中,以下是三类比较主流的存储产品及其特点分析:

块存储

底层语义,基于block编程;

接口朴素:在Linux的IO软件栈中,要直接使用块存储的话就要基于LBA编程,因此接口较为简单朴素,再加上块存储本身处于整个存储软件栈的底层,这导致块存储使用起来并不十分友好;

追求低时延、高吞吐:研发一个块存储系统,在设计目标上我们往往会追求超高的性能,体现在超低的时延和超高的吞吐。但考虑到块存储的接口确实过于朴素,往往只有一些追求超高性能的系统才会直接基于块存储构建,然后自建应用层cache。

对象存储

成本优先:一般不苛求单次操作的时延,但是非常注重系统吞吐存储成本。

文件系统

接口语义丰富,普适性强:遵循POSIX/弱POSIX语义,诸如Open、Write、Read等许多操作数据的接口都能在文件系统中被找到。

拥有较多开源的分布式实现,生态良好。

一般也不苛求时延,注重系统吞吐存储成本。

单机数据库存储解析

单机数据库存储,要从内存层和持久化层两个方面来解析。在内存层,仅说关系型数据库,其内存数据结构特点可以总结为:一切都是“树”。我们以最常见的B+树为例,B+树具有以下突出的特点:

Inmemory操作效率非常高:B+树搜索时间复杂度是log级别;并且B+树的叶子节点构成链表,非常有利于在内存中对数据进行scan操作。

磁盘操作效率高:B+树的Fanout足够大,树的层级较少,呈矮胖状,可以减少磁盘IO数;同时B+树的非叶子节点只存索引数据,叶子节点存实际数据,能大大压缩树高,进一步减少磁盘IO数。

数据结构高度统一:数据索引都可以直接组织成B+树,因此代码的可维护性、可读性和开发效率都比较好。

仅有内存数据结构当然是不够的,我们还需要设计高效的磁盘数据结构,下图展示了从内存数据结构到磁盘数据结构的数据持久化过程:

左边虚线框描绘的是InMemory结构示意图。举个例子,如果我们要修改PageA的某一行数据,对其中的一个字段进行自增,自增值是2。自然而然会产生一个数据库的物理操作日志,即RedoLog,用来描述我们对PageA的修改。同时,在数据库的事务执行过程中,可能还会产生大量临时数据(图里的Tempdata),当内存不够用的时候也需要将其持久化。

右边虚线框描绘的是InPersistentLayer的示意图。假设我们使用比较友好的文件系统来将内存数据持久化,我们需要设置不同的文件,让它们各司其职。例如图里的蓝色文件存储Page,绿色文件存储RedoLog,粉色文件存储临时数据。如果数据库发生crash,在恢复阶段我们就在各类文件中进行数据定位,结合RedoLogFile和PageFile,进行数据库的数据恢复。除此之外,如果直接基于块存储进行持久化,就需要数据库本身的存储引擎管理好LBA,需要在用户态里面实现buffercache等逻辑,这也是可行的。

那么基于单机的FS/块存储去做持久化,我们会遇到哪些问题呢?通过下面的单机数据库系统的典型架构图,我们可以发现三个问题:

单机容量瓶颈:在Database层的单机服务器上运行着database进程,服务器上挂载了大量本地磁盘用作数据持久化。但一台物理服务器能挂载的磁盘容量总是有限的,这就导致了单机的容量瓶颈问题。

扩缩容困难:当容量、CPU或者内存等资源不够时,我们需要进行扩容。在单机时代,扩容意味着将数据从这个磁盘搬迁到另一个磁盘。但不管我们是通过网络还是有线连接手段,都需要花费一定的时间,这可能导致业务较长时间的停写(不可用),因此扩缩容是非常困难的。

多份独立数据,成本高:如果我们要在“复制集”之间或者主备机之间去做数据冗余或数据同步,那么每新增一分计算能力(新增一个计算节点),就要新增一分存储冗余,就会导致存储成本提高。

分布式数据库存储解析

为了解决单机数据库存储系统面临的问题和挑战,字节跳动的数据库团队调研了一些业界主流的分布式数据库方案。

MyRocks:MySQL+RocksDB

需要说明的是,MyRocks不是分布式数据库或者分布式解决方案,它是单机SQLoverkv的典型代表。

核心理念:用RocksDB替换InnoDB。使用RocksDB能够有效缓解单机容量瓶颈的问题;

特点:一是:数据可压缩比例较高。RocksDB实现了一种比较优秀的压缩算法,根据实际调研结果显示,在关系型数据库场景,基本上它能实现2-4倍的压缩比,能有效缓解单机的容量瓶颈问题。例如,单机原本挂载了10块磁盘,只能承载10TB数据,使用RocksDB就能在不改变硬件条件下帮助单机承载20TB或30TB等更多的数据;二是,顺序写性能较好,这也是LSM-Tree这种数据结构在HDD年代出现的核心原因。

难点:Compaction会导致性能抖动,且兼容性一般。众所周知,RocksDB基于LSM-Tree构建,必然会遇到一些典型的LSM-Tree-based系统的问题。虽然RocksDB对顺序写特别友好,但它一定程度上牺牲了读性能——RocksDB在读的过程中会触发Compaction,可能引发性能抖动,导致前台的写出现卡顿现象;同时,这一类SQLoverkv解决方案的兼容性能表现较为一般。

AmazonAurora:计算存储分离

核心理念:计算存储分离,LogisDatabase。

特点:架构灵活,存储层带有特定的数据库计算逻辑,除了具备存储能力之外,还具备RedoLog解析、回放生成数据库Page、维护多版本数据的能力。

优势:兼容性强、读扩展能力较优。基于共享存储系统的特点,AmazonAurora的读计算节点具备较好的扩展性,能够实现一主15备的部署形态,其兼容性、读扩展性表现较好。

Spanner系:Shared-Nothing

核心理念:计算存储分离,且Share-Nothing。

特点:Spanner系的数据库系统一般基于分布式k-v存储构建,由存储层保证事务特性,计算层做成纯计算的无状态节点。

难点:要解决当前数据库生态兼容性问题分布式k-v系统的hotspot问题比较麻烦。

最佳实践:veDB分布式存储系统

基于上述字节数据库团队的调研结果,我们设计了veDB分布式存储系统以解决单机数据库存储系统面临的问题与挑战,本节将主要介绍veDB分布式存储系统的系统目标与核心技术特点。

系统目标

在设计理念上,我们期望存储系统能够实现以下四个主要目标:

极致弹性:存储节点与计算节点解耦,随时弹性扩缩容;

极致易用性:构建one-size-fits-all的存储系统,而非专用存储,要能兼容多个主流数据库(MySQLPostgreSQLMongo……);

极致性价比:低时延、低成本;

极致可靠性:具备高性能、高可靠的备份恢复能力。

基于以上系统目标,数据库团队设计并开发了veDB分布式存储系统,如下图所示:

从图中可以看出,分布式存储层基于LogStore和PageStore这两个子系统构建,其系统特点与我们的设计目标相互呼应。

高弹性:存储层可独立扩缩容,计算层完全不感知;

高性价比:在LogStore实现了高性能Log存储在PageStore实现了低成本Page存储;

兼容性好:LogStore和PageStore都支持多DBEngine插件化;

高可靠:PageStore侧支持Segment级别的PITR功能。

核心技术

以下主要从研发背景(Problem)、解决思路(Solution)、解决成效(Outcome)三个方面来分别介绍veDB分布式存储系统的五个核心技术。

DistributedDataModel

Problem:从单机FS到分布式存储,需要有高效的数据布局模型。基于单机的文件系统或块存储系统去实现数据持久化是比较简单的,我们可以直接通过申请一批LBA或者一批文件来存储数据,然后控制并发即可,但是这对于分布式存储并不容易。从上面的示意图可以看到,最上层的Tablespace代表一张数据库表,里面可能包含上百万甚至上千万的Pagedata(数据库的基础管理单元)。然而存储系统的管理单元,却不可能是Page——Page的粒度过小,往往只有KB级别,如果存储层以过小的粒度去管理数据,可能会造成元数据膨胀,增加管理成本。

Solution:Tablespace-Segement分布式映射。基于上述问题,我们可以在存储层利用相对大的管理单元Segment去进行数据管理。此时,数据库的管理单元是Page,存储系统的管理单元是Segement。Tablespace和Segement之间必然要存在一层映射关系,该映射关系可以根据不同数据库引擎的数据管理空间大小要求进行设置,可能MySQL和PostgreSQL的映射规则就大不相同。上述示意图展示了最简单的模2规则,我们也可以发展出其他更加复杂的打散规则,此处不进行赘述。当我们将Page打散到对应的Segement之后,数据库就不需要管数据Replication的逻辑,不管底层存储是多副本还是EC策略,可以完全由存储系统来做透明的Replication,数据库就像在使用单机文件系统一样简单。

Outcome

天然负载均衡;

分布式打散,可最大程度实现并行计算;

Scalein/out简单,仅需部分Segement数据rebalance,摒弃了将整个数据库表的TB级数据在硬盘间搬迁的繁杂流程。

Log-OnlySegement

Problem:数据冗余成本高,需要降低存储成本。

Solution:开发Log-OnlySegement,节省非必要的Page副本空间。什么是Log-onlysegement?关系型数据库中往往都包含Log数据和Page数据。在存储层中,存了多副本的Log数据后,我们可以选择性地只回放一部分Log数据来生成Page,让另一部分Log数据保持不动,不要生成任何Page数据。以上面的示意图为例,Rep_0和Rep_1都是Log数据生成的各种版本Page数据,然而Rep_2是一个空的Page数据副本,它里面只有Redolog。我们都知道Redolog和Pagedata的数据大小比例是比较夸张的,Pagedata的大小可能是Redolog的几倍甚至十几倍,因此通过以上方法能够较大的节省单机的Page存储空间。

Outcome:结合单机引擎的压缩算法,能将存储空间放大倍数从3.,较好缓解成本问题。

高性能IO引擎

Problem:存储层写性能容易成为系统性能瓶颈,如何解决?

Solution:全异步IO+无锁结构+并发打散。当数据库提交了一个Redolog到LogStorage之后,LogStorage中会有一个无锁的Ringbuffer去对Redolog进行有序组织,然后我们将RedoLog的Ringbuffer进行线性的定长切割,并发打散到底层存储的Blob单元。

Outcome:4KB+depth8,writelatency~100+us,较好支撑了数据库下发日志的性能刚需。

PITR

PITR(Point-in-timeRecovery)是指我们都可以迅速地恢复在过去一段时间内某个时间点的数据库快照。

Problem:如何快速备份恢复,且降低对前台业务影响?

Solution:基于Segement的高并发PITR机制,Segement间互不影响。之前提到存储层的管理单元是Segement,我们也可以基于Segement做备份恢复。这样做有两个好处:首先计算层是完全透明的,计算层完全不会感知,并且计算层的性能不会抖动。其次基于Segment可以做到天然的并发打散,因此备份恢复也可以做到并发恢复。

Outcome

性能优秀,恢复1TB数据~15min;

扩展性强,不受数据大小影响,性能与数据大小呈近常数关系:因为基于Segment单元去做并发备份恢复,每个Segment都是独立的,其性能能够与数据大小解耦开来。因此不管数据大小是多少,只要备份恢复资源足够,都能做到常数级的备份恢复性能。

多计算引擎插件化

Problem:数据库团队希望统一的存储层能够支持不同的数据库引擎,做到100%兼容和快速接入。

Solution:WriteAheadLog+LogReplay=任意PageData。基于本地存储引擎的k-v结构,或者基于裸的块设备抽象出一种相对通用的数据结构,从而高效地存储Pagedata。同时,我们在SDK侧和Server侧都做了Logparse的插件化,要接入新的数据库引擎只需要其提供适配存储接口的日志插件,从而可以快速接入各式各样的数据库计算引擎。

Outcome:

基于统一接口,计算引擎仅需提供Logparse+Replaylib即可接入veDB存储层。

统一存储层已支持MySQL、PostgreSQL、MongoDB计算引擎,目前仍在持续拓展。

数据库存储系统:What'sNext

在谈及数据库存储的未来演进时,首先我们可以思考一下哪些因素会触发数据库存储架构的变革和演进?答案可能包含:存储架构自身的革命、数据库理论的突破、或者新硬件冲击引发存储系统架构迭代。基于这三个方向的思考,我们总结了以下几个数据库存储系统的演进趋势:

HTAP/HSAP

我们总结的第一个趋势即HTAP/HSAP系统将会逐渐爆发。在HTAP/HSAP系统中,“实时”是第一关键词。为了支持实时,存储系统可能会发生架构演进和变革,因此我们需要探索:

行列存All-in-one:既要存储行式的数据,又要存储列式的数据。

近实时,写时计算:我们需要在存储层实现写时计算的逻辑来支持实时性。

AIEnhancement

AI技术运用领域广泛,具体在数据库存储领域,我们可以利用AI技术进行以下工作:

存储参数调优;

智能存储格式:利用AI技术进行智能的行存和列存格式转换,AI可以提醒我们什么时间进行转换,什么时候绝对不能转换,从而避免格式转换为前台业务带来的性能overhead。

HardwareRevolution

在硬件变革趋势上,我们总结了三个变革方向:

计算单元变革:CPU产品已经从multi-core变成了many-core(从96c变成了192c、384c)。要怎么利用多核的能力?对于非计算密集型的存储系统而言,多余的算力能否用来加速数据库算子?一些无锁的数据结构是不是需要要重新设计?以上都需要我们认真考虑。

网络设施变革:例如RDMA,以及可编程的P4交换机这类全新的一些网络设施,可能会对我们的软件架构特别是分布式存储架构造成较大的冲击。相应地,我们需要在存储侧做出调整。

字节跳动基础架构数据库云存储团队

DatabaseCloudStorageTeam,服务于字节跳动全系产品。在这里,我们有丰富的云存储产品,负责治理数十EB级别的海量数据;有多种数据库产品,提供极致时延、超大吞吐的云原生数据库服务;有前沿的技术研究,探索新硬件与新软件架构的融合,打造下一代革命性的云存储与数据库产品。

版权声明:本站所有作品(图文、音视频)均由用户自行上传分享,仅供网友学习交流,不声明或保证其内容的正确性,如发现本站有涉嫌抄袭侵权/违法违规的内容。请举报,一经查实,本站将立刻删除。

相关推荐