此前,通过《向量化引擎对HTAP的价值与技术思考》一文,我们分享了 OceanBase 怎样看待向量化引擎技术,并介绍了用它解决复杂查询场景的技术思路。
HTAP 的本意是把 OLTP(事务处理)和 OLAP(分析处理)放在一个系统上更好地运行,帮助客户开展实时业务决策,降低运营成本并提升创新效率。因为 OLTP 、OLAP 使用资源(CPU、内存、IO 等)的方式不同,同时运行时容易产生资源干扰。如何将二者的相互影响降到最小,成为实现 HTAP 的关键,也是本篇文章中资源隔离技术要解决的问题。
关于作者
席华锋
OceanBase技术专家,11年来持续专注数据库的高可用和扩展性,曾负责 Paxos 协议在OceanBase的落地,是OceanBase TPC-C攻坚项目组成员。目前在OceanBase系统组,负责打造 HTAP的基础设施,包括如何解决AP和TP的资源隔离问题。
我们认为真正的 HTAP 需要完备的资源隔离,数据库需要提供逻辑隔离能力,与物理资源隔离形成互补,帮助用户根据实际业务场景进行调整。需要极致隔离的核心业务采用物理资源隔离,对成本敏感的长尾业务采用逻辑资源隔离。 本篇文章将分享 OceanBase 对资源隔离技术的思考,阐述为什么资源隔离技术是实现 HTAP 的必要前提,以及我们如何应对资源隔离的实施挑战等:
- HTAP 为什么需要资源隔离;
- 如何实现适合 HTAP 的资源隔离;
- OceanBase 资源隔离的实现效果。
HTAP为什么需要资源隔离?
资源隔离是 HTAP 的立足根本
为了说明资源隔离的重要性,我们可以把数据库与操作系统进行比较:这两者的共同点是复杂性,而复杂性来源于两方面:一是功能的开放,二是对性价比的极致追求。功能的开放意味着负载不可控,如一个用户进程可以做任何事,一条 SQL 也可以做任何事;追求性价比则是因为基础软件用户量大,优化节省每一点资源都有重要意义。而追求性价比有很多方法,其中最直接的就是资源隔离技术。
经过数十年的发展,当前的操作系统都已具备支持多用户,支持 Docker(虚拟化应用容器)的能力,基于 Docker 的 Kubernetes 已经成为业务部署的事实标准。而数据库也有多租户和混合负载的场景需求,比如很多业务把历史库和在线库分开,在历史库上执行分析,不仅增加了运维复杂性,也导致 AP 的实时性不够,无法在有限的硬件资源下实现 TP 和 AP 的动态平衡,未来随着数据库的部署实例继续增加,解决这一问题的价值收益会越来越明显。
资源隔离的需求本质来自于负载的差异分组,只要能分组,自然就产生了某种隔离的需求。 负载的分组:如备份任务和前台 SQL 任务,两者存在时效性的差异,OLTP 和 OLAP 对资源的使用方式不同,也会产生分组。只要一个软件系统要对服务的对象作区别对待,那就自然会产生分组和 QoS(Quality of Service,服务质量)的概念,也就有了资源隔离的需求。
资源隔离对数据库稳定运行至关重要。这有两种典型情况:一是为数据库内部重要的任务预留资源,避免出现用户负载高导致数据库自身垮掉的情况;另一种是用户原来就有 QoS 要求不同的业务混在一个库里, 比如实时性高的 OLTP 业务,加上少量的重要性低一些的后台任务,如果用户愿意把这些信息告诉 DB ,数据库就可以更稳定地运行。
第二种情况的典型例子就是 OLAP 和 OLTP 两种负载的隔离。传统数据库为了避免 OLTP 和 OLAP 业务间产生干扰,需要配置较多硬件资源分配给不同业务,这样就会出现资源利用率低的现象。我们可以通过引入 consolidation(数据整合)的概念来解决这一问题,consolidation 通过把原有的多套数据库聚合到一个物理库,可以在减少硬件成本的同时降低运维复杂性。
从 OLTP 和 OLAP 两个库进化到 HTAP 一个库,这一进化过程就可以理解为 consolidation 。我们知道操作系统早已实现多用户和 Docker 的能力,数据库是否也会随着技术发展出现共享物力资源的需求呢?我们认为,随着技术进步和数据库部署规模继续变大,逻辑资源隔离的应用场景会越来越多。同时,现实中原本就有不少用户在一个库中既服务 OLTP 负载,也执行一些简单的 OLAP,只是受限于 OLAP 和资源隔离的的能力,限制较多。
比如一个电商的老板想知道当天卖得最好的商品是什么。那就需要在在线库上执行分析,但主流数据库缺少资源隔离能力,分析类 SQL 可能影响在线交易,为了保证在线交易的稳定性,就需要对数据库扩容,用更多的物理资源换业务稳定性,即使这样,也需要对分析类 SQL 做严格 review,防止这些 SQL 无限制占用资源。
物理&逻辑隔离,哪个是更优选择?
资源隔离并不是一个新概念,传统方式下不共享物理资源,可以理解为物理资源隔离方案。这种方案下不同租户或同一租户内 OLAP 和 OLTP 使用不同的副本,行存副本服务 OLTP,列存副本服务 OLAP,两种业务不共享物理资源。如果不考虑成本,物理资源隔离无疑是更好的选择。
但现实中,大部分客户都会考虑硬件成本及其资源利用率。一方面,数据库硬件的购买和维护成本高昂,而所有硬件都需要定期换新;另一方面,数据库硬件在进行单项业务处理时,平均占用率水平较低。如果不能充分利用硬件资源,无疑会造成巨大的资源浪费。
而要充分利用硬件资源,不同租户或同一租户内 OLAP 和 OLTP 共享物理资源的逻辑资源隔离方案,自然脱颖而出。 同时我们认为,物理资源隔离和逻辑资源隔离不是二选一,而是互为补充的关系。但考量到资源共享可能出现的干扰问题,一些人认为资源共享会导致 QoS 无法保证,因此对用户价值不大;另一些人也会关注完美的资源隔离是否能实现,如果实现方案过于复杂是否会得不偿失等问题。
面对上述问题,我们认为一方面要放弃完美主义,认识到基础的资源隔离能力对客户的明显价值;另一方面要用发展的眼光看问题,了解到逻辑资源隔离技术在持续进步。
因此,适合 HTAP 的资源隔离并不是物理资源隔离或逻辑资源隔离中二选一,理想的资源隔离方案是在完全物理隔离和完全共享中找到平衡点。 基础软件应该给用户更多自由,帮助用户在面对各类场景下都可以做出最合适的选择,数据库产品有必要同时提供物理隔离、逻辑隔离各级别的资源隔离能力。
如何实现适合HTAP的资源隔离?
我们在实施资源隔离前,要先解决两个问题:
定义资源组,以及资源组的 QoS,对数据库来说租户就是最常见的资源组,另外 AP 和 TP 也可以是两个不同的资源组;
按定义好的 QoS 制定实施资源隔离的策略。
我们先看 DBA(数据库管理员)的控制接口,然后再分析要对哪些资源做隔离(一般选择对业务影响最大的资源),最后会以 CPU 时间、IOPS 和网络带宽为例讲述 OceanBase 的隔离方案。
定义资源组,做好 OLTP 和 OLAP 的资源规划
OceanBase 的目标是实现在不同租户间的资源隔离,以及租户内 OLTP 和 OLAP 业务的资源隔离。
怎样描述租户的资源要求?OceanBase 内部是通过 unit config 实现的,比如创建一个租户之前要创建 resource pool(资源池) 、resource pool 的规格描述里就指定了各种资源的限制。对这个概念不太了解的可以参考 OceanBase 的 DBA 手册集群和多租户管理这一章。
create resource unit box1 max_cpu 4, max_memory 21474836480, max_iops 128, max_disk_size '5G', max_session_num 64, min_cpu=4, min_memory=21474836480, min_iops=128;
怎样描述租户内 OLTP 和 OLAP 需要的资源规格?OceanBase 参考了 Oracle 经典的 Resource Manager 系统包提供的管理接口。我们观察到,很多客户的跑批业务会安排在业务低峰期,如午夜或者凌晨,此时不用过于担心 OLAP 会影响到 OLTP 类业务,我们可以把集群绝大部分资源分配给 OLAP 类业务,给 OLTP 留下最小资源保证即可。在白天的业务高峰期,通过调整资源隔离方案,可以确保 OLTP 业务资源充足,同时按照预设资源满足基本的 AP 类查询。在 OceanBase 里,我们只需要预设两套资源管理计划,白天激活 DAYTIME 计划,夜间激活 NIGHT 计划,就可以实现满足基本的隔离需求的同时实现资源利用率的最大化。
比如我们可以用以下语法定义一个白天资源使用计划(resource plan),并且制定了此计划下 OLTP (interactive_group)和 OLAP (batch_group) 的资源百分比。80% 的资源用于 TP,剩下 20% 资源用于 AP。
DBMS_RESOURCE_MANAGER.CREATE_PLAN(
PLAN => 'DAYTIME',
COMMENT => 'More resources for OLTP applications');
DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE (
PLAN => 'DAYTIME',
GROUP_OR_SUBPLAN => 'interactive_group',
COMMENT => 'OLTP group',
MGMT_P1 => 80,
UTILIZATION_LIMIT => 100);
DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE (
PLAN => 'DAYTIME',
GROUP_OR_SUBPLAN => 'batch_group',
COMMENT => 'OLAP group',
MGMT_P1 => 20,
UTILIZATION_LIMIT => 20);
定义好 资源使用计划后,可以用以下方式激活它:
ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = 'DAYTIME';
按照类似的方式,我们可以定义夜晚的资源使用计划,并在业务低峰期激活它。
OceanBase 现在提供了按登录用户对 SQL 分类的方法,客户可以创建一个新用户用于执行 分析 SQL,只要是该用户发起的 SQL,都会被判定为是 AP 负载,这样分类简单有效。同时,OceanBase 会把执行时间超过 5s 的请求识别为当作大查询,大查询会被降低优先级。
min, max, weight,满足 QoS 根本诉求的三重定义
QoS(Quality of Service,服务质量)作为一种安全机制,可以在资源过载时保障关键进程的平稳运行。以下我们通过权重分配、资源上限和保留资源来描述 QoS。
在不同的时间段,业务的流量会有波动,所以 QoS 描述需要有一定的弹性,如果像公有云上的 ECS 一样指定一个固定的 CPU 核数和 IO 带宽,在业务高峰的时候容易出现数据库容量不够而导致的故障。
我们假设这样一个场景:总带宽是 100M,由租户 A 和租户 B 共同使用,基于资源的闲时共享和忙时隔离原则,我们尝试让租户 A 和租户 B 互不干扰地共同使用总带宽。
如果两者的重要程度不同,怎样保证重要进程的优先运行?此时我们可以每个租户的重要程度分配使用资源的比例,如给租户 A 和租户 B 分配 1:3 的权重比,当这两个租户都需要 CPU 时,A 将得到 1 份 CPU 时间,B 将得到 3 份 CPU 时间。这一操作我们称为权重分配,或
有时候物理资源较为充裕,低权重租户可能会占用大量并不需要的资源,如何限制它的使用呢?我们可以在权重分配的基础上给不同的租户定义资源上限
租户数量增减会引发权重配比改变,如何直观判断各租户最低资源需求的满足情况?此时我们可以给各租户设置保留资源
我们希望把更完美的资源隔离,做进 OceanBase 数据库
资源按照使用情况有刚性和弹性的区别,资源隔离的对象通常是弹性资源。刚性资源是保障程序完成功能必须的资源,一旦被占用,短时间内也难以释放。刚性资源的典型是磁盘空间和内存空间,连接数等,这类资源做好静态规划后,每个组可以使用的资源数量就会固定下来。弹性资源是指和程序功能无关,但是和性能有关的资源,比如 IOPS、CPU 时间、网络带宽等,这类资源一般可以抢占或被迅速释放,因此资源调度策略可以介入,实现闲时共享,忙时隔离。我们需要关注的正是弹性资源的共享机制。
刚性资源比较重要的是内存和磁盘空间,弹性资源比较重要的是 CPU 时间,IOPS 和网络带宽,OceanBase 会优先把这些资源的隔离做好。
CPU 隔离
OceanBase 目前已实现 CPU 时间的隔离,未来会加入 CPU cache 的隔离。CPU 隔离有一个特点,那就是只有在内核态才能做得比较实时,因为一个资源要能调度,前提是要能切分成很多小片,网络 IO 天然就是一个一个的 packet,磁盘 IO 也类似。CPU 时间被操作系统切分成了很多片,但是这个时间片对用户态是透明的,用户态无法介入时间片调度。用户态要调度,那就需要在代码中插入很多检查点,通过检查点把用户线程的 CPU 时间切分成很多段,同时在检查点执行调度策略。用户态插入检查点切分效果无法保证,如何在一个静态库函数里插入检查点呢?
OceanBase 选择了内核态解决方案,即 cgroup 的 cpu controller,cgroup 目前能支持
CPU 隔离不仅可以隔离用户负载,也可以隔离系统内部的不同任务。比如对 OBServer 来说,多副本的 leader 选举是一个高优先级任务,我们不希望用户 SQL 把 CPU 打满最后影响到选举。我们在 cgroup 的顶层把选举和用户 SQL 分到两个目录,在用户 SQL 的目录进一步分目录,对应租户和租户内的用户。
IOPS 隔离
对于 SSD 磁盘,带宽可以通过 IOPS 来等价描述(bandwidth = size * iops)。其次不同大小的 IO,我们根据经验公式可以归一化,我们设定一次 IO 的标准大小是 16K,那么一次 2M 的 IO 就可以等价为多次 16K 的 IO。IOPS 隔离要区分设备,但是把设备暴露出来会让配置比较复杂,所以大部分情况下可以让多个设备共用一套配置。
OceanBase 从 VMware 用于隔离虚拟机 IO 的一篇论文《mClock: Handling Throughput Variability for Hypervisor IO Scheduling》中获得启发。
在公有云上部署的时候,我们发现云盘的 IO 能力是会有波动的,OceanBase 可以快速适应云盘 IO 能力的下降,保障最重要的 TP 业务不受损。同时 OceanBase 的 IO 隔离会和数据库的块缓存一起联动,OceanBase 不仅会限制 AP 的 IO 带宽,还会限制 AP 的缓存使用,这样就能避免 AP 污染块缓存,最终保障 TP 的低延迟。
网络带宽隔离
我们可以把 OBServer 之间的 RPC 分为机房内通信和机房间通信:前者主要是 SQL 分布式执行以及两阶段提交引起的,后者主要是为了高可用而做的日志复制和数据备份。不同于机房内通信,对于机房间通信的来说,一个机器到不同的机房的延迟和可用带宽都是不一样的,通常机房间带宽是共享资源,所以带宽的分配和限制需全局考虑才有意义。关键问题就在于全局的范围是什么?比如有多套 OceanBase 集群,是否要协同考虑;就算只有一套 OceanBase 集群,如果出现网络分区怎么办?我们怎么才能确保拿到全局视图?
OceanBase 从 3.2 版本开始支持 region 级别的带宽控制,接下来,我们的思路是多套 OceanBase 集群之间不做协调,需要 DBA 静态划分资源,也就是要给每个集群设置机房和机房间的可用带宽, OceanBase 在集群内部把带宽动态分到每个 OBServer,每个 OBServer 内进一步把带宽按优先级分给不同的组。
对大部分业务来说,机房内的网络带宽分配更为关键,带宽的隔离和 IOPS 隔离是非常像的。不过由于通信目的端众多,一般不区别通信目的端,算法实施的时候把网卡当作一个 IO 设备,而不是把通信目的端当作一个设备。
网络带宽隔离问题可以分解为两部分:首先要对流量分组,或者说打标签;其次要按设定的要求对打好标签的流量做隔离。其中第一步只能由应用逻辑提供,第二步可以在应用层解决,或者在内核层面解决。因为 linux 下 tc 提供了非常丰富的限速和优先级策略,所以 OceanBase 选择应用层打标,内核态限速的方案。复用内核的能力,同时也是在复用内核的生态,用户不再需要学习一套新的限速机制。
OceanBase资源隔离的实现效果
OceanBase 目前实现了内存隔离、磁盘空间隔离、CPU 隔离以及 IOPS 隔离,未来还将支持网络带宽隔离,下文我们会以 CPU 隔离为例,对 OceanBase 资源隔离实现效果进行测试。
在介绍定义资源组的方法时,我们提到可以建一个特殊用户专门来服务 AP。在本次实验中,先创建两个测试用户:AP@ORACLE 和 TP@ORACLE。我们把 AP 任务绑定到 AP_GROUP,TP 任务绑定到 TP_GROUP。假设这个业务白天的时候 TP 负载高,AP 集中在晚上。因此我们为白天和晚上设置两个不同的资源使用计划,白天的时候我们希望 80% 的资源用于 TP,剩下 20% 资源用于 AP,夜晚的时候希望 50% 的资源用于 TP,剩下 50% 资源用于 TP。
从白天计划切换到夜晚计划
从结果上可以看出来,切换为夜晚计划后,AP 的 CPU 资源占比变大后,AP 的 QPS 明显变高,TP 的 QPS 有一些降低。下图中 AP 和 TP QPS 发送变化的点就是切换资源使用计划的时间。
看起来 TP 的 QPS 降低比较少,和 AP 的 QPS 变化比起来不明显。这里要注意,按理想情况来算,TP 的 QPS 变化本来就要比 AP 的变化小,因为 AP 是从 0.3 到 0.5,增加了 66.7%, TP 从 0.7 到 0.5,降了 28.5%,然后实际算一下,TP 下降了 24.7%(19000 到 14300),和理想值的差距不算特别大。
CPU 隔离能否起到理想作用,和负载类型有很大关系,如果网络成为瓶颈,那就必须要加上网络带宽隔离才能起效。 这个实验目的也不是为了表明 CPU 隔离就很牛,能解决很多问题,但是它表明了对 CPU bound 的负载,简单的 CPU 隔离效果还不错,比如目前我们还没有考虑 CPU cache 的隔离。隔离能力的建设是个渐进的过程,单纯的 CPU 隔离对 TP 加简单 AP,或者 TP 和 TP 之间的隔离就能直接起效;适当的 IOPS 隔离和网络带宽隔离加上之后,适应范围就足够广了。
写在最后
本文介绍了 OceanBase 对资源隔离技术的思考和实现方案。HTAP 数据库要实现不同租户间、以及同一租户内 OLTP 和 OLAP 业务的硬件资源共享,对资源隔离提出了很高的要求,我们认为更适合 HTAP 数据库的资源隔离方案是物理隔离、逻辑隔离两者互补的方案。展望未来,OceanBase 的资源隔离技术也会不断演进和完善,更好地满足用户对资源隔离的需求。