云与分布式是数据库发展的两大趋势,那云时代下新一代数据库会是什么样的呢?腾讯云数据库专家工程师窦贤明讲师给大家分享了自己的畅想, 基于冷热分级存储与ServerlessDB结合的新一代数据库 。基于腾讯云数据库TDSQL-C PostgreSQL在云原生这条路上的一些探索,重点从Serverless 数据库和分级存储(冷热分离)的设计与实现两个方面进行分享。内容主要分为四个部分:

第一部分:介绍云时代的数据库的背景;

第二部分:探讨云上数据库进化的逻辑是什么、方向是什么;

第三部分:描述Serverless数据库具体是什么样子;

第四部分:云原生数据库在存储方向上的进一步演进,分级存储所达到的效果、在冷热分级等场景下的一些用例。

公众号福利 :本期讲师课件获取方式, 腾讯云数据库 公众号后台回复“ 5.7内核课件 ”即可。

云时代的数据库

在过去一二十年间,整个关系型数据库行业最大的变化只有两个,一个是  ,一个是 分布式 。

云时代,对数据库产生了一个非常大的一个冲击,或者说变化。就Gartner近期数据,云上数据库的份额也已经赶上并即将超过on promise(传统方式)的产值。

那云时代的数据库是一个什么样子呢 ?以腾讯云的TencentDB for PostgreSQL为例。云数据库的第一个阶段,其实是在将传统数据库搬到云上来。首先,最开始部分是基础环境,比如说硬件资源、网络、存储之类;在此基础上,进行一些虚拟化,这些是云本身具备的能力;在用户侧,资源准备好了之后,是一个资源的管理分配和运行环境的准备;然后是做云数据库托管的一些事情,包括部署、HA、备份恢复等,还有监控这些;那整体上还是一个PaaS平台这么一个事情。这个过程中,整体来讲还是将传统的主备搬到一个云环境这么一个过程,其实并没有对数据库的内核或者说数据库的架构产生一些根本性的变化。

这其实是在过去几年云数据库或云的一个演进的第一阶段,把原来的数据库运维,以云的方式托管起来、在云上使用起来。

云原生大数据平台_mysql

那在这期间是怎样一个实现方式呢?首先,会有一个云数据库的一个部署,即实例进程运行在虚拟机里面、存储则放在一个云盘存储上;然后会建立一个备库,主备之间通过Replication实现数据的复制,通过两份完整的数据节点实现高可用。这一点,与当前物理环境并没有什么本质上的变化,即 一主一备 的方式。

即使如此(简单的实现),云数据库相比传统数据库仍然会有很多的优点。

第一, 成本更低 ,当前主要是云本身的特质带来的;第二点就是 扩容能力更好 ,比如说它扩容能力好的是在于说存储这里可以动态扩容,计算这里可以更为轻量的扩缩容;第三点,是 体验上也有非常大的提升 。

云原生大数据平台_mysql_02

然而,仍然有些问题没有解决,尤其是在站在云的视角来看。当有越来越多的数据库实例跑在一起的时候,发现这个 成本的增长是线性 的,成本上是没有去得到一些根本性的降低。

就一主一备的情况来说,有两份完全一样的数据;当我们再新加一个RO(Read Only节点,仅用于读请求)的时候,还会再加一份完整的数据。存储成本没有根本性的收敛,根据RO的数量线性增长。

而另外一种情况, 网络存储 成为一个瓶颈。再拿这个例子来说,每次读写都会对网络形成一个吞吐,且随着RO数量增加也是一个线性增长,对网络总流量造成较大的压力。

RO节点(Replica)的建设时间成本也是一个问题 。多添加一个RO节点,就是多一份数据,是完整的一个复制(对应存储上的三副本),复制时间较长。

云原生大数据平台_mysql_03

云原生进化

云原生数据库( Cloud Native Database )的提出,是 为了解决原来传统架构下无法解决的这些问题 ,基于云基础设施重新设计与实现所提出的一个解决思路。

那其中核心的解决思路是什么?答案就是 存算分离 。

可以思考一个问题:主节点和 RO 节点各自有一份完整的存储,且各自都有三副本。为什么我们这些节点不共用同一份数据呢?这里很容易就想到一点,就是我们把所有节点的数据都放在远端分布式存储上,不再本地存放。这样的话,存储就可以实现仅有一份数据(三个副本),而计算仍然是多节点。

云原生大数据平台_mysql_04

