OceanBase 4.1解读:给用户足够灵活简单的IO隔离体验
孙坚运:OceanBase 技术专家
从事存储引擎相关工作,曾参加 TPC-C 项目攻坚和蚂蚁双 11 大促支持,目前主要负责 IO 调度、DDL 等方向的设计和研发工作。
此前,在 《为什么资源隔离对 HTAP 至关重要?》 一文中,我们谈了 HTAP 为何需要资源隔离及其实现方法。资源隔离作为一种能力,基于它可以生长出许多有意思的场景,不仅是 HTAP,还包括多租户、Pay as You Go 等。本质上,资源隔离叠加上资源池化(云)之后,可以让每种资源就像自来水一样,用多少就取多少。 OceanBase 4.0 已经具备了 CPU、内存等资源的隔离能力,我们在本次 4.1 版本升级中,着重强化了磁盘 IO 的隔离能力,并提供了简洁灵活的使用方式。
我们认为,磁盘 IO 隔离是资源隔离至关重要的组成部分,实现磁盘 IO 隔离可以带给用户更完整的资源管控能力。 本篇文章将分享 OceanBase 对磁盘 IO 隔离的思考,介绍磁盘 IO 隔离的配置方法,并通过实验展示 4.1 磁盘 IO 隔离能力的实际效果。
一、为什么要做磁盘 IO 隔离
有人问:资源隔离尤其是磁盘 IO 隔离,有必要做吗?为什么不直接拆分机器呢?比如将 TP 和 AP 负载放在不同的副本、放在不同的机器执行,而多租户更是可以将不同租户放在不同机器,直接实现物理隔离。 在我看来,这确实是一种简便的解决方案,但它也存在很多局限,其中最主要的问题是成本。 我们假设某游戏公司有 A、B 两个租户分别处理国际与国内业务,由于时差问题,这两个租户的负载基本互补,这两个租户固然可以分别独占机器,但这样会浪费一半的资源。
对于磁盘 IO 资源而言,数据紧耦合的负载并不容易拆分机器。 比如数据库中的备份、迁移、重整等操作,都强依赖于数据的大量读写。如果没有磁盘 IO 隔离,这些任务很可能影响业务的吞吐量和响应时间。其实 TP 和 AP 的负载也很难像想象中一样拆分到不同机器,且不说 TP 和 AP 之间很多时候并没有明显界线,即便都是 TP 负载,也会存在业务上的优先级区分,此时又该如何处理呢?
磁盘 IO 作为一种柔性资源,负载之间可以互相挤占。 内存空间等资源属于刚性资源,因为这类资源的描述是标量,一块内存被 A 占用了,就不能再分配给 B 使用。而磁盘 IO 属于柔性资源,因为这类资源的描述都是单位时间的处理能力,A、B 负载可以同时读写磁盘。对于刚性资源的隔离,可以像切蛋糕一样做简单切分。但对于柔性资源,还可以考虑负载间的互相挤占,就像一条小河同时灌溉 A、B 两块农田,当 A 农田的水流调小时,B 农田水流可以自然调大。
二、好的磁盘 IO 隔离什么样
OceanBase 要实现什么样的磁盘 IO 隔离呢?首先要搞清楚,客户需要什么样的磁盘 IO 隔离,但这说起来有点复杂,正如一千个读者就有一千个哈姆雷特,不同客户对磁盘 IO 隔离的理解与需求也不尽相同:
- 有的客户希望 IO 隔离保证资源独占,承诺给到 200M 磁盘带宽,那必须预留好,不能用作他用;
- 有的客户希望磁盘 IO 隔离可以限制资源消耗,想保证某些负载的资源用量一定不超过给定阈值;
- 还有的客户说:我只想在资源不够时按权重分配资源,资源充足时不需要考虑资源隔离。
其实,在资源隔离技术领域,上面三点需求分别对应了 reservation, limitation, proportion(保留、限制、比例)三种隔离语义,OceanBase 磁盘 IO 隔离的目标就是实现这三种语义。
三、如何配置磁盘 IO 隔离
有了上文提到的三种语义后,如何让用户方便地使用呢?我们设计了一个灵活好用的配置方法。
租户间的磁盘 IO 隔离比较容易配置,如果以 IOPS 为度量单位的话,我们可以在 unit config 中指定一个租户的 MIN_IOPS, MAX_IOPS,以及 IOPS_WEIGHT,契合上述三种不同的隔离需求。例如:
alter resource unit set tp_unit min_iops=20000, max_iops=40000, iops_weight=500;
租户内具体负载的磁盘 IO 隔离又该如何配置呢?考虑到兼容用户已有的使用习惯,OceanBase 的选择是扩展 Oracle 的 ResourceManager 包。
以下我们将举例说明利用 ResourceManager 如何隔离 tp 和 ap 两种负载磁盘 IO 资源:
- 首先我们定义一个资源管理计划 htap_plan 和两个资源消费组 tp_group 和 ap_group;
- 然后我们将 tp_group 和 ap_group 绑定到 htap_plan 并分配资源,我们为 tp_group 分配更多资源,为 ap_group 分配更少资源,其中 MIN_IOPS,MAX_IOPS,WEIGHT_IOPS 均为占用租户 unit 的百分比;
- 最后设置负载到资源消费组的映射规则,这里举例是按照用户名映射,例如 trade 用户的负载全部使用 tp_group 的资源。
# 定义资源管理计划
BEGIN DBMS_RESOURCE_MANAGER.CREATE_PLAN(
PLAN => 'htap_plan');
END; /
1. 定义资源组
BEGIN DBMS_RESOURCE_MANAGER.CREATE_CONSUMER_GROUP(
CONSUMER_GROUP => 'tp_group',
COMMENT => 'resource group for oltp applications');
END;/
BEGIN DBMS_RESOURCE_MANAGER.CREATE_CONSUMER_GROUP(
CONSUMER_GROUP => 'ap_group',
COMMENT => 'resource group for olap applications');
END;/
1. 分配资源
BEGIN DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE(
PLAN => 'htap_plan',
GROUP_OR_SUBPLAN => 'tp_group' ,
COMMENT => 'more resource for tp_group',
MGMT_P1 => 100,
MIN_IOPS => 60,
MIX_IOPS => 100,
WEIGHT_IOPS => 100);
END; /
BEGIN DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE(
PLAN => 'htap_plan',
GROUP_OR_SUBPLAN => 'ap_group' ,
COMMENT => 'less resource for ap_group',
MGMT_P1 => 20,
MIN_IOPS => 0,
MIX_IOPS => 80,
WEIGHT_IOPS => 20);
END; /
1. 负载绑定
BEGIN
DBMS_RESOURCE_MANAGER.SET_CONSUMER_GROUP_MAPPING
('USER', 'trade', 'tp_group');
END;/
BEGIN
DBMS_RESOURCE_MANAGER.SET_CONSUMER_GROUP_MAPPING
('USER', 'analysis', 'ap_group');
END;/
资源消费组的映射规则还支持函数名和列名,通过函数名的映射,可以让后台任务也通过 Resource Manager 控制资源用量,
通过列名的映射,甚至可以将资源隔离粒度控制到 SQL 语句级别。例如:
# 后台任务绑定资源组
BEGIN
DBMS_RESOURCE_MANAGER.SET_CONSUMER_GROUP_MAPPING
('FUNCTION', 'CAOPACTION_HIGH', 'background_group');
END;/
1. 特定SQL绑定资源组
BEGIN
DBMS_RESOURCE_MANAGER.SET_CONSUMER_GROUP_MAPPING
('COLUMN', 'test.t1.c1 = 3', 'big1_group');
END;/
四、4.X 磁盘 IO 隔离效果测试
验证磁盘 IO 隔离能力
为了验证磁盘 IO 隔离的能力,我们首先用单测做了一项仿真实验:我们设置 4 个租户,每个租户启动 64 个线程发送 IO 请求,IO 请求固定为 16KB 随机读,租户 1、2、4 的负载持续 20 秒,租户 3 的负载从第 10 秒开始,持续 10 秒。实验磁盘 IOPS 上限大概在 6w,如果不加限制,任意一个租户单独都可以打满磁盘。
首先验证租户间磁盘 IO 隔离,各租户的配置和实验结果如表 1 和图 1 所示:
- 磁盘已经打满时,新加入的租户 3 依然拥有 1 万 IOPS,因为其通过 MIN_IOPS 预留了 1 万;
- 租户 4 的 IOPS 没有超过 5 千,因为其通过 MAX_IOPS 设置了资源上限;
- 无论负载如何变化,租户 1 和租户 2 的 IOPS 比值大概为 2:1,正如权重比例要求。
接下来,我们将验证租户内负载的隔离。我们在租户 2 内设置了 4 个类别的负载,各负载的配置和实验结果如表 2 和图 2 所示:
- B 负载稳定在近 2000 IOPS,哪怕其权重为 0,因为 B 负载通过 MIN_PERCENT 预留了租户 MIN_IOPS 97% 的资源;
- A 负载稳定在 1000 IOPS 左右,因为其 MAX_PERCENT 为 1,最多只能使用租户 MAX_IOPS 1% 的资源;
- C、D 负载的 IOPS 比例始终保持大约 2:1,因为其权重为 50:25。
从上述实验可以看出,OceanBase 在支持租户间磁盘 IO 隔离的同时,还支持租户内负载间的磁盘 IO 隔离, 且都满足 reservation,limitation,proportion 三种隔离语义。
磁盘 IO 隔离实时调整
有的同学可能发现,上述实验中,磁盘 IO 隔离的配置始终没变, 那 OceanBase 是否支持实时调整配置呢?答案是肯定的。 我们将通过以下实验来说明。
首先,我们准备了一张大表,使用并行查询做全表扫描,在扫描的同时,管理员去不断修改租户的 MAX_IOPS,视频中可以看到,操作系统监控中 IOPS 将随着管理员的修改不断变化。
细心的同学会发现,操作系统监控到的 IOPS 为什么总比管理员设置的 IOPS 少一些呢?这是因为 OceanBase 对 IO 请求的代价做了归一化。
举例来说,64KB 随机读的代价和 4KB 随机读的代价是不一样的,租户规格中配置的 IOPS 使用的基准代价是 16KB 随机读,但实际发生的 IO 请求的尺寸大约是 20KB,经过代价折算后,操作系统中看到的 IOPS 便有些差异。感兴趣的同学可以查看 ob_io_manager 相关代码。
五、写在最后
通过 OceanBase 4.x 的资源隔离能力,用户已可以灵活控制不同负载的资源分配。我们也会不断完善这项能力,解决更多用户关注的问题,例如目前用户仍需要关心租户的 unit 规格以及 unit 数量。 OceanBase 希望把更好的资源隔离能力和使用体验带给大家,让用户像使用自来水一样使用数据库,随着业务流量的变化,OceanBase 自动分配所需的资源,就像使用一个无限资源的单机数据库一样。路虽远,行则将至。
最后,欢迎大家在评论区留言,一起探讨对磁盘 IO 隔离能力的看法。