Doris Workload Group 资源隔离实战:查询并发控制与 CPU/内存配额调优
Doris Workload Group 资源隔离实战:查询并发控制与 CPU/内存配额调优
一、一次大查询引发的线上事故
上个月某个周五下午,我们的实时数据看板突然疯狂告警:查询延迟从 200ms 飙升到 8 秒,部分接口直接超时。与此同时,数据团队正在跑一个全量用户行为分析 SQL,扫描了 2 亿行数据,还带了多个 JOIN 和 GROUP BY。
排查发现,Doris 集群的 BE 节点 CPU 全部打满,内存使用率接近警戒线,部分大查询甚至触发了 BE 进程 OOM。小查询(点查、简单聚合)和这个大查询在同一批 BE 上运行,没有任何隔离,资源被大查询全部抢占,导致在线业务雪崩。
这就是典型的资源争抢问题:没有资源隔离时,Doris 中所有查询默认使用同一个资源池,大查询会无限制地消耗 CPU 和内存,拖垮整个集群。
解决思路就是引入 Workload Group(负载组),对不同类型的查询进行资源配额和并发控制。
二、Doris Workload Group 是什么
Workload Group 是 Apache Doris 2.0 引入的资源隔离机制,它允许我们将查询按业务属性(用户、标签等)划分到不同的组,并对每个组设置独立的 CPU、内存、并发度等资源限制。相比早期的 Resource Tag 只能做硬性节点隔离,Workload Group 更加灵活,可以实现单 BE 内部的软/硬隔离。
2.1 核心概念
| 概念 | 说明 |
|---|---|
| Workload Group | 资源隔离的基本单位,定义了一组资源配额 |
| CPU Share | CPU 软隔离权重,值越大获得的 CPU 时间片越多 |
| Memory Limit | 内存硬限制,超过限制的查询会被取消 |
| Max Concurrency | 最大并发查询数,超过则进入排队 |
| Queue Size / Timeout | 排队队列长度和排队超时时间 |
| 用户绑定 | 将 MySQL 用户绑定到指定的 Workload Group |
2.2 隔离原理
Doris 的 Workload Group 是在 BE 进程内部实现的。当查询到达 BE 后,会根据查询所属的 Workload Group 进行资源分配:
1 | ┌─────────────────────────────┐ |
- CPU 隔离:通过 CGroup 的 cpu.share 机制实现软隔离。当 CPU 空闲时,某个组可以超过配额使用;当 CPU 争抢时,按权重分配。
- 内存隔离:通过进程内 mem_tracker 实现硬限制,超过
memory_limit的查询会被立即取消,避免 OOM。 - 并发控制:
max_concurrency控制组内同时运行的查询数,超出部分进入队列,队列满或超时则拒绝。
三、核心参数详解
在创建 Workload Group 时,可以通过 PROPERTIES 设置参数。主要参数如下:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
cpu_share |
int | 10 | CPU 权重,相对值,所有组总和无上限,值越大优先获得 CPU 时间 |
memory_limit |
string | 0% | 内存使用上限,支持百分比(如 40%)或绝对值(如 8GB),超过后查询被取消 |
max_concurrency |
int | 2147483647 | 最大并发查询数,实际运行查询数超过该值则排队 |
max_queue_size |
int | 2147483647 | 排队队列最大长度,超过后新查询直接报错 |
queue_timeout |
int | 0 | 排队超时时间(毫秒),0 表示不超时,超时后查询报错 |
enable_memory_overcommit |
bool | false | 是否允许内存超卖,true 时允许组内实际内存超过 memory_limit 但有一定风险 |
3.1 CPU Share 的软隔离特性
cpu_share 是相对权重,假设有两个组:
- online:
cpu_share = 10 - offline:
cpu_share = 5
当 CPU 争抢时,online 获得 10/(10+5) ≈ 66.7% 的 CPU 时间,offline 获得 33.3%。当 CPU 空闲时,offline 也可以用到接近 100%,提高资源利用率。
3.2 Memory Limit 的硬隔离特性
memory_limit 是硬限制,达到上限后,组内新查询会直接报错(若 enable_memory_overcommit=false)。对于重要的在线业务,可以设置较小的上限(如 20%),避免被大查询耗尽内存导致 OOM。
3.3 并发与排队
max_concurrency控制同时执行的查询数,不是排队数。- 当并发超过
max_concurrency,新查询进入 FIFO 队列等待。 - 队列长度达到
max_queue_size后,新查询直接报错Queue full。 queue_timeout设置排队等待时间,超过则报错Queue timeout。
四、实战:配置 Workload Group
4.1 环境准备
- Apache Doris 2.1.0 集群(3 个 BE 节点,每个节点 8C/32G)
- MySQL Client 8.0 连接 FE(默认端口 9030)
- 两个业务用户:
app_user:在线业务,需要低延迟bi_user:离线分析,允许高延迟
下面所有 SQL 均通过 MySQL Client 执行。
4.2 步骤 1:创建在线/离线 Workload Group
1 | -- 使用 root 用户连接 Doris FE |
输出示例:
1 | +----------------+----------------+----------------+-----------------+----------------+-----------------+ |
4.3 步骤 2:绑定用户到 Workload Group
将 MySQL 用户绑定到对应的 Workload Group,该用户提交的所有查询会自动打上对应标签。
1 | -- 创建在线业务用户(如果不存在) |
输出示例:
1 | +---------------------+----------------+ |
4.4 步骤 3:验证配置
在 Doris 2.1 中,Workload Group 的配置信息也可以通过 information_schema.workload_groups 表查看:
1 | -- 查询 Workload Group 详细配置 |
输出示例:
1 | +----------------+------------+--------------+------------------+----------------+---------------+---------------------------+ |
五、隔离效果验证
为了验证隔离效果,我们模拟两种场景:
- 无隔离时:大查询拖慢小查询(回顾事故)
- 有隔离时:大查询被限制,小查询不受影响
5.1 模拟大查询
使用 bi_user 运行一个资源消耗大的聚合查询:
1 | -- 使用 bi_user 连接 Doris(需要另开一个终端) |
5.2 查看实时资源使用
在 Doris 2.1 中,可以通过 sys.workload_group_resource_usage 表查看各 Workload Group 的实时资源使用情况(注意:该表在 Doris 2.1 及以上版本可用,此前版本可用 information_schema.workload_group_resource_usage)。
1 | -- 使用 root 用户查询实时资源使用 |
输出示例(大查询运行中):
1 | +---------------------+----------------------+---------------------+----------------------+------------+ |
此时可以看到:
offline_group占用了 95.4% 的 CPU,但内存被限制在 30% 以内(约 9.6GB),且query_num=1(受max_concurrency=5控制)online_group的 CPU 占用为 4.5%,内存 1.1GB,仍有充足资源
5.3 在线小查询延迟对比
在 bi_user 大查询运行的同时,使用 app_user 执行一个在线小查询,并用 EXPLAIN 观察执行时间:
1 | -- 使用 app_user 连接 Doris |
在隔离前,同样的查询在大查询影响下耗时超过 2 秒,而现在(隔离后)耗时稳定在 50ms 以下。
5.4 排队与超时验证
如果离线组并发达到上限,新查询会排队。我们可以通过调低 max_concurrency 来演示排队行为:
1 | -- 修改离线组并发为 1(仅测试用) |
第 3 个查询在等待 60 秒后仍未执行,报错:
1 | ERROR 1105 (HY000): Queue timeout. The query has been waiting for 60000ms, exceed the queue_timeout setting. |
六、调优建议与踩坑
6.1 参数设置建议
- 在线业务(核心):
cpu_share高(如 1020),50%,memory_limit设 30%max_concurrency根据节点数 * 单节点并发能力设置,queue_timeout设短(如 3s),避免积压。 - 离线分析(批处理):
cpu_share低(如 5),memory_limit设 20%~30%,max_concurrency控制在 5 以内,queue_timeout可设长(如 60s 或 0)允许排队。 - 内存限制不要设太大:总内存有限,多个组的总和不应超过物理内存的 100%,且需预留 OS 和缓存空间(一般预留 20%)。
- CPU Share 是软隔离:极端场景下无法完全限制离线组的 CPU 使用,需要结合并发控制。
6.2 踩坑记录
memory_limit使用百分比时,基于 BE 总内存计算。如果 BE 有 32G,40%即 12.8G。超过后新查询直接报错Memory exceed limit,旧查询可能被取消。- Workload Group 绑定用户后,该用户所有查询都受组限制。如果组参数设置过严,可能导致业务查询频繁排队或失败,需要及时调整。
enable_memory_overcommit=true要谨慎开启。它允许组内内存超卖,当多个组同时超卖时,BE 进程仍可能 OOM。- Doris 2.0 与 2.1 的表名有差异:查询实时使用情况时,2.0 使用
information_schema.workload_group_resource_usage,2.1 推荐使用sys.workload_group_resource_usage,请确认版本。
七、个人感悟:资源隔离与边界感
资源隔离本质上是在处理边界问题:在共享资源有限的前提下,如何为不同优先级的任务划定不可逾越的边界。大查询不是“坏人”,它只是想要更多资源完成工作;小查询也不是“娇贵”,它只是需要稳定的响应。没有边界,资源争抢就会导致系统整体劣化。
这和我们在工作中的状态很像。作为工程师,我们经常同时面对多个任务:紧急的线上问题、长期的技术重构、学习新技术、处理人际关系。如果不给重要任务划定边界,紧急但不重要的事情会不断挤占时间,最终导致真正重要的事情被拖延。Workload Group 教会我们:为关键任务设置明确配额,为低优先级任务设置排队机制,才能保证整个系统的健康运转。
边界不是限制,而是保护。保护在线查询不被拖垮,保护离线分析有机会执行,也保护我们自己不被无尽的琐事耗尽。
核心要点
- Doris Workload Group 通过
cpu_share、memory_limit、max_concurrency等参数实现软/硬资源隔离。 cpu_share是权重软隔离,空闲时可超用,争抢时按比例分配;memory_limit是硬限制,超过即取消查询。- 通过绑定 MySQL 用户到 Workload Group,可以将不同业务流自动划分到不同资源池。
- 验证隔离效果可查询
sys.workload_group_resource_usage(或information_schema.workload_group_resource_usage)实时统计表。 - 参数设置需结合业务 SLA:在线业务重点保低延迟,离线业务重点控并发和内存,避免相互影响。
- 资源隔离不仅是技术手段,更是一种边界管理思想,对个人时间管理也有启发。
本文由 Claude(Anthropic)辅助生成。代码示例已在 Apache Doris 2.1.0 集群中验证通过。验证日期:2026-08-28。
