PolarDB PostgreSQL版Serverless技术原理解读
背景
数据库是现代企业IT系统中非常重要的一部分。在创建数据库时,客户往往需要比较保守地去配置数据库集群的资源,包括CPU、内存、存储以及连接数等多种参数配置,以确保业务能够在波峰和波谷都能平稳运行。在这种情况下,客户购买的集群资源在业务波谷时期会被闲置,导致整体成本偏高;而在业务压力增长阶段,集群资源又应对不足。Serverless数据库可以很好地解决这个问题。它能够让数据库集群资源随客户业务负载动态弹性扩缩,将客户从复杂的业务资源评估和运维工作中解放出来。
本文描述PolarDB PostgreSQL版Serverless的构建中, 如何实现弹得快、弹得准、弹得稳、弹得广的几个关键技术点。
关键技术点
弹得快
为了有效应对突发流量场景,Serverless形态实例以更少的任务步骤、更轻量的变配操作以及更智能的弹升策略完成了更快的规格弹升。
整体Serverless管控流程如下:
在PolarDB数据库的同主机上, 附带有采集组件, 负责获取数据库实例的性能数据。当数据库资源水位持续到达一定阈值之后, 采集组件立即通知扩缩容决策组件进行决策, 决策组件会根据本机资源情况, 对实例所在cgroup以及规格参数进行调整。PolarDB通过下面两个优化使该流程更加高效。
原地弹升优先
PolarDB通过监控组件实时采集宿主机上节点的资源使用水位。当资源使用达到预警值时,会率先尝试在当前宿主机内进行资源申请(PolarDB对Severless实例所在的宿主机上均有资源预留池以及资源管理组件,可以成功响应90%以上的资源申请请求)。在完成资源申请后,实例节点会立即扩展内核资源(如shared buffer等),整个原地弹升过程可以轻易做到秒级弹升。
当宿主机资源无法满足时,才会将实例节点从当前宿主机立即迁移至另一个资源充足的宿主机上去,整个迁移过程通过连接保持技术实现数据库连接在不同节点间的迁移,从而减少业务的性能抖动。
弹性可变步长
为了应对突发业务流量场景,PolarDB PostgreSQL版Serverless会在决策时确定弹升步长:根据实例当前的规格,以及节点实际CPU使用率高于预设的目标使用率的程度来确定下一次的弹升步长。
如上图所示,应对突发压力时,PolarDB PostgreSQL版Serverless在30s内以逐渐增大的扩容步长,由初始的1PCU达到预设扩容上限值(16PCU),期间单次弹升粒度由0.5PCU提升至4PCU。
弹得准
相对以往的固定规格形态而言,Serverless形态不仅仅使资源变配变得更加迅速,更重要的是,Serverless准确评估了业务负载对资源的使用,将技术人员从复杂的资源与成本配置问题中解放出来,所有的成本计算均以实际使用为准,真正做到了按需、按量使用。
多维度评估与弹升弹降
PolarDB PostgreSQL版为了实现弹得更准,在CPU资源使用、内存资源、以及内核资源使用等多个维度实现了资源评估,不同指标在弹升与弹降时采取的评估策略不同。
对于弹升场景,由单一指标满足弹升条件后触发;对于弹降场景,由多个指标联合满足条件后触发。其中,在CPU资源使用上,PolarDB PostgreSQL版以目标CPU使用率为基准来调控单次弹升弹降的粒度,在兼顾弹升更快的特性基础上,实现了弹得更准。
举例而言,扩缩容分别需要满足以下基础条件(根据节点实际的使用情况,节点扩缩容的情况可能会更加复杂):
单节点扩容:
- 当单节点的CPU使用率高于85%,会触发本节点资源扩展。
- 当单节点的内存使用率高于85%,会触发本节点资源扩展。
单节点缩容:
- CPU使用率低于 55% 且内存使用率低于40%。
物理实例级独立弹性
独立弹性也是PolarDB PostgreSQL版Serverless保证准确弹性的重要手段。独立弹性指数据库代理与数据库节点之间的弹性是独立的,数据库节点与节点之间的弹性也是独立的。PolarDB PostgreSQL版在不同组件维度上实现独立弹性,以实现资源使用与业务负载的准确匹配。
内核组件细粒度弹性
资源方面, Serverless已经支持CPU和内存的弹性, 但原生PostgreSQL并未在buffer pool上实现在线扩缩容的能力, 导致buffer pool无法即时利用弹升出来的内存。
PolarDB PostgreSQL版基于PostgreSQL的DSM(Dynamic Shared Memory)机制进行了改进, 抽象出动态内存管理层DSGA(Dynamic Shared Global Area)。如下图所示, DSGA以granule为粒度对共享内存进行管理, 支持了上层各个带业务语义的共享内存组件的在线扩缩容能力, 如Buffer Pool、logindex memtable等。每一个共享内存组件均可独立进行扩缩容。
弹得稳
根据业务负载的变化而改变资源使用是Serverless实例最大的特点,业务流量是弹性的触发器。业务流量突发场景下做到稳定的秒级弹升是PolarDB PostgreSQL版Serverless的目标,当业务流量不稳定时,做到实例性能稳定也是PolarDB PostgreSQL版Serverless的目标。
瞬时抖动稳定
PolarDB PostgreSQL版在决策弹性时,会对一段时间窗口内的监控指标进行评估,由决策算法识别业务流量的模式,从而决策是否进行弹升或者弹降。例如,当稳定的业务流量出现瞬时抖动时,Serverless不受瞬时抖动的影响,依旧保持原有规格来保证实例性能的稳定。
如上图所示,Serverless实例随业务压力打满CPU后,PCU数量迅速抬升;期间由于业务不稳定因素,CPU使用率出现瞬时抖动,PolarDB PostgreSQL版Serverless能够根据历史的业务使用模式准确判断抖动,维持Serverless规格不变;当识别到业务对CPU使用率持续较低时,能够在10s内触发弹降,及时缩容。
内核扩缩容
在内核共享内存各组件的扩缩容流程上, 也存在两个挑战点:一是扩缩容时效性,二是控制扩缩容过程中对性能的影响。
时效性上, 由于设计上进行了分层,整体扩缩容流程使用了两阶段的感知协议:扩容时DSGA层先扩容,再通知使用共享内存的各个component扩容;缩容时先通知component缩容,DSGA再释放内存。为了提升时效性, 首先将两阶段在单个进程内的实现中合并为一个步骤,其次在跨进程感知的过程中使用了通知+轮询相结合的方式,提升感知的效率,确保整体扩容能在秒级内完成。
性能影响上, 在具体的Buffer Pool动态扩缩容实现中, 为了降低扩缩容过程中对性能的影响, 对buffer pool的持锁粒度进行了控制:
- 扩容过程中,只在不遍历Nbuffers逻辑时做reload,新buffer添加仅需在串联进freelist时加一次spinlock。
- 缩容过程中,对要缩容的granule,将其内部所有buffer设置为SHRINK状态,确保不会再次被复用,直至buffer锁均被释放,然后对未使用的脏页刷脏,最终回收freelist,整个过程仅需对granual3的buffer上锁。
从整体测试来看, 8 PCU规格下,使用pgbench压测连续进行20次扩缩容,性能曲线平滑,无可见影响。
弹得广
除了垂直扩缩容之外, 为了充分利用到PolarDB的一写多读能力,让读实现更好的线性扩展,PolarDB PostgreSQL版Serverless还支持了水平扩缩RO节点的能力。
横向扩容:以一个初始有一个 RW 节点的 Serverless 实例为例,集群设置的 PCU 最大值为 32,并且设置了自动横向扩容 RO 节点的范围,比如 1~4 个(最多可以支持扩容到 7 个)。在通过集群地址访问时,伴随着访问压力的增加,RW 节点会先进行独立弹升到最大 32 PCU 后。如果继续有扩容需求,会触发横向扩容 RO 节点事件,此时会伴随着一个新的 RO 节点扩容出来。新扩容的 RO 节点也会独立弹升,当弹升到最大 32 PCU 后,也会进一步触发扩容新 RO 的事件。由于每个节点都会独立弹升,并可能同时触发扩容新 RO 的决策,引入了静默机制,避免在短时间内频繁增加 RO 节点。
横向缩容:我们会监控整个 Serverless 集群的各个 RO 节点在一定时间窗口内的负载情况,并且满足一定时间窗口内某个 RO 节点为低负载时,会自动删除对应的 RO 节点,实现横向缩容,降低集群使用成本。
弹性测试
表数量:16
单表数据量:500000
压力阶梯数:16(连续上升8个阶梯,连续下降8个阶梯)
每压力阶梯并发数:4并发
每压力阶梯持续时间:30s
oltp_read_only
oltp_write_only
oltp_read_write
免费体验
目前PolarDB PostgreSQL版Serverless已在产品控制台开放公测, 公测持续三个月,您可以在PolarDB购买页直接开通Serverless免费实例进行体验。您还可前往PolarDB PostgreSQL Serverless弹性&价格力观测体验馆进行免费体验。
如有任何问题,欢迎加入“PolarDB PG Serverless用户交流群”钉钉群(群号: 75850003226)进行咨询、交流和反馈。