移动云基于 TiDB 实现 serverless 数据库服务

一、背景

随着云计算的不断发展,数据库技术呈现从传统集中式到云时代分布式迁移的发展趋势。而目前云数据库的发展主要还处于“数据库托管上云”的阶段,也就是用户在订购数据库实例时,还是按照传统思维,基于业务负载高峰,预先确定数据库实例的规格与存储等资源。这种订购数据库方式,会存在如下问题:

  1. 用户无法精准地将业务负载与实例规格关联(或者业务负载完全没法评估)。如果出现资源不足的情况,只能进行紧急规格变更,无法及时应对负载高峰,且在规格变更期间还会出现短暂的停服,用户体验会较差。

  2. 为了减少规格变更的频率,导致服务的中断,用户往往按照一定时间内的峰值申请相应资源,那么对应也会持续按照峰值资源计费。但是大部分业务处于峰值的时间很短,从而造成用户大部分时间为了不必要的资源在付费。最终导致用户使用成本上升。

二、理想中的云数据库

作为一个用户,理想中的云数据应该具有以下几个特征:

  1. 使用简单

用户在创建数据库实例时,不需要预先指定实例的规格及存储等配置,只要点申请,云服务提供商就能够提供一个可以访问数据库的地址以及用户密码。用户使用过程中完全不用担心资源不足,参数优化,高可用等。其他资源配置项,由云服务提供商做最优化处置,并且保证对用户零感知。

  1. 收费低

基于业务负载提供刚刚好的资源(这是一个动态调整的过程),换句话说就是保证运行过程中,任意时刻有多少业务负载就提供多少资源,云服务商保证分配的资源不多也不少,用户只需为他真实使用的资源付费。

  1. 服务稳定

能够平滑应对业务负载高峰,并且用户无感知,对用户来说,任何负载的变化都不会影响其业务性能,即用户的任何业务请求,都能在合理的时间返回。

云数据库服务提供商角度,在保证一定收益前提下,对上述用户关心的三点做的越极致,则产品越具有竞争力。

关于收益和用户成本关系,下面通过一个简单的例子来比较RDS与理想中的云数据库资源使用情况,以来加深读者的理解:

假设一个资源池可以提供100个vcpu,总共有100个用户订购了数据库实例,每个数据库实例的规格是1核,每个vcpu的单价为6元/小时,平均每个用户每个小时真实使用数据库的时间为10分钟。

如果订购RDS服务,那么每个用户每小时的成本为6元,云服务提供商每小时的总收益为6*100=600元。

根据云服务提供商利益最大化原则,除了用户真实使用的10分钟以外,可以把资源分给其他用户进行使用,按照资源满负荷运转及每个用户使用情况,100个vcpu可以提供给600个用户使用,每个用户的成本不变,但是云服务提供商每小时的总收益就变成了6*600=3600元。

而根据用户利益最大化原则,根据使用的资源进行付费,每个用户每小时只使用了10分钟,那么只需要付10分钟的钱即可。按照资源满负荷运转及每个用户使用情况,100个vcpu可以提供给600个用户使用,云服务提供商每小时的总收益不变,但是每个用户的成本变成了6/60*10=1元。

理想中的云数据库,可以将两者的利益结合起来,实现共同利益最大化。但在使用弹性扩缩容的时候,不可能每时每刻资源都满负荷运转,需要有一些冗余,按照80%计算。根据用户真实使用情况进行按秒计费,假设每个vcpu的单价变为12元/小时,其他假设条件不变。则每个用户每小时的成本为12/6010=2元,是使用RDS服务成本的1/3;而云服务提供商每小时的总收益就变成了12100*0.8=960元,是提供RDS服务收益的1.6倍。

综上所述,为了降低成本,云服务商技术演进包含以下方向:

  1. 最大化提高底层资源的利用率。 主要通过数据库服务编排实现,在保证每个数据库服务不受影响的情况下,最大限度提升底层资源的利用率。

  2. 数据库内核能力,提高单vcpu 能够提供数据库服务的能力。即同等资源情况下,内核是否能够提供更高的服务能力

当然评价一个数据库,成本只是因素之一。其它例如高可用,高可靠,HTAP能力,扩展性等方面都是衡量一个DB的重要指标。

三、Serverless DB 架构

¨ 我们为什么选择TIDB作为底层数据库来实现serverless服务

  1. 支持计算存储分离,

  2. 支持动态扩缩容

  3. 支持TP和AP场景的HTAP数据库

  4. 高可靠,高可用能力,大规模

TIDB这些特性,能够帮助我们提供最理想的serverless db 服务

  1. 基于业务负载实现动态扩缩容,并且用户零感知

  2. 使用简单,支持MYSQL协议,同时支持AP和TP的业务

  3. TIDB能够提供极致的高可用能力,保证用户完全不用担心

  4. 支持超大业务负载,保证业务峰值时服务的稳定性

¨ Serverless 架构

Serverless架构图

Ø proxy模块

作为所有SQL请求的入口,proxy基于业务负载模型,通知serverless模块实现计算节点的扩缩容

Ø Serverless模块:

实现计算存储的扩缩容,支持scale up/down. scale out/in

Ø 计算层:

提供多个计算节点,对应TIDB节点,提供数据库计算服务

Ø 存储层:

提供多个存储节点,对应TIKV节点,提供数据存储

¨ 核心技术点

  1. 如何精准感知业务负载。

我们实现的第一个版本,业务负载主要关联两类指标:QPS以及CPU使用率

QPS:proxy记录每次客户端请求,每秒统计当前QPS

CPU平均使用率:通过监控软件,定时计算所有计算节点的平均CPU使用率

  1. 感知业务负载变化后,如何完成扩缩容操作。
  1. 计算引擎扩容:

两种情况触发扩容操作:

a) proxy 每秒统计业务QPS。每个vcpu 对应1000qps。proxy 检查当前提供服务的计算节点vcpu核数和QPS,如需要扩容,则调用serverless模块,快速完成扩容

b) serverless 模块也会实时计算所有节点CPU平均使用率,如果发现超过30%并且每个CPU误差不超过10%,会触发扩容操作

  1. 计算引擎缩容:

计算节点缩容,不会像扩容那么敏感积极,相对而言是比较迟钝的。主要原因是每次扩容是有成本的,当前基于容器的方案,完成计算节点的扩容需要10秒左右时间,如果缩容也和扩容一样敏感,会导致频繁的扩缩容,反而导致服务不稳定。缩容的逻辑算法如下:划分时间片15分钟为一个缩容周期,如果15分钟内,每秒基于业务负载模型计算出的结果都显示需要缩容,即会选择一个最小缩容规模,调用serverless 模块完成计算节点缩容。如果15分钟周期内,只要有一次基于业务模型算出需要扩容或者保持算力的话,会重新计算进入新的周期(也就是重新开始一个15分钟周期)。当前时间片是一个动态调整的参数,后续会基于历史运行信息,每个实例动态设置不同的值。最终目的,是保证该缩的时候,尽快缩,减少使用成本。不该缩的情况就是那种刚刚缩后,很快又启动扩容操作。

  1. 存储扩容:

支持scale up和scale out. 每个存储引擎初始时会分配一定量的空间X,当存储容量达到80%时,会触发存储scale out 。如果存储规模达到一定量以后,空间不够用时,会触发容量scale up.

  1. 存储缩容:

当前支持sacle in,不支持scale down. 即如果发现一个存储引擎的容量小于初始容量的50%时,会scale in此存储节点,触发数据的rebalance. 缩容节点是串行操作,会选择业务低负载或者零负载的时候实施存储缩容操作

  1. 在计算扩缩容时,不可避免地会创建和删除计算节点,这时如何做到在增加计算节点时可以将负载转移过去,在删除计算节点时将负载平稳的转移走,做到用户无感知。

作为serverless数据库,不可避免的频繁扩缩容,那么技术上如何做到用户无感知. 当前我们通过proxy 解决这个问题。即用户直连proxy,通过proxy管理后台计算节点的连接。每个proxy和后台的每个计算节点会维护一个连接池。下面分情况讨论扩缩容;

扩容:serverless 完成扩容后,调用proxy接口,把新增的计算节点加入后台连接池管理。这样用户负载过来时,会把部分流量导入到新增的计算节点,用户完全无感知,但是整体负载被平均打散到所有后台节点。

缩容:缩容特定的计算节点,相对扩容来说较麻烦,分几个步骤:

a) 对于要缩容的节点,停止连接池向它分配新的连接

b) 等待当前缩容节点所有分配的连接被回收

c) 如果超过一定时间,还有部分连接没有回收,会强制关闭。

d) serverless模块真实关闭要缩容的计算节点

proxy 部分核心逻辑如下:

proxy 本身作为mysql server 提供客户端连接。当收到用户请求时,会把请求按照一定的比率发送到相应的计算节点(当前支持按照不同的vcpu分配连接)。proxy 和后台每个计算节点建立一个连接池,收到用户请求时,会选择一个后台的计算节点,然后从连接池选择一个连接,发送请求给计算节点。处理完连接会重新放回连接池。所以只要保证用户到proxy的连接不发现变化,就能保证整个用户的体验

计算节点的服务发现和注册:因为整个serverless是运行在k8s 环境,所以通过k8s 的接口实现计算节点的服务注册和发现

  1. 在零算力的时候,如何处理业务请求并能对用户无感知。

当前如果proxy在一定的时间内没有收到用户请求(这个时间可以动态调整),proxy会通知serverless模块,关闭所有的计算引擎,也就是计算节点缩到零(最大化降低用户使用成本)。算力缩到零以后,如果有新的连接请求过来,proxy会调用serverless 启动新的算力,新算力启动时间10秒左右,对用户的体验就是第一个SQL会有10秒的时延。

四、当前技术瓶颈及优化方案

目前遇到的技术瓶颈

  1. 业务负载模型不准确,当前只支持QPS和CPU,不能精准的描述所有的业务负载。好的业务负载模型,能够准确的告诉我们负载情况,什么资源需要扩缩,扩缩多少。

  2. 无法很好的应对业务负载的爆炸式增长,例如1秒内,负载激增到1000倍,甚至更高。现有的架构仅适合负载一定范围的线性变化,当前业务负载模型,如果负载上限50%时,会触发扩容,也就是如果想要好的serverless体验的话,负载变化要控制在一定的范围。

  3. 扩容时间无法做到极致,虽然当前使用容器技术,但是扩容还是以秒为粒度,在扩容的窗口期间,系统无法很好的应对负载变化。

  4. 唤醒时长无法做到极致,当缩容到零以后,用户第一个SQL请求会触发唤醒操作,当前唤醒操作以秒为单位,也就是用户的第一个SQL时延是秒。

  5. 如果业务负载变化太快,会造成资源扩容赶不上业务负载变化,这个时候,

用户会明显感知到性能下降。这种情况在小算力下,问题更明显。

¨ 针对以下技术瓶颈,我们采用部分优化方法如下

  1. 针对第1、2、3条瓶颈限制,开创性的引入了规则系统。我们认为大部分的业务负载是有规律的,用户可以自定义一些扩容规则。例如晚上8点到9点业务高峰,提前完成扩容需求,从而解决扩容时间长,以及无法应对爆炸式业务负载变化的问题。而在定义的规则范围时间外,还是基于业务负载进行弹性扩缩容。这个方案主要解决的就是核心关健业务,它们对服务稳定性要求比较高,不希望频繁的扩缩容导致性能有任何波动。类比饭店吃饭,提前订个包间,届时会有足够的空间和服务员保障服务。

  2. 针对第4条瓶颈限制,如果用户不设置自动暂停,在业务低峰期时,我们不缩容到0,而是提供用户设置的最小算力,从而避免进行唤醒操作,同时用户也能花更少的钱。最小的算力值以及是否支持缩容到零,用户可以进行选择。

  3. 针对第4条瓶颈限制,另外提出一种思路:在实例缩为0之后的具体时间点提供一个极小算力。

  4. 针对第5个限制,我们在小算力情况下,资源使用可以临时scale up(不用重

起虚机),例如小算力对应0.5 VCPU. 用户负载正常范围波动时,在0.5 VCPU没有打满的情况下,我们就会完成新的节点的扩容。但是如果业务负载快速达到一个很大的值,我们准许小算力节点的资源临时提升到2VCPU,直到新的计算节点完成扩容。

五、未来发展思路

当前proxy 主要负责业务负载代理,转发到后台计算节点,会存在以下问题:

  1. 性能损耗,大概20%以内

  2. 资源浪费,特别在小算力或者低算力情况下,proxy本身也占用资源,导致用户成本高

  3. 当前业务负载模型主要针对TP场景,无法很好的解决htap 场景下的的serverless服务

针对以上问题,我们会开发下一个版本:

  1. 希望proxy不仅仅提供代理功能,还能够提供部分计算功能,甚至在小算力情况下,能够完全退化成计算节点。
  1. 作为proxy时,如果proxy整体负载不高,可以直接提供一些计算服务(例如点查询,资源占用少,delay 比较低),而不用再转发到其它计算节点。从而大幅度提升性能。例如点查时长是3ms, 如果转发到后台计算节点,开销是1ms,通过proxy直接提供计算能力,这类SQL性能提升30%。

  2. 如果小算力情况下,计算节点使用0.5 vcpu。 proxy 使用0.5 vcpu,如果现在的方案,直接把proxy 退化为计算节点,直接降低一半的资源成本。

  1. 业务负载模型的优化,当前我们主要基于QPS以及CPU决定是否扩容, QPS也没有区分不同的SQL资源占用情况,而是每个SQL对应加1. 这种方式太简单粗爆,会导致不同的计算节点资源负载相差很大。例如虽然都是TP类的SQL操作,但是SELECT 和UPDATE 资源使用量肯定不一样。所以后续我们会重新优化负载模型,而不是简单统计SQL数目,而是统计每种SQL 实际运行成本。然后中间件以成本均衡角度分发SQL,而不是现有的SQL数目均衡角度。初步计划,以plan cost的思路得出成本综合值。

  2. 能够同时支持ap和tp场景的serverless。要解决这个问题,需要解决以下两类问题:

  1. 如何区分是AP还是TP请求

a) SQL里加hint,显示表明这是一个AP SQL。

b) proxy 解析SQL,基于plan cost判断是AP还是TP。

  1. 如何运行TP和AP SQL

之前讲的都是针对TP 类SQL的serverless处理;基于AP类的SQL,我们处理逻辑会有不同:后台会有两类计算节点,一类处理TP,一类处理AP。 根据AP类SQL特点,启动资源比较大的计算节点,处理完以后,很快释放。如果后台没有AP类计算节点,和TP类似,会触发启动计算节点。

【注】:TP业务特性:处理快速,资源占用少,并发量大

AP业务特性:处理时间长,资源占用多,并发量小

六、性能测试报告

1. 业务感知度

业务感知度是衡量serverless能力的一个重要维度。基于serverless架构的数据库系统能够根据用户业务量的大小动态扩缩数据库系统的计算资源。及时感知到业务的变化,并计算满足业务需求的最小数量的计算资源,是计算资源动态扩缩的基础。

he3db 的业务感知度能够达到1秒以内。he3db 的计算资源个数(En)根据业务的qps计算。计算公式为:

公式一:En = ⌈qps / 1000 ⌉

图1:qps变化折线图(片段)

图2:预期计算资源变化折线图(片段)

图1和图2分别展示了qps与预期计算资源的变化趋势,qps与预期计算资源的变化趋势基本一致。

时间 qps 预期计算资源个数
06:39:40 2043 3
06:39:41 3972 4
06:39:42 6053 7
06:39:43 6105 7
06:39:44 5765 6
06:39:45 6076 7
06:39:46 5861 6
06:39:47 6063 7
06:39:48 5811 6
06:39:49 6102 7

表1:计算资源与qps数据对比

表1定量展示了qps与En的变化关系,完全符合公式一。

2. 计算资源扩容灵敏度

是否有足够的计算资源个数直接影响到用户业务进行的的流畅程度。一个良好的基于serverless架构的数据库系统应该能够在最短的时间内响应用户业务量的增长并提供足够数量的计算资源。

he3db 计算资源的扩容动作由预期计算资源的个数的变化来触发,实际计算资源的数量最终会达到预期计算资源数量。扩容灵敏度由实际计算资源数量达到预期资源数量所花费的时间来衡量。he3db 的计算实例扩容响应时间理论最长时间为2分钟,否则即为失败。测试数据如表2所示,具体实际算力与预期算力的变化趋势见附件。

测试时长 76分钟
qps范围 0 - 12000
扩容频次 21
每次扩容时长(S) 22,23,31,26,56,23,23,35,20,14,20,19,22,15,19,30,17,37,27,59,29

表2:扩容测试数据

扩容时长落入不同时间段的比例如图三所示:

图3:计算资源扩容时间比例饼图

由图可知,时间在11~30秒之间的扩容占全时间段的75%。

3. 零算力模式与小算力模式

零算力与小算力模式的区别在于当业务请求降至0并持续一定时间后,在零算力模式下,数据库的计算资源会被缩为0,而在小算力模式,则会将计算资源维持在一个既定的规模。目前he3db将小算力的规模设置为0.5个标准算力。

3.1 首个请求的响应

在零算力模式下,首个sql请求的延迟需要包括启动一个算力的时间,而在小算力模式下,则不需要。在零算力模式和小算力模式下,分别进行五次sql请求测试,延迟比对如表3所示:

次数 零算力模式 小算例模式
1 16606ms 11ms
2 15252ms 11ms
3 21987ms 14ms
4 25868ms 10ms
5 17208ms 10ms

表3:首个请求延迟对比

3.2 综合对比

小算力模式下,qps变化每周期呈3倍关系变化,变化趋势如图4所示:

图4:小算力下qps变化趋势

小算力测试结果如表4所示:

时间段 qps(期望) Duration80(期望) Duration95(期望) Duration99(期望) Duration999(期望)
第一分钟 230.80 37.65 67.35 88.32 143.42
第二分钟 689.00 72.42 117.47 287.15 403.63
第三分钟 2042.07 60.69 124.03 266.37 389.08
第四分钟 6012.50 63.35 170.20 365.17 516.27

表4:小算力测试数据表

表4中,DurationXX表示在每一分钟内,XX分位上的sql执行的时长期望。

零算力模式下,qps变化每周期呈3倍关系变化,变化趋势如图5所示:

图5:零算力模式下qps变化趋势

对比图5与图4,明显的区别在于,在零算力模式下,在业务开始的前16秒左右,qps为0,即为恢复算力过程,请求无法被响应.

零算力模式的测试结果如表5所示:

时间段 qps(期望) Duration80(期望) Duration95(期望) Duration99(期望) Duration999(期望)
第一分钟 172.05 28.65 574.81 586.48 621.29
第二分钟 683.85 66.02 110.88 221.38 354.53
第三分钟 2024.52 66.77 173.90 353.17 438.90
第四分钟 6001.45 70.18 189.40 401.87 596.33

表5:零算力模式测试数据表

对比表5与表4,第一周期(第一分钟)的95分位,99分位和999分位和表四的对应值有数倍的差异,除去第一周期,其他指标均无明显差异。

4. 竞品对标

本次对标选用腾讯的TDSQL-C。

测试从读写两个维度进行测试,每个维度进行四组测试,并对SQL的时延进行比对。本次对标测试使用标准tpcc测试数据,数据量大小为60G。测试假设用户对SQL执行时长以500ms为基础。

5.1 写入测试

写入共进行四组测试,测试标准如图6所示:

组数 最小qps 最大qps 步长 每次变化的时间
第一组 750 13000 1000 5s
第二组 750 13000 1000 10s
第三组 750 13000 1000 20s
第四组 750 13000 1000 30s

表6:写入对标测试标准

测试数据如下表所示:

数据来源 TPC-C
数据量 60G
交易类型 PAYMENT

对比测试结果如图6所示:

图6-1-1 TDSQL-C 写入80,95,99,999分位sql执行时长图(1000qps/5s)

图6-1-2 tidb 写入80,95,99,999分位sql执行时长图(1000qps/5s)

图6-2-1 TDSQL-C 写入80,95,99,999分位sql执行时长图(1000qps/10s)

图6-2-2 tidb 写入80,95,99,999分位sql执行时长图(1000qps/10s)

图6-3-1 TDSQL-C 写入80,95,99,999分位sql执行时长图(1000qps/20s)

图6-3-2 tidb 写入80,95,99,999分位sql执行时长图(1000qps/20s)

图6-4-1 TDSQL-C 写入80,95,99,999分位sql执行时长图(1000qps/30s)

图6-4-2 tidb 写入80,95,99,999分位sql执行时长图(1000qps/30s)

5.2 读取测试

读取也进行四组测试,测试标准如表8所示:

组数 最小qps 最大qps 步长 每次变化的时间
第一组 90 1500 120 5s
第二组 90 1500 120 10s
第三组 90 1500 120 20s
第四组 90 1500 120 30s

表7:读取对标测试标准

测试数据如下表所示:

数据来源 TPC-C
数据量 60G
交易类型 STOCKLEVEL

测试结果如图7所示:

图7-5-1 TDSQL-C 读取80,95,99,999分位sql执行时长图(120qps/5s)

图7-5-2 tidb读取80,95,99,999分位sql执行时长图(120qps/5s)

图7-6-1 TDSQL-C 读取80,95,99,999分位sql执行时长图(120qps/10s)

图7-6-2 tidb读取80,95,99,999分位sql执行时长图(120qps/10s)

图7-7-1 TDSQL-C 读取80,95,99,999分位sql执行时长图(120qps/20s)

图7-7-2 tidb读取80,95,99,999分位sql执行时长图(120qps/20s)

图7-8-1 TDSQL-C 读取80,95,99,999分位sql执行时长图(120qps/30s)

图7-8-2 tidb读取80,95,99,999分位sql执行时长图(120qps/30s)

(1)通过对TDSQL-C测试结果看,在TDSQL-C能够处理的数据量范围内,如果业务量变化过于频繁(比如增长120qps小于等于5秒),则TDSQL-C的性能会受到业务变化的影响明显大于业务量的影响。当业务变化量低于一定的频率后(比如增长120qps的时间大于等于10秒),TDSQL-C的性能会显著受到业务量大小的影响,而业务量的变化对于性能的影响无从体现。

(2)从基于tidb的serverless数据库系统的测试结果来看,系统读取所受的影响与其写入一致,在能够处理的数据量范围内,系统性能不受业务量大小的影响,只受到业务量变化幅度的影响,当业务增长量与系统的计算资源扩展速度相匹配时,系统能够保证业务的平稳运行。

6. 总结

  1. 关于数据库性能/成本个人的一些简单理解:

1) SQL时延,对于时延我们理解是这样的,站在用户的角度时延是1ms,还是0.5ms没有本质的差距,用户感知不到太大的差别。 所以我们对待时延的态度,只要在用户接受范围以内即可(例如都低于50ms)。传统主备数据库特别在意时延是因为它无法做到线性扩展,为了保证TPMC数值,只能极致优化每个sql的时延。而对于分布式数据库,计算存储分离/数据多副本架构,SQL处理必然涉及多次网络通信,从而导致单个SQL时延相对更高。但是这种代价能够给其他维度带来更大的收益,首先增加的时延在合理区间,总体来说利大于弊(高可用,线性扩展)。

2) TPMC指标,也就是每分钟能够处理的交易数量。如果能够保证每个SQL时延在合理区间,那么用户真正在意的其实就是TPMC上限是多少,能否包住业务峰值。

3) 成本,分布式数据库支持线性扩展,TPMC可以很高。但是考虑到成本因素,在开始时就分配大规模的计算资源并不划算。因此基于用户负载动态扩缩容(要多少资源提供多少),这也是serverless的本质。因为频繁扩缩容,我们测试重点关注两个方面,完成扩容的时间以及扩容SQL时延是否合理。

  1. 关于看待测试结果:

这次我们重点测试是serverless能力,而不是数据库本身,所以场景只限制纯读和纯写。关于业务变化,现实场景中,有负载急速增加,有缓慢增加。所以我们提供不同负载变化速度的测试结果,例如每5秒增加1000QPS, 10秒增加1000QPS。根据我们提供的测试结果,大家很容易了解不同负载变化场景下,serverless的能力。

我们测试机器只有5台,无法体现分布式数据库规模优势。后期会补测超大集群TPMC指标,通过对比TDSQL-C现网最高只能支持16算力,移动云serverless数据库正式上线以后,可以支持128算力,以支撑更大的业务规模。

声明:所有友商测试数据都是通过公共渠道订购相关服务测试获取。测试数据可能具有局限性。