腾讯云数据库国产数据库专题线上技术沙龙已圆满结束,本期带来王少华分享的《CynosDB计算引擎关键技术——极致的计算存储分类》直播视频和文字回顾。
关注“腾讯云数据库”公众号,回复“0523王少华”,即可下载直播分享PPT。
请拖动进度条至2小时50分左右观看直播回顾视频
大家好,我是王少华,是CynosDB的架构师。架构师就是architect,其实我觉得我们实际上就是builder,本质上还是程序员。
在工作中,我们除了追求好的设计之外,我们也很乐于去亲手把它用代码写出来。就像艺术家雕琢一件作品一样,我们也很用心地去打磨我们的产品。产品就像我们的孩子一样,在我们眼里面可能觉得是几乎完美的,但是在用户那里免不了有这样或那样的缺点。而这些缺点也是用户的痛点,也是我们不断进行架构革新的动力。
在我的分享之前给大家提个醒,要先把水准备好,因为今天我讲的可能有点干。我分享的主题是“CynosDB计算引擎关键技术”。我自己作为一个做了十多年数据库的人,CynosDB绝对是我参与开发过的最激动人心的产品。
我今天分享的主题比较偏内核实现。这个是分享的目录:首先是讲的我们CynosDB系统总体架构。第二部分是CynosDB计算存储分离。第三部分是CynosDB备机只读扩展,这一块也是由我主导开发的。今天着重点讲计算层的一些关键技术点,我目前的工作主要集中在此。
第一部分,我们原有的CDB(即腾讯云MySQL数据库)架构是基于一个Binlog的主从的复制架构,大家应该都是非常熟悉的。这样一个架构在云上基本满足了大部分用户的需求,但是它并不完美的。作为内核开发人员,我们在日常的值班运维过程中发现这个架构有一些痛点。
第一点它的存储容量是受限的,我们的存储容量是受限于单机磁盘的大小。常见的2T或者4T,就是这样一个级别。通常用户在数据上超过这个限制之后,我们会建议用户分库分表,在业务上进行妥协,但是这个时候用户有可能不愿意接受。因为分库分表之后,用户有一个担忧,就是现有的分布式事务的实现和使用都有一些比较高的门槛,可能带来一些潜在的问题。所以,用户对扩容这方面觉得不方便。
第二点是可靠性。我们有异步复制、半同步复制,还有强同步。异步复制和半同步复制都有丢失数据的可能,而强同步复制则会带来性能上的损失。
第三点是可用性。刚前面一个主题讲了备份,实际上我们的备份也是为了方便系统在崩溃之后能够尽快地恢复。现有架构下,主机崩溃之后我们面临着两个选择:
第一个选项是尝试原地拉起,前提是物理机器是完好的。原地拉起的时候,首先InnoDB引擎拉起的时候首先要进行redo log的回放。这样的过程在系统写压力大的情况下,时间可能会比较长。
第二个选项是把备机(slave)升为主机(master)。在这种情况下,我们需要一个额外的备机。由于主备延迟,备机需要去追主机的Binlog,这个过程也可能会非常耗时。因此我们可以看到HA的时间会比较慢,一般来说是分钟级。
另外一个问题是主从延迟会比较大,基于Binlog的主从延迟范围可以从分钟级到小时级。日常运维中我们发现导致主从延迟的原因有很多,比如说一个大表的DDL,或者一个大表上进行一个没有主键的Delete的操作,或者由于主机上的写压力很大。在我们日常运维中发现,主机写压力到3万或者4万、5万的时候,主从延迟就开始扩大了。随着系统的不断运行,主从延迟会越来越大,导致备机实际上是并不可用的。为什么会是这样的呢?因为Binlog的回放,实际上是执行了一条SQL语句的完整过程。
我们以一条insert为例,它首先要语法解析,生成执行计划,然后在InnoDB层面,还有几个步骤,需要到表里找到一个合适的插入点;找到这个插入点之后,我们会在页面上进行实际修改;在页面的修改之后要去写日志。这样一系列的过程代价是很高的。相对而言,如果是基于redo log的复制,只需要回放对页面的修改即可,前面所有其他的过程都会被省略掉。
第四点是扩展性。在发生单点时,我们需要增加一个新的备。这个时候我们需要一个备份。如果备份已经存在,我们就直接拿备份去新建备机。如果没有备份的话,我们要在当前主机上进行备份。备份文件包括数据备份,还有Binlog的备份。把全量备份拉起来之后,还要去追Binlog。如果备份的数据量在TB级,这些操作的耗时会非常长。这是扩展性的第一个问题。
第二个扩展性的问题是磁盘占用空间。我们添加任何一个Slave节点,都会在新的磁盘里面去拷贝原有的Master上面的全量数据。
这些就是目前现有CDB架构上的痛点。正因为基于这样的一些痛点,我们现在设计了新的CynosDB的架构。
大家可以看到我们黄色的箭头部分,代表的是日志流。蓝色的方框部分这些Master和Slave是我们的计算节点。计算节点Master到Slave之间进行交互的话,它主要传输的是日志流。还有一个比较重要的特点是,我们的整个架构是日志即数据库。我们的存储层具备日志回放的能力,同时能提供多版本的数据页面给计算层。计算层在执行事务的过程中,只写redo log,不写脏的数据页。数据页的生成是由存储层来完成的。这样的架构减轻了计算节点的很多压力。
那么在现有的这样一个架构的情况下,我们是如何去解决CDB的痛点呢?
首先我们要看第一个是存储容量。因为下面存储层是一个分布式的块存储。我们目前的数据容量是可以扩展到128T。
第二个是可靠性。我们的分布式存储系统是三副本的,基本上可以保证我们的数据不丢。
第三个是可用性。Master如果是崩溃之后,我们可以迅速地在原地拉起,如果物理机是好的;或者找一个新的物理机拉起,不需要数据的备份或拷贝。怎么叫快速拉起呢?在原有CDB架构的情况下,我们的拉起之后还有一个日志回放的过程。在CynosDB架构里面,我们的回放在存储层做,计算层就会省去这个过程,所以拉起非常快。依托于这样一个物理复制的架构,解决了另外一个痛点,就是主从的延迟会非常小,达到毫秒级。我们的测试发现,比较典型的是10毫秒,甚至比10毫秒更小,即便是在Master的写压力特别大的情况下,也都能保证。
第四点,扩展性。首先,因为存储层是所有的计算节点是共享的,所以在任何时候添加一个Slave,也就是一个只读节点的情况的时候,没有任何的数据拷贝。计算层的节点直接起来去连接存储层就可以了。因此省去了所有的全量备份,追Binlog以及Binlog回放这些过程,实现了加备节点。只读备节点最多可以扩展到15个。如果用户读压力大,可以增加只读节点,把压力分散到新的只读节点上面去。如果这个压力变小了,可以快速地减掉只读节点。如果我们使用15个只读节点,存储层的数据按三副本算,一个节点只占用了全量数据五分之一的存储空间,非常的节省存储空间。
说了这么多CynosDB的优点,那么CynosDB有没有痛点呢?原有的CDB架构的情况下,IO全部都是在本地的磁盘,这个非常快。目前计算和存储分离的架构,IO变成了网络的IO,所以我们在IO方面是做了很多的优化。即便如此,跟在本地磁盘上还有一定的差距。说到这里,因为在整个架构里面,我们重点要讲计算层的架构和关键技术。我们也要把存储层日志相关的一些处理的流程在这里先讲一下,让大家有一个整体的印象。
首先我们看到上层有InnoDB。InnoDB上有一个remote IO系统模块,来跟存储层进行对接。
接下来我们来看日志流程。第一步,InnoDB写日志发送给存储层,存储层接收到日志之后,放入缓存中;第二步,缓存的日志落盘。完成这个操作之后,我们就立即到第三步,即存储层返回确认给计算层。这三步实际上是一个同步的过程,InnoDB层必须要收到确认才可以提交事务。剩下的4,5,6三个步骤实际上是存储层针对这些日志的处理。还要做什么事情呢?要生成数据页面,虽然是计算层不写页面到存储层,但计算层会向存储层请求读取页面的一个特定版本。
第四步,存储层进行日志的回放,即应用日志到数据页面上来,当它生成这样一个特定页面之后,就可以返回给计算层。
第五步,这些页面是在适当的时机要持久化,写入到稳定的存储介质。
第六步垃圾回收。存储层有一个页面缓存,可以向计算机层提供多版本的数据页面。它需要进行垃圾回收,对计算层不再需要的老版本进行清理。
下面我们来讲,如果要做一个计算和存储分离的单节点系统,在计算层要做哪些工作。
上一个架构图里面,有一个RIO(Remote IO)系统,RIO是指本地的磁盘IO变成了远程的网络IO。InnoDB系统里面原生的AIO接口不能直接使用,于是我们就设计了这样一套RIO的系统,来实现页面的读取,还有日志的写盘。
与原生AIO系统相比,我们做了一些改进和调整。首先是全面的异步化。不管是同步IO还是异步IO请求,都要进RIO队列,IO请求实际上都是异步完成的。其次是并行化。存储层的IO能力是分布到很多存储cell中,每个cell都有独立的IO能力,因此上层的IO请求可以在下层并行化,最大化地利用底层的IO能力来弥补在网络传输上的时延。有了RIO系统之后,计算层与存储层就实现了对接。
第二个要调整的模块是Buffer Pool。大家都知道Buffer Pool就是数据库的二级缓存,类似于CPU的二级缓存,是为了提高数据页的访问速度。Buffer Pool有两个主要的功能:
第一个是是刷脏,脏的数据页面要写盘。在计算存储分离的架构里面,数据页面的生成下放到存储层了,因此,我们不需要对脏的数据页面写盘。但是由于临时表不写日志,存储层是没法去生成临时表的数据页面。所以我们还是要保留刷脏功能,仅针对临时表。
第二个就是淘汰。既然脏页是不需要写盘的,那么理论上所有的脏页都可以被淘汰的。因此,我们实现了一个快速淘汰的算法。当Buffer Pool比较小或者不够用的情况下,经常会因为没有可用的空闲页,需要等待脏页刷盘,从而导致性能抖动。在这种情况下,快速淘汰意味着可以得到更多的空闲页,保证性能平稳。
现在来说日志系统。CynosDB是基于我们自研的TXSQL-5.7来做的。大家可以看到我们计算存储分离的架构里面,日志是系统的核心。日志就是数据库,写日志的效率(性能)很大程度上决定了整个系统的吞吐量。原有的日志系统,有两个问题。首先是写日志是排他的。一个事务写日志到缓冲区,必须要把它锁住,等它写完其他事务才可以接着写。这里就变成了一个瓶颈。另外一个日志写盘。事务提交的时候,要主动去发起日志写盘的操作,即把缓冲区的日志写到存储中。这两个点是现有系统的瓶颈和痛点。官方的MySQL-8.0对日志系统做了很大的优化。我们在CynosDB引入了这个优化。
第一个是并行的写日志。从图中可以看到日志缓冲区,有多个线程在同时写日志。这是如何去做到呢?首先对日志缓冲区做了一个无锁的改造。其次,任何一个事务要去写日志的时候,只需要去先保留一定的日志空间。这个是一个很快的同步操作。在保留出日志空间之后,就可以开始实际写入日志了。它写的过程中并不影响别人去写。在上图中,我们可以看到有三个线程在同时写,这样并发就非常快了。
第二个是单独的日志写盘线程。它会一直检查日志缓冲区,当前日志已经连续写到哪里,可以写到磁盘了(在这里是发送给存储节点)。以上就是日志系统的优化。
现在来介绍异步组提交。日志系统的优化为异步组提交打下良好的基础。数据库内部存在各种各样的锁。在高并发的情况下,锁的竞争会非常的激烈,造成事务的等待时间变长,从而影响系统的吞吐量。解决这一问题最直接的方式就是线程池,在没有线程池的情况下,当压力逐渐增大,从256、512到1024,随着线程数会越来越多的时候,性能并不是直线上升,到后面会往下降。线程池在更高并发的情况下,可以保证内部执行的线程数在一个合理的水平,从而保证系统性能的稳定性。但是线程池对任务的长短又非常敏感。如果一个线程池在等待某个高时延的IO的时候,它的效果可能又并不好了。所以这个时候我们是希望线程池里面的工作线程,它在执行任务的时候不要有太多的阻塞,而且尽量不要阻塞在同步的IO上面。任何一个工作线程去执行一个事务,事务在提交阶段必须要等待日志的写盘(持久化)。由于CynosDB使用的是RIO,写日志的延迟会比写本地磁盘要大一些,线程池的效果其实并不是特别的理想。
因此在线程池的基础上,我们实现了异步组提交。工作线程在事务提交的时,不需要等待日志写盘,而是进入提交队列,然后立即返回。这时它可以返回到线程池,从任务队列中去抓取新的任务执行了。后台的日志写盘线程会持续的检查日志缓冲区,进行日志写盘操作。当日志写盘线程收到存储层的确认之后,就会去检查事务提交队列。这时一般会发现里面有一组事务要求的日志已经写盘完成了。于是就把这一组提交事务再放回到线程池的任务队列里,由一组专门的工作线程来完成事务提交剩下的过程,最终提交事务。
经过我们前面的IO和Buffer Pool优化调整之后,整个系统可以跑了。加上后面日志系统的优化和异步组提交的优化之后,把一个单节点的计算存储分离系统性能提高到较优的水平。
下面主要讲加只读的备节点,大家可以看到我们的黄色部分,是我们的日志系统。先看左边Master,我们有事务,有Buffer Pool,有DDL,有Purge(垃圾回收)。主机发送日志给备机。备机接收到日志之后,先放到日志缓冲区,同时通过日志的回放线程,进行日志记录回放。一般来说,日志只回放到Buffer Pool的数据页面中。但是这里备节点会回放到事务系统和DDL系统中。从图中可以看到,我们新增了三种逻辑日志。其一是事务逻辑日志,用来进行主备read view的同步;其二是DDL日志,用来进行主备DDL的同步;其三是SMO日志,用来进行主备Btree结构变更的同步。下面将针对备机只读的关键点一一进行解读。
首先是日志的应用,日志的应用跟通常的物理复制有所不同。如果页面已经在Buffer Pool中,直接应用日志,这个跟通常是一样的。这里面有一种特殊情况,这个页面在Buffer Pool中,但是还处于IO状态,即还没有读上来。如果等待IO完成,就会影响日志应用的速度。我们的处理方式就是把日志挂到数据页面的日志链表里去。等页面IO完成之后,再由IO线程或用户线程独立进行日志回放。这是第二点,我们做的一个小的优化。第三点,也是我们系统比较特别的地方。如果页面不在Buffer Pool中,就直接跳过日志应用。为什么可以跳过呢?因为存储层可以提供了页面的多个版本,也就是存储层把跳过的日志应用到数据页面,再返回给计算机层。日志应用的速度在系统里面非常的重要,直接影响主备的延迟,CynosDB的主备延迟可以控制在20毫秒以内,通常是10毫秒。
现在来看DDL。首先我们表的定义没有存放在frm文件里面,而是存在InnoDB的表里面。我们增加了一个DDL start和DDL end的逻辑日志,相比而言,CDB系统里的日志基本上都是物理日志。但是我们现在所看到的DDL日志纯粹是逻辑日志。举个DDL的例子,比如我们有进行一个alter table操作,在开始的时候要写DDL start,提交之后要写DDL end。备机是如何回放的呢?备机在回放DDL start的时候,就会对这个table上一个MDL的锁,把这个table锁住,不允许其他线程访问,因为这个table在进行结构的变更。接着回放这些DDL相关的操作,比如系统字典表的修改,新的索引创建,以及数据的插入等等。最后回放DDL end的时候,把这个table对应的内存对象(dict table)淘汰掉,然后把MDL的锁释放掉。当用户下一次访问到这个table时,就会重新去读取这个表的定义,加载到内存中。这个是DDL在备机整个回放过程。CynosDB的DDL有一个什么特点: 主机在执行DDL时,从开始到结束,都不依赖于备机。也就是说备机开始没有或者结束没有,对主机都没有影响。
第四个是Read View。由于只读备机中没有写事务,因此没法自己去构建Read View。在主机上,添加事务开始和事务结束的逻辑日志,主要是记录事务的ID。在备机上,通过回放事务逻辑日志,来生成Read View。CynosDB在此基础上做了两个优化。第一个是批量更新:搜集一个批次事务日志,批量的更新到Read View中。这样做的好处是减少对事务系统的锁占用。第二个是Read View的缓存。读事务从缓存里面去拿取最新的Read View使用,省去重新生成Read View的开销,也避免了不必要的锁占用。
第五个是purge。Purge主要是做垃圾回收的,将不用的记录版本或者删除的记录回收掉。我们主要做了两方面的工作。第一,计算层的主机能不能purge备机所需要读取的版本。备机相对主机是有延迟的,主机不要的版本,备机可能还要读取。因此,需要同步备机上事务提交信息(trx no)给主机。主机在进行purge的时候,需要考虑到备机。第二,存储层不能purge备机要读的数据页面版本。主机每次都是从存储层读取最新的版本,所以存储层总是能够满足主机的页面请求。但是由于主备是有延迟的,备机需要读取相对老的数据页面版本。前面(1.3)的存储日志流程过程中有一个页面垃圾回收步骤。存储层进行页面垃圾回收时,需要考虑到备机的读请求。也就是把备机最小的未完成的页面IO请求的LSN,通知存储层(先发给主机,由其统一发给存储层),这个LSN之前的版本是不需要的,是可以回收的;同时保留这个LSN之后的版本。所以归结起来就两点:第一个是主机purge的时候要考虑到备机的记录读取请求;第二个是存储层purge页面的时候,也要考虑到备机的页面读取请求。
在我们把前面的这些问题解决以后,就到了目前整个备节点读里面很关键的核心技术问题:备机Btree的一致性读。这个关键部分对性能的影响至关重要。它本质上而言就是如何处理SMO操作,即Btree的结构变更,包括Btree分裂和合并两种操作。一般涉及多个节点(至少三个),包括中间节点和叶子节点。这里需要解决两个问题。
第一个问题,备机如何识别SMO操作。SMO的操作是对一系列页面的修改,是一个不可分割的整体。但是目前的物理日志里面无法识别是SMO操作。因此我们在主机中添加SMO逻辑日志,放在整个SMO操作的物理日志全面去,作为一个整体。
第二个问题,备机上Btree访问的过程中,碰到SMO的操作应该如何处理?更准确的说就是游标打开或者游标移动的过程中,碰到了SMO操作,该如何处理。如何保证Btree的一致性读?
我们最先想到的方案是整个SMO日志应用的过程中,对Btree(index)上锁,这样可以确保新的读请求进不来。但是对于已有的读请求,如果是游标在叶子节点中移动,它实际上是不持有锁的。对于这种情况该怎么处理呢?可以在整个SMO日志回放的过程中,对相关的所有页面先上锁,然后再来应用日志的方法来解决。这种实现方式里面还有一个潜在的问题,可能会导致死锁。因为涉及到很多代码实现的细节,这里就不展开了。这个方案有什么缺点呢?日志应用的时候对Btree上锁,有可能会因等待锁导致主备延迟,同时影响备机的QPS。
还有一种方案,通过Buffer Pool的页面多版本来解决。在事务开始的时候,获取到一个一致性的读LSN。在事务执行过程中,它对所有页面的访问都用这个LSN去向存储层请求页面。因此能确保对Btree访问都是其某一个时刻的快照。这个解决方案有什么缺点呢?首先我们现有的Buffer Pool里面,是不支持多版本的。多版本会导致Buffer Pool实际上变小了。如果Buffer Pool的大小为100兆,原来一个页面只有一个版本,现在如果有两个版本,那么Buffer Pool就相当于只有50兆,严重缩水了。其次,会导致一个严重的问题:存储层无法进行版本回收。我们刚才也谈到了(3.5),存储层需要去purge那些不需要的页面版本。如果有一个长事务一直不提交,其需要的老版本页面在存储层需要保留,无法回收。这样的设计对存储层的考验非常大。
考虑到以上这两种方案的弊端,我设计了一个新的方案来解决,基本的思路是,在访问Btree的过程中,如果发现页面处于SMO中,则保存游标位置,重新打开游标。
如图是一棵Btree结构示意图。一个完整的SMO的操作包括了对P1,P2,P3三个节点的修改。这是一个分裂操作:P2分裂成了P2和P3,父节点是P1。SMO日志按顺序备机中回放。P1和P2是黄色,表示的是P1和P2的日志已经回放了。P3是红色,表示日志没应用。此时,Btree处于SMO过程中,结构并不完整。
我们对SMO的处理分四个部分。首先,新增的SMO的日志来标识Btree的分裂或合并。其次,在备机日志应用SMO日志的时,我们更新index上的sync_lsn来标识Btree的SMO状态,这样SMO的日志标志进行了转换。然后,访问Btree页面的时候,我们要判断这个页面是否在SMO中。在图中,不管是访问P1还是P2,它们都是在SMO中。最后,碰到这个SMO,我们如何去处理呢?我们重新打开游标。如果我们访问的页面是P1,说明我们是一个游标打开的操作。这时我们需要去释放之前锁定的这些页面,回到根节点把游标重新打开。如果我们访问的页面是P2,可能是一个叶子节点的扫描操作。这时候需要把这个游标位点先保存,然后再重新打开游标。
为什么重新打开可以成功?在日志回放的过程中,页面P1、P2回放了,P3没有回放。在重新打开游标之前,会一个短暂的睡眠(1毫秒),这个时候P3的日志已经回放完了(如果没有回访完,则继续重试)。这时Btree结构是完整的,重新打开游标就可以成功了。因为Btree上数据都是有序的,不管它的结构怎么变更,都可以通过位点可以重新定位回来。
这样的方案有什么优点呢?首先很明显,回放全程没有对Btree上锁。其次是游标级别的重试,代价低。最后一个特点有必要说明一下,SMO日志不必作为一个整体回放。比如对P1、P2、P3的回放,不必把它们先全部锁定后一起回放,只需要分别单个页面进行回放就可以。
这里再总结一下,CynosDB的Btree一致性读是通过首先去识别某一个页面是不是在SMO的过程中。如果是的话,我们是通过重新打开游标来解决这样一个问题。Read View是为了解决逻辑一致性(记录可见性),而Btree SMO的处理是为了解决物理一致性(记录完整性)。
Q1:像CynosDB这种共享存储的架构,如果底层的存储层或者是硬件磁盘故障了,怎么做高可用呢?这个问题请王老师解答一下。
A1:这个问题问的非常好,我们刚才也说了,我们存储是三副本的,实际上我们三副本如果全部都坏了,这种情况下怎么办。首先,我们现有的解决方案有两个。第一,我们是支持快照备份,备份肯定是必须要做的,不能因为有了我们的分布式存储我们就不做备份了。我们叫快照备份,在页面存储层,在块存储上进行快速的快照备份。存储层有什么问题的情况下,快照备份是可以用来还原的。其二,我们后面会推出来我们在跨AZ或数据中心的情况下,基于redo log复制的standby集群,在这个集群上有同样的存储节点。
Q2:刚才提到了CynosDB的只读扩展的Purge的技术。这个技术的话,主机Purge是需要考虑备机的读请求的。这样的话,如果备机上面的大量的读访问会影响这个Purge的速度。有一种情况,备机上存在一个读的事务夯住了,那么主机是不是它的Purge的操作就执行不了了,就卡在那里了,性能就会受到一定的影响?
A2:这个问题也是我们要考虑去解决的。我们的初步设想是,主机去Purge的时候不要去考虑备机。如何去做到呢?要让备机访问历史版本的时候,知道它的历史版本已经没有了,返回错误即可。这个问题确实问的非常好,这个是我们后续要重点解决的。在现有的情况下,我们实际上还有更简洁的解决办法。我们如果发现备机和主机之间的Purge的相差比较大的情况下,可以想办法把备机踢掉,但不是特别友好。最终的根本的解决方案还是希望备机能够识别这个版本没有了,让它进行重试或报错,这样可能更加友好一些。
Q3:CynosDB数据库很大的优势在于它的弹性能力,因为它的计算与存储是分离的,刚才王老师也介绍了,可以秒加计算节点。这个存储节点的扩容,它的速度和性能是怎么样的?我的存储容量不够了,要从6T扩展到10T,这个效率和性能是什么样的,有请王老师回答一下。
A3:我们可以看到,现有的存储是一个分布式存储系统。本质上而言是有很多的存储节点,是按需的分配。如果现在是2个T,我们需要扩展到4个T的时候,存储系统本身是有这么大的存储能力的。我们现有的这样一个存储池里面,我们假如有1千个T,实际上你如果从2个T变成4个T,我这个存储池里面是可以随时去分配的。大家也看到我们的存储容量,我们做了一个简单的限制是128T。这个就是我们主要做一个逻辑上的限制。实际上我们如果说受限于整个递增存储的容量的,这是第一点。
第二点,现在底层的存储层实际上是非常大的,你这样是不是有浪费,这个实际上不用担心。我们存储池并不是为了专门某一个计算节点来用的,我们实际上是有多个计算节点都是可以去共享存储池。在逻辑上可以通过逻辑卷进行区分,进行划分。所以,因为我们在限制了它的容量是128T,我们肯定能保证容量是能达到128T。
我再多说一句,大家对存储层确实也很感兴趣。希望有机会我们这边做存储层的同事也可以来给大家分享一下我们存储层是如何做到这样一些弹性,页面的多版本的各种方面的支持。
↓↓更多惊喜优惠请点这儿~
云数据库 超值采购专场