1. 功能介绍及痛点
云原生数据仓库AnalyticDB MySQL版(下文简称为ADB MySQL)是阿里巴巴自研的分析型数据库,本文将讲解ADB Compaction Service能力,首先我们来看什么是Compaction。
ADB MySQL的存储引擎架构类似LSM-Tree:用户以文件Append-Only,内存标记删除的形式高效的将数据更新到面向写入优化的实时数据,然后存储引擎内部会将实时数据通过Compaction,将实时数据转换为面向查询优化的历史数据。在Compaction过程中会对数据进行分区、索引构建、排序等面向查询的建模过程,此外还会进行历史分区淘汰,数据冷热分层,异步应用DDL变更等数据管理操作。
由此可见在ADB MySQL中,Compaction过程是一项IO与CPU密集型操作。而ADB MySQL的存储节点除需定期在后台执行Compaction外,还承担数据实时写入、高性能查询以及高吞吐数据导入等各项工作。在这种Compaction必须执行于存储节点的架构下,存在一些用户痛点问题:
- 执行并发度小:为不影响存储节点其他任务,Compaction仅可使用少量存储节点资源以较少的并发在后台执行。
- 资源隔离性弱:即使在充分的资源隔离措施的前提下,Compaction的任务执行依然难免在业务高峰期影响查询与写入。
- 扩展弹性能力弱:不能独立为Compaction任务进行资源扩容,只能伴随存储节点扩容。
为了解决上面客户痛点问题,ADB MySQL推出了Compaction Service功能:将系统后台Compaction负载从存储节点解耦出来,由基于Region级别池化资源并自动弹性扩展的Compaction service承担这部分负载。
Compaction Service功能具备如下优势:
- 秒级弹性扩展能力:在业务流量增加突发大量写入时,可以秒级扩展Compaction资源,实现提升数倍任务并发。可以尽快的将实时数据转换为历史数据,即使存在写入洪峰也不会影响用户查询性能。
- 高负载隔离能力:系统后台Compaction在Compaction Service执行而不是在存储节点中执行,显著降低Compaction执行对用户读写业务的影响。
- 按量付费能力:根据Compaction数据量计费,不需要为Compaction负载保留常驻资源,无Compaction任务时无需付费。
总体来看,和在存储节点本地执行Compaction对比,使用Compaction Service可显著降低Worker资源消耗、提升并发度和弹性能力:存储资源资源消耗降低50%,并能通过在线调整配置,可秒级时间实现并发的线性拓展,任务总执行时间平均降低40%。
下文将重点从技术的角度向大家介绍Compaction Service的整体实现。
2. 技术架构
Compaction Service使用了共享弹性资源池服务于一个Region的ADB MySQL实例的所有Compaction任务,主要包括Controller节点和Executor节点,Controller节点负责任务的调度、分发,而Executor节点主要负责任务的执行。
通过面向多租户的资源隔离和调度机制具备多实例服务能力,通过感知负载的自动弹性管理实现对Compaction Service集群资源的秒级动态扩缩容。
- 基于池化弹性资源池的共享服务:建设Region级别池化共享的Compaction Service,有一定的常驻资源保证高效率的任务执行,避免频繁重复的资源拉起和释放导致的低效率,同时通过一个Region多实例共享池化资源和弹性扩缩容降低服务成本。
- 多租户实例任务的隔离和调度:确保调度公平性,避免一个实例任务长期等待。
- 秒级自动弹性扩缩容:通过感知集群任务负载情况,自动执行秒级集群扩容和缩容,在任务堆积时通过扩容来避免任务长期等待,在任务数量少时通过缩容来降低服务成本。
2.1 调度Compaction Task到Compaction Service执行
为了降低Compaction任务对用户读写业务的影响,我们需要调度Compaction Task在Compaction Service中执行,而不是在存储节点执行,关键在于:
▶︎ 执行:在ADB MySQL的存储引擎之上,我们实现了一套Storage SDK。借助这套Storage SDK, Compaction 任务可以脱离存储节点执行在Serverless的Compaction集群之上。Storage SDK核心包括两个模块:
- 读模块:可从存储节点或OSS中读取ADB MySQL自研格式存储与索引文件。
- 写模块:实现将读取数据进行加工做排序、构建Layout、构建索引等工作,并将处理结果写入到制定存储介质。
▶︎ 调度:调度一个Compaction Task到Compaction Service执行的会涉及两层调度:
- 第一层调度在存储节点的Compaction Scheduler
a. 确定一个Compaction Task是否提交到Compaction Service执行:Compaction Scheduler会根据存储节点的负载情况和一个Compaction Task处理数据量大小,判断是否需要提交到Compaction Service执行。
b. 确定Compaction Task提交顺序:按照优先级顺序提交Compaction Task到Compaction Service。c. 在Compaction Task执行完成后完成数据上线:在Compaction Task在Compaction Service中执行完成后,会执行新数据上线操作,最新数据会对查询可见。
- 第二层调度在Compaction Service的控制节点
a. 提交流控:Controller会根据当前集群资源情况对提交的Compaction Task做流控。在资源不足情况下,可能会通知Worker Compaction Scheduler等待后再重新提交,再Compaction Service根据负载情况完成集群扩容后,重试提交Compaction Task会成功。
b. 优先级调度:控制节点会为已经提交的Compaction Task确定优先级,然后按照优先级顺序为每个Comaption Task分配执行节点Executor。对应Executor会执行分配到的Commapction Task,并在执行结束后通知Worker Compaction Scheduler完成结果数据上线。
2.2 多租户任务的隔离和调度
正如上文所提到,在同一个Region下的不同用户,Compaction任务会被提交到同一个Compaction Service。换而言之 Compaction Service需要具备多租户能力。多租户任务的隔离和调度有如下挑战:
- 多租户下的任务资源分配和优先级调度,如分配一个实例合理的资源,以满足该实例任务运行需求;如确保调度公平性,避免实例任务长期等待排队。
- 多租户下的任务执行隔离,如避免多租户任务的执行上下文相互影响;如避免多任务之间资源竞争影响。
多租户隔离和调度的整体方案如下:
- Controller维护全局状态,负责提交流控和任务调度。
- Executor维护和汇报本地状态,负责任务执行和隔离。
多租户任务流控
对每个实例的可以提交执行的Compaction Task做流控是Compaction Service的自我保护机制,避免一个实例突然提交异常大量任务导致Compaction Service资源被一个实例耗尽,同时默认流控值可以保证实例正常Compaction Task执行需求。
▶︎ Compaction Service中最小资源分配单位是1个Slot:一个Executor支持8个Slot,一个Task占用一个Slot。
▶︎ 一个实例默认分配的最大Slot资源策略如下,即最大并发运行Compaction Task数量。
- 原则:以实例资源数量作为多租户资源分配依据。
- 策略:根据实例资源来分配实例可以运行Task的最大并发,默认并发为一个实例ACU数*0.375,这个数值是实例Compaction的执行并发数,可以满足实例正常Compaction Task执行需求。
- 执行:Compaction Service会对实例的Task提交数量做流控。
多租户任务调度
以一个实例资源数量和已经运行任务数量同时作为多实例Compaction Task做调度优先级依据,以确保调度公平性,避免实例任务长期等待排队。每一次调度Compaction Service都会选择一个最优先的Compaction Task到最空闲一个Executor执行:
▶︎ 选择最优先的Task
- 多租户优先级调度:调度选出最高优先的一个实例
a. 原则:实际消耗集群资源占比 =(趋近于) 实例资源占比
b. 策略:每次选择优先级分值最高的实例的Task调度执行,同等情况以提交时间顺序调度。一个实例的优先级分值 = 一个实例的资源占比 / 一个实例的实际使用资源占比
- 租户内实例优先级调度:会按照Task提交时间顺序调度,因为Worker Compaction Schduler已经按照优先级顺序提交了Task。
▶︎ 选择最空闲的Executor
- 选择空闲Slot最多的executor节点。无空闲Slot的节点时会排队等待,等待其它task执行结束或集群自动扩容。
多租户任务隔离
需要对Compaction Task执行环境做隔离,对执行资源消耗做控制,确保一个实例的Compaction Task不受其它实例Compaction Task干扰。
▶︎ 每个Task有独立的互不干扰的执行上下文:Task元信息:如实例元数据信息、表元信息等。
- Task执行信息:如控制是否使用SSD Disk作为临时缓存等。
- Task执行过程中临时信息:如执行统计信息等。
▶︎ 限制每个Task所使用的资源:每个Executor可执行8个Task,每个Task可使用Executor的1/8资源。
- 默认限制最多使用1 Core Cpu和1/8 Memory。
- 默认不限制SSD Disk的使用,在SSD Disk使用率达到90%时,自动切换到不使用SSD Disk作为缓存的执行模式,保证任务正常运行。
- 默认不限制IO的使用,在IO资源使用率接近100%时,自动限制单个任务的IO资源使用,最低会降低到最小的1/8 IO资源。
2.3 秒级自动扩缩容
负载感知的自动扩缩容功能是提升稳定性和降低成本的关键:通过及时扩容节点,避免Task堆积,提升稳定性,而通过及时缩容节点,避免资源空闲,提升集群资源利用率,降低成本。
基于K8s HorizontalPodAutoscaler能力,我们实现了根据负载变化对Compaction Service集群资源自动执行动态扩缩容。Compaction Service输出资源负载指标如CPU/IO、业务负载指标如任务排队数量、期望副本数量等指标,K8s HorizontalPodAutoscaler根据负载情况自动执行横向扩缩容。
为了在任务堆积时快速扩容资源,我们采用了快速的扩容策略,可以在30s内完成40个Executor节点的扩容,平均一个节点耗时<1s。而为了避免误缩容导致任务堆积,我们采用了保守的缩容策略,会在缩容前等待5分钟,如果5分钟内仍无任务需要执行,才会执行缩容,同时缩容节点会等待正在运行任务执行结束,避免缩容节点导致任务执行中断导致资源浪费。
3. 总结
Compaction Service可以解决用户对现在Compaction任务的资源隔离性弱、并发不足等客户痛点问题,在资源隔离性、并发执行能力、弹性能力和按量付费能力上有了显著提升。
可显著降低存储资源消耗50%,Compaction任务总执行时间平均降低40%。
此外Compaction Service还具备按量付费能力,根据Compaction实际处理数据量收取费用,无需要为Compaction预留常驻资源。
云原生数据仓库 AnalyticDB MySQL 版的Compaction Service已经上线,可点击链接参考文档开启Compaction Service功能。
作者:郭小兵、张浩然