怎样才是分布式数据库存算分离的正确姿势
vikingapple  2024-06-29 11:27  发布于中国

随着分布式数据库技术在国内的快速发展,存算分离一直是大家津津乐道的热点话题。那么对于一个分布式数据库来说,怎样的存算分离才算是正确的姿势呢。

存算分离的缘起:降本增效

一切都要从企业的数字化转型开始讲起。企业数字化转型是一项系统工程,其中非常重要的一项就是分布式数据库的改造。这里有两个核心关键词“分布式”和“数据库”。“分布式”意味着是要满足大规模集群水平扩展,提供云原生服务的能力;而“数据库”则包含了数据的持久化存储的高可用和数据访问服务的高可用两层需求。

看到这里,小伙伴们可能还没觉得有什么问题,毕竟现在用多台服务器搭建一个分布式集群,似乎也不是什么难事,开源解决方案也有不少。可如果我们深挖下去,这事儿似乎没这么简单。

当前大部分的分布式集群方案,数据库实例之间是通过日志复制完成数据同步的。由于实例之间的数据各归各管,所以有几个实例就要有几份硬盘上的数据副本;反之也一样,需要有多少分副本保证数据可靠,就必须对应运行多少个实例。于是这种绑定关系,不论是硬盘还是服务器,都必须按最大规格来配置。这真的是有钱任性啊!

062910_副本.png

 

钱解决不了的问题:存算一体架构的约束导致不能灵活扩展

钱能解决的问题都“不是问题”,咱暂且放一边,先聊聊其他技术问题。就从容器化和资源池开始吧。直接把数据库放在容器里,是不是就完成了容器化的改造了呢?事情肯定没那么简单。因为数据库的副本是固定在某几台服务器上的,所以故障的切换不能在整个资源池内均衡调度,而仅限于这几台特定的服务器。

062911.png

如上图所示,切换似乎也是能切换的,但是由于不能把任意服务器作为切换的目标,除非预先执行数据克隆,这对于资源池建设目标来说,灵活性显然是不足的。

而真正的麻烦还是扩展能力。讲到这里我们就不得不稍微展开讲讲数据多副本这件事。前面提到了,当前的方案,数据库是在多台服务器上构建了多个副本来实现数据的冗余。那组成多副本的服务器之间的数据一致性怎么保障呢?有的小伙伴已经想到了,用 Paxos 。是的,现在的一些解决方案就是这样做的。咱先把 Paxos 算法实现本身有多复杂放在一边不谈,只要使用 Paxos( 或者也有用 Raft 的 ) 就意味着,每次在想做变更前,都必须发起一次投票获得大部分人支持。 OMG ,这还能快得了吗!更糟糕的是,多个节点可能同时发起变更投票要求获得对方的支持,这就可能会对同一个资源产生竞争乃至冲突。 OMG , again !算了咱要不还是不用 Paxos 了,就用个简单的主从复制吧。什么你又说什么主从延迟,业务压力大了,网络抽风一下没办法保证数据一致性, RTO 还没法保证?还能不能愉快地玩耍了?

在了解了多副本之间的关系和实现上的一些限制之后,我们也就不难理解,现状的方案,其实是两害相较取其轻的一种状态。要么就选择在一个节点上执行读写业务并接受数据在主从之间不能完全一致的风险(比如 MySQL 主从模式),要么就选择忍受多个节点执行读写业务带来的选举开销和协商冲突乃至锁死的问题(例如 MGR 模式)。而且当需要性能扩展的时候,并不能通过立刻增加一批数据库实例来解决问题,因为这些实例所在的节点,根本就还没有数据呢。也就是说数据库的实例是放在容器里了,但是并不能被自由的调度,切换和扩展。

那么该怎么解决上面提到的这些问题呢?

走向存算分离的第一步:把存和算解耦

首先必须打破存算之间的绑定耦合关系。基于共享的存储,解决每个实例自带数据副本无法共享的问题,同时让数据库实例独立于存储实现无状态化。

062912.png

部署方案如上图所示, MySQL 本地不再有数据盘,各自的数据全部都由存储池提供。

但是这只是解决了数据库容器在多个节点之间漂移必须要提前拷贝数据的问题。可数据虽然共享了,但共享的三份或多分数据是由多个不同实例来操作的,因此这几份数据之间的一致性还是要由数据库层来解决。也就是说 Paxos/Raft 等协商机制依然是必不可少的,前面提到的问题也并未被彻底解决。而且,假如这时要增加更多的 MySQL 实例,那存储池里还是要有更多分的数据拷贝出现的,有几个实例存储池就要有几个副本。

前面我们说了,增加 MySQL 从节点和增加数据副本之间本来是不需要绑定的。于是出现了一种业界目前使用比较多的做法,即让数据库实例访问同一份逻辑数据,然后逻辑数据对应于存储内固定的三副本,这样数据副本和数据库实例就无关了。基于这种方式,多个实例之间不需要再有额外数据副本了。

不过能用这种方式的,都要改造内核实现,一般都是宣称可兼容 MySQL 生态的自研内核数据库,或者是一些经过了深度改造的云数据库。开源的 MySQL 数据库是享受不到这种福利的。不过也不用着急,后面我们会讨论解决方法。

062913.png

走向存算分离的第二步:提升存算分离的效率

既然数据都已经实现共享存放,和实例数量解耦了,那是否还需要把数据在共享存储内复制三个或多个副本,占用多倍空间呢?事实上,如果采用多个存储数据副本(一般都是跨存储节点的副本),他们之间依然要解决跨网络的一致性问题,要引入跨网络的协商。而且我们知道为了写三个副本,业界一般有两种做法,一种做法是先把数据从计算节点发到某个存储节点,我们把这个存储节点姑且称为“队长”,他协调其他存储节点的数据全部刷盘之后返回。这种做法很明显的问题就是“队长”要做二倒手,收集完结果再返回,时延太大。另一种做法是直接从计算节点把数据发给三个存储节点去刷盘,计算节点自己承担“队长”校色进行组织协调。这种做法时延固然是比前一种方式低了,可是数据要在计算和存储之间被放大至少三倍,而且作为队长的协调者故障之后处理起来相对复杂。所以现在有些客户会被告知,要么选择时延低流量大,要么选择流量小时延大,还是只能两害取其轻。

其实,既然数据库已经可以访问同一个逻辑副本,这个逻辑副本只要能保证自身的高可靠就可以了。数据搞成三副本只是实现可靠性的方式之一,并不是唯一方法。同时还要考虑避免上面说的时延问题。

走向存算分离的基础:企业级共享存储技术提供了可靠底座

这里我们就要先介绍一下高可用保电内存和纠删码技术。事实上专业的企业级存储,这两项都是标配的看家本领。先说纠删码,这个技术实际是通过校验算法,从 N 个原始数据块计算出 M 个冗余校验快,组成 N+M 份数据块。而其中任何不超过 M 个数据块丢失或者损坏都可以通过计算得出最初的 N 个数据块内容。举个例子,假设 N=8 , M=2 ,计算组成 10 个数据块分散到 10 块盘上去。这时任意坏 2 块盘,数据都不会有任何丢失。而如果基于副本的方式要达到相同保护级别,必须要 3 副本,也就是至少要产生 8x3 = 24 个数据块,数据块占用空间将是利用纠删码技术的 24/10 = 2.4 倍。

再来说说高可用的保电内存,顾名思义就是掉电的时候,数据不会丢失的内存。而且基于专业存储的硬件设计,能支持跨节点保护,存储节点故障业务 0 感知(这部分技术细节有公开的资料,就不在本文展开了)。有了这玩意,数据写入存储,其实只需要写入内存就完事了,基本上就是网络发送的时延。而保电内存后台再把数据做纠删码计算和刷盘。这样还带来了另一个好处就是数据可以大块大块地刷盘。我们都知道硬盘在大块连续刷盘的时候,比小块随机刷的性能要高出几倍。

062914.png

要知道,配备了这两项技术的存储产品,都是现在常年在金融或运营商核心应用中运行的系统,已经是相当成熟的技术方案了。不夸张地说,现在我们银行卡里的钱,很可能现在就存在这种级别的专业存储上。

存算分离的使用:无缝平滑替换,简单易于集成

这个方式看上去很棒,数据也共享了,副本也归一了,可是前面不是也说了,开源的数据库多个实例之间没办法在线访问同一个副本啊。过去确实是这样的,毕竟以前数据库实例运行逻辑是,数据变更要么来自于业务层的操作,要么来自于日志带来的同步,而共享副本就意味着数据变更有了第三个来源,即数据本身被另一个实例直接修改。但这没关系,这也正是我们要讲的一个重点。

为了让开源数据库实现真正的存算分离解耦,多实例访问共享存储数据,我们构建了一个存储加速层,实现主从之间数据的强一致读写。这个存储加速层解决的主要问题就是当多个节点之间有读有写的时候,始终保持节点之间数据视图的一致。在这个基础上,实际上主从之间已经不再有延迟了,从节点可以实时地读到主节点的数据变化。而这个加速层,是可以通过插件直接对接到当前开源数据库上的,无需修改任何代码,已经运行的数据库也无需重新编译,简单配置之后就可以使用,是不是很方便?

极致的存算分离:业务的多读多写

再继续大胆设想一下,如果主从之间都已经实现了 Cache 级数据强一致,没有主从延迟了,那有没有可能从节点直接接受读写请求而不仅仅是只读呢,也就是所有的 MySQL 实例都变成“主节点”?答案是当然可以!

其实这一创新对于分布式数据库的改造可以说是至关重要的。因为强一致的多读多写意味着,我们可以在任意时刻,从任意服务器,拉起任意多个数据库实例的容器,来支撑业务。这是真正的业务按需而弹,哦,不仅仅是按需而弹,由于以前那些 Stand by 的从节点,摇身一变成了可以接业务的主节点,干活效率提升那可是刚刚的,效率提升了也就不需要原先那么多计算服务器空转了。多出来的服务器算力,拿来干点啥不香呢。当然在强一致的基础上,实现多写和一些多读的技术难度完全不在一个台阶上,好在华为企业存储现在已经完全解决了这个问题。

062916.png

 

至此,分布式数据库改造的目标算是基本达成了。

总结一下:

1、 存算之间的绑定关系是成本和业务灵活性的障碍,所以存算分离是业界必然趋势;

2、 存算分离之后,提升存储效率和性能是核心;在高可用前提下,将多副本归一化同时提供极致的时延访问是竞争力的关键;

3、 存算分离共享数据,为主从强一致打下了基础,进一步的可以实现多主多写。而多主多写才是真正的计算无状态化,可以真正的任意拉起实例,任意部署和扩展业务;

4、 分布式数据库改造的关键,是不需要对内核进行改造,存储加速层可以平滑切入现有系统对接业务。

全部回复(
回复
回复