把数据库内部拆开来看,基本上来讲分为两部分:一个是 存储层 ,一个是 计算层 。计算层一般包含词法解析、语法解析、语义解析、查询重写、优化器等。下一层则是数据缓存,相对设计逻辑比较简单一些,这部分一般不单独列;中间这个事务层,保证数据存储、读取的正确性;最下层storage层负责跟实际的存储硬件打交道。

既然要把所有节点的数据放在同一个分布式存储(租户)上,就需要将数据库内核的引擎和存储部分拆开到两个地方运行,存储的部分放在分布式存储系统内运行,把引擎的部分放在计算节点中运行。表现为所有的RW、RO都没有实际的数据,只需要内存和CPU的资源拉起来即可,这个时候RO启动的效率就非常高,本身就很轻。RO则通过Replication从RW拿到更新的修改,去更新它内存中的缓存。

那前面也有讲到网络成为瓶颈的问题,需要分别针对 RW和RO来说明。

针对 RW ,有一个 WAL的概念,即Write Ahead Log,所有数据的变更都会记录在这里。这里做一个极端假设,假如从数据库被初始化之后所有的WAL都被保留、且有一台非常非常强大的计算机,在每次读取数据时,都将最开始到最新的所有WAL全部重放到当前时刻,其实是可以得到与当前数据库中完全一致的数据。这一点,可以描述为Log is Database。

如果 WAL 能够对应一份完整的数据,那么在写入存储时,可以不写入数据部分、仅写入 WAL。存储层在收到WAL之后,基于存储上已有的数据部分,对WAL进行不断的重放,就可以实现数据不断的更新,保证数据的一致性。这里具体的实现较为复杂,不再作展开。 达到的效果就是,至少减少一半的网络流量 

RO 刚才已经简单说过一些,在通过 Replication获取到WAL之后,会对缓存中数据进行更新。当需要从存储上读取数据时,根据该数据页的时间戳,将其后的WAL更新上去,也因此,RO需要在内存中缓存一份近期的WAL,得到一个保证一致性的最新数据页。

整体来讲,通过以上的机制,实现数据存储在分布式存储上主备节点采用同一份存储,达到RO节点增加存储成本不变的效果。也因此,RO的数量支持最大到15个。

云原生大数据平台_云原生大数据平台_05

存储计算分离之后,刚开始优势未必特别明显,在使用上和前面的云数据库没有本质的区别,用户体验基本一致。效果会随着使用的加深而逐步体现出来。

第一, 扩缩容的效率完全不一样 ,原本在扩容的时候,有可能出现空间不够需要迁移,导致时间成本非常高。计算变得特别轻,可以快速拉起、关闭,迁移效率极高,不用担心扩容时需要迁移的情况。

可用性、可靠性 等方面,因为所有的状态都存储在分布式存储中,计算节点的启停(可用性),不会影响存储上数据的可靠性,因此在计算节点出现故障时,可以随意关闭老节点、启动新节点,不用担心会丢失数据,可用性方面达到了较高的保证;存储上数据有三副本,保证了数据的可靠性;且多个节点共用同一份存储,整体成本也更低。

针对计算来说,计算节点被做得轻量、可以便捷地启停,当这份便捷性达到一定水平的时候,就会引起质变。

云原生大数据平台_mysql_06

极致弹性

正常来讲,业务有高峰低谷,比如订餐系统。一家餐饮公司的订单系统,肯定是有高峰和低谷,基本上是三餐的时候比较高,夜里几乎为零。那没有业务在运行的时候,为什么还要这个计算节点付钱?在传统方式下,需要准备一台物理机; 在云数据库形势下,则以实例为单位,计费的粒度仍然较粗。那怎么去做呢 ?

云原生大数据平台_缓存_07

这里可以考虑这样的产品形态,在用户端呢, 计算节点在不用时不计费,在真正使用时再拉起并开始计费;且扩容也不再需要用户操作,由后端自动根据负载来做调整,在不用时自动将资源占用降为0 。存储空间也类似。原本客户在购买了一个100GB的存储空间,会一直按100GB来计算费用,但实际可能并没有真正用到那么多。这里可以实现为仅仅为实际占用的空间付费。

云原生大数据平台_java_08

正常情况下,数据库实例处于休眠状态;当SQL到达时,将计算节点拉起来,然后执行SQL。同时,RO也可以加进去一起参与,就是可以一次拉起一个或者多个计算节点,在这些节点上做负载均衡。当没有SQL在运行超过一定时间,比如超过五秒钟、十秒钟没有SQL在运行,计算节点可以直接关闭,也因为业务没有在运行,也感知不到负面影响。而 计费成本上,则获得较大的降低 。

举例来说,比如餐厅运营的高峰时间段(如中午时间),SQL会一直进来一直使用,后端计算节点则持续存在。当资源用满达到一定阈值,将自动升配;那中午过后,不再有请求,计算节点则会被关闭、也不再计费,计算成本降为0。

演进到当前, 计算节点最细粒度可以做到一秒级别的计费 。据内部数据来看,有不少客户的业务一天只花可能不到几块钱、甚至几毛钱都有,一个月可能就花几十块钱。而像传统物理机的方式起码十万起,云数据库也要每月几百、几千块。这是一个巨大的飞越!

云原生大数据平台_mysql_09

分级存储

花分两朵,各表一支。前面是计算节点的演进, 存储节点又该如何演进 ?

云原生大数据平台_mysql_10

存储的演进持续在进行,比如性能、压缩等。此处仅针对数据的存储成本。数据大致可以分为几层:热数据、温数据、冷数据。热数据放在内存缓存里,价格最贵、性能最好。然后,大量的数据放在分布式存储上,那冷数据该如何处理?

热、温、冷的划分,主要基于的是访问频率、量和性能要求。冷数据,一般定义不经常访问的数据,比如历史订单、历史日志等。当前 TDSQL-C PostgreSQL的存储规模支持最高128TB,绝大部分情况下足够业务使用。冷数据比较多、不常访问,放在 TDSQL-C PostgreSQL的存储中又较贵,该如何处理?

答案是COS。COS是腾讯云的 对象存储服务 ,数据存储成本要低于TDSQL-C PostgreSQL的高性能存储盘。温热的数据,或者说时刻需要用到的数据,还是要放在分布式存储上正常使用,但针对时间较老、不大访问的冷数据,可以放在COS中,并通过同样的一套SQL语言、表结构来访问。

云原生大数据平台_数据库_11

为实现这一点,TDSQL-C PostgreSQL 封装了COS的访问接口 ,通过与常规数据表完全一样的使用方式,达到对COS上数据文件进行访问的目的。

云原生大数据平台_java_12

这里举一个具体的例子:第一步,创建一个Server,指定COS的信息,包括id、key、endpoint、文件等;第二步,在该Server上创建表;然后就可以通过读这张表实现对COS上文件的读取。异构存储的访问,基本上分为三部分,计算、元数据(表结构等)、存储格式。Server/表定义这里,即实现了元数据的维护,存储格式上当前支持CSV。具体的执行逻辑可以通过执行计划查看。

云原生大数据平台_云原生大数据平台_13

另外一个例子,是更复杂的一些用法,比如:Table a和Table b都是本地表,数据存放在存储上,再建一张COS表,就可以直接对这三张表做关联运算。这比较适合报表类的场景,比如以账户信息为维度统计历史订单类的报表。

云原生大数据平台_云原生大数据平台_14

还有一个例子,就是 分区表 。还是Table a和Table b,放在分布式存储上,一张 COS表,三张表放在一起作为一张分区表的三张子表。PostgreSQL有非常强大的分析能力,当基于分区字段做过滤的时候,会根据分区字段做裁剪;再配合分区表的Time to live的功能,比如Table a和Table b是正常的按时间分区,Table c则是 COS 表,可以实现同样一张(分区)表,部分放在存储、部分放在COS 上的效果。

云原生大数据平台_数据库_15

专家答疑

1. 存储计算分离之前PostgreSQL用的什么高可用方案?

答:原先一主一备形态下,高可用方案是內部自研的一套,基本分为探测、策略和执行三个步骤。

2. 主库和备库要做到同步,那资源岂不是很浪费?

答:主库和备库的数据同步,主要是为了解决 RO、备库上內存中热数据的持续更新,一定程度上是为了提升备库的性能和数据一致性。如果不在RO上保持缓存,性能会较为糟糕;若保留了缓存,则需要对这些缓存持续更新,以保证数据一致。

3. 更新操作多的情况呢?

答:主备间复制采用的是物理复制的方式,只是将数据页上的变更部分发送到备库上,在数据页上重做,这种方式较为高效、延迟较低。

4. RO先读取数据页,再应用WAL,会不会出现读延迟?

答:会有一定延迟,但这不会成为一个问题。

主备方式在当前硬件、网络情况下,必然会存在一定延迟,收敛在一定范围內即可。若要保证完全无延迟,也不是做不到,代价过于高昂、不值得;

WAL 的重放改为以页为单位,相比原来的方式更为高效,延迟反而更低;

主备间应该通过 Proxy 实现全局一致性;

通过以上措施综合解决主备延迟带来的影响。

5. 目前是一个RW,多个RO,怎么才能扩展写能力呢?

答:当前写能力很多时候不会成为一个瓶颈。在仅写入 WAL 之后,网络IO是制约写能力的核心因素之一,当前最新可以到达 100Gb/s 网络,在存储侧又被分发到多台机器上,少有多业务能将这两个地方都打到瓶颈上。当趋势出现的时候,我们也可以考虑采用多写的方式来承接,这就是另外一个故事了。

6. 既然是share存储了,为什么还要master到replica的复制?

答:参考问题二,主要是为了解决RO上的查询性能问题,需要在缓存中保持数据。

7. 存算分离后怎么解决谓词下沉技术和存储节点计算瓶颈问题?所有数据都从存储拉到计算节点计算?

答:这里其实不用过于担优性能的问题。比如,现在有一个RW15个RO,一台机器机器大约 96vCore,16台加起来一共1536,很难有业务能吃掉这么多CPU,计算资源在很多时候是足够的。

但谓词下推确实也适合这种架构,减少网络开销,实现的方式是将where条件的描述下发到存储层,存储层在返回数据之前对数据进行过滤。其中比较难的课题是存储上计算资源的调度问题,这时候要看存储机的硬件条件。这也是存储计算分离一个价值点,存储层可以针对存储层定制相关的机型,可能就要去配合一些新硬件,比如FPGA、GPU之类的

8. 没明白存算分离的意思,存储单独存储,计算的话指的是每次查询都需要新拉起一个实例去存储中拉取数据么?

答:是也不是。这里可以保持一个实例一直运行,这样有部分数据是在内存中,没有用到存储上的数据时不用从存储上读取,没有的时候从存储上读。缺点是,计算节点会持续计费。

核心还是成本。

这里比较好的玩法,是在每次执行SQL的时候才拉起实例,在超过阈值时间不再使用后,将其关闭,以节省资源。Serverless形态解决的是计费和调度的问题,存储和计算分离之后,存储层可以单独计费、计算成本按实际用量计算,可以极大节省成本。

对于很多业务来讲,尤其是有高峰低谷的业务,有非常大的成本降低的效果。并且,也解决了云数据库架构上没有解决的问题,从而实现更高可用性、更好的用户体验。

9.分级存储,如果数据放到对象存储上面,这种存储方式只适合存储归档数据,不适合有update,delete的数据。

答:这个问题比较专业。 分 级存储只解决一类的场景,数据量比较大、不改不删、偶尔读取,比如归档类的数据,放在数据库內这种高性能存储上成本又高,说到底还是成本问题。 比如有很多行业有安全性的要求,要求至少保留两年以上的历史数据; 而这些数据都不会访问,但时不时的还会查一下。

这个时候,如果用另外一套存储、另外一套引擎、另外一套机器,维护成本是相当高的。我们提供这种方式,一部分相对冷的数据放到COS来,但数据的管理和维护还是在数据库中。因此,不适合删改较多的场景。

10.计算节点下的存储是不是有优化的方向,比如WAL放在计算节点上,用高速设备进行优化?

答:存算分离方案实现的一个核心思想,就是 Log is Database。通过将 WAL 写到存储、并在存储中存放,达到数据写入存储的目的。

我理解这里的问题是,是否可以先把 WAL 写入本地、然后异步化写入存储中?这是一个有意思的思路,但这假设了一个前提,就是本地盘比分布式存储的吞吐能力更强。在当前的网络、硬件条件下,这个假设已经不一定成立了。毕竟现在100Gb/s的网络已经可以作为标配,再有RDMA的加持,网络吞吐已经高于本地盘;且存储侧的写入会分布在多个节点上,也提升了吞吐。

关于作者

窦贤明,腾讯云数据库专家工程师,从事云数据库产品研发多年,从零到一主导研发多款云数据库、云原生数据库。目前负责 TDSQL-C PostgreSQL、TencentDB For PostgreSQL 的全栈研发工作,和TDSQL-C MySQL 的产品化研发工作。