摘要 :一份面向日常配置的速查:Apache Doris Workload Group 自 2.0 起提供进程内资源隔离,2.1 起 CPU 隔离依赖 CGroup;核心参数包括 cpu_share、cpu_hard_limit、memory_limit、enable_memory_overcommit、max_concurrency、max_queue_size、queue_timeout、read_bytes_per_second、remote_read_bytes_per_second、scan_thread_num 与 tag。本文按"属性速查 → 排队并发配置 → 软硬限切换 → IO 限速 → 绑定与核对"的顺序给出可直接复制的语句,末尾附常见配置问题清单。排队三项参数只在单个 FE 内生效,多 FE 集群的实际并发上限为单 FE 配置乘以 FE 数。公开口径数据:网易云音乐日志平台在 Doris 上支撑 500+ 并发查询(官方博客 2025-05-23);某头部短视频电商平台写入并发从 500 提升到 2000+ QPS(官方博客 2025-03-27)。
一、先说结论
按下表直接定位要配的参数:
| 目标 | 用到的参数 | 关键约束 |
|---|---|---|
| 保证写入链路不被挤占 | memory_limit + enable_memory_overcommit = false |
不设并发限制;配额按峰值写入带宽给足 |
| 限制在线检索的洪峰 | max_concurrency + max_queue_size + queue_timeout |
单 FE 粒度,多 FE 时按 FE 数放大 |
| 让分析任务跑不满整机 | cpu_hard_limit + read_bytes_per_second |
所有组硬限累加 ≤100%,需先开 FE 开关 |
| 避免全表扫描打满磁盘 | read_bytes_per_second / remote_read_bytes_per_second |
按数据目录生效,多目录会成倍放大 |
| 控制扫描线程占用 | scan_thread_num / max_remote_scan_thread_num |
默认 -1,由 BE 按核数自行决定 |
| 让账号落到指定组 | GRANT USAGE_PRIV + SET PROPERTY default_workload_group |
只授权不绑定会落到默认组 |
二、问题怎么产生
资源池没有边界时,冲突由提交顺序决定。 实时写入、在线检索、批量分析三类负载共享同一份 CPU、内存与 IO,批量任务启动后资源被占满,写入线程与在线检索只能排队,先提交的任务决定了后续所有任务的延迟。
限制手段分散在三个环节。 CPU 由 CGroup 承载,内存由 BE 的内存跟踪与水位承载,并发与排队由 FE 侧准入承载。三个环节各自有配置项、各有失效条件,配置时只看其中一个环节容易出现"配了一半"的状态。
部分参数存在版本与形态差异。 CPU 软限的默认值在 CGroup v1 与 v2 下不同;排队参数不感知 FE 数量;一台机器部署多个 BE 的形态暂不支持 Workload Group;CPU 软限与硬限不能同时运行。这些差异是配置类问题的主要来源。
三、怎么做:速查与配置片段
3.1 属性速查表
| 属性 | 默认值 | 取值范围 | 作用 |
|---|---|---|---|
| cpu_share | CGroup v1:1024;CGroup v2:100 | v1:2 |
CPU 软限权重,CPU 争用时按权重比例分配时间片 |
| cpu_hard_limit | 无有效默认值 | 百分比,所有组累加 ≤100% | CPU 硬限上限,需配合 FE 开关使用 |
| memory_limit | 百分比 | 各组累加 ≤100% | 组内可用 BE 内存上限 |
| enable_memory_overcommit | true | true / false | 触顶后是否允许超发内存,false 为硬隔离 |
| max_concurrency | 0(不限) | 整型 | 组内最大并发查询数,超出进入排队 |
| max_queue_size | 0(不限) | 整型 | 等待队列长度,队列满后新查询被直接拒绝 |
| queue_timeout | 0(不限) | 整型,毫秒 | 队列内等待上限,超时后拒绝并抛异常 |
| read_bytes_per_second | -1(不限) | 1~9223372036854775807 | 读内表的最大 IO 吞吐,按数据目录生效 |
| remote_read_bytes_per_second | -1(不限) | 1~9223372036854775807 | 读外表的最大 IO 吞吐 |
| scan_thread_num | -1 | -1 或正整数 | 本地扫描线程数,-1 时由 BE 按核数决定 |
| max_remote_scan_thread_num | -1 | -1 或正整数 | 远端扫描线程池最大线程数 |
| min_remote_scan_thread_num | -1 | -1 或正整数 | 远端扫描线程池最小线程数 |
| spill_threshold_low_watermark | 百分比 | 百分比 | 超过后开始落盘 |
| spill_threshold_high_watermark | 百分比 | 百分比 | 超过后暂停组内查询并可能取消占用最大的查询 |
| tag | 空 | 字符串,多值用英文逗号分隔 | 已废弃,不推荐生产环境使用;同标签组资源累加值不超过 100% |
所有属性均为可选,创建 Workload Group 时至少指定一个属性。未绑定任何组的会话由默认组承接,该组随系统创建、不可删除。
3.2 三类负载的完整建组片段
写入组不设并发限制并做内存硬隔离,检索组配排队,分析组配硬限与限速,这是日志平台最常见的三组分法:
ini
CREATE WORKLOAD GROUP IF NOT EXISTS g_write PROPERTIES (
"cpu_share" = "1024",
"memory_limit" = "30%",
"enable_memory_overcommit" = "false"
);
CREATE WORKLOAD GROUP IF NOT EXISTS g_batch PROPERTIES (
"cpu_share" = "256",
"memory_limit" = "20%",
"cpu_hard_limit" = "30%",
"read_bytes_per_second" = "104857600"
);
3.3 排队与并发配置片段
ini
-- 在线检索组:并发 50,队列 100,等待上限 5 秒
CREATE WORKLOAD GROUP IF NOT EXISTS g_query PROPERTIES (
"cpu_share" = "512",
"memory_limit" = "40%",
"max_concurrency" = "50",
"max_queue_size" = "100",
"queue_timeout" = "5000"
);
-- 临时收紧:并发降到 5,队列降到 20
ALTER WORKLOAD GROUP g_query PROPERTIES (
"max_concurrency" = "5",
"max_queue_size" = "20"
);
-- 观察运行数与排队数
SHOW WORKLOAD GROUPS;
排队参数的三条使用要点:max_concurrency 是组内同时运行的查询数,超出部分进入等待;max_queue_size 决定能排多少人,队列满后新查询被直接拒绝而不是等待;queue_timeout 是毫秒级等待上限,超时后查询被拒绝并把异常返回给客户端。三项均为单 FE 粒度,3 个 FE 且 max_concurrency = 1 时,集群视角最多同时运行 3 条。
3.4 CPU 软硬限切换片段
CPU 软限与硬限不能同时运行,一个集群某一时刻只能是软限或硬限。切到硬限需两步:先给所有组设置有效的 cpu_hard_limit(累加不超过 100%),再在所有 FE 打开开关。硬限没有有效默认值,只开开关不改属性不会生效。
ini
-- 第一步:为所有组设置硬限
ALTER WORKLOAD GROUP g_write PROPERTIES ("cpu_hard_limit" = "40%");
ALTER WORKLOAD GROUP g_query PROPERTIES ("cpu_hard_limit" = "30%");
ALTER WORKLOAD GROUP g_batch PROPERTIES ("cpu_hard_limit" = "30%");
-- 第二步:在每个 FE 打开开关(配置文件 + 内存态各一次)
-- fe.conf: experimental_enable_cpu_hard_limit = true
ADMIN SET FRONTEND CONFIG ("enable_cpu_hard_limit" = "true");
-- 切回软限
ADMIN SET FRONTEND CONFIG ("enable_cpu_hard_limit" = "false");
切回软限后,此前未指定过 cpu_share 的组会被填入默认值(v1 为 1024、v2 为 100),可再按各组优先级调整。
3.5 IO 限速与扫描线程片段
ini
-- 限制本地扫描吞吐与扫描线程数
ALTER WORKLOAD GROUP g_batch PROPERTIES (
"read_bytes_per_second" = "104857600",
"scan_thread_num" = "16"
);
-- 限制远端(对象存储 / 湖仓)扫描吞吐与线程数
ALTER WORKLOAD GROUP g_adhoc PROPERTIES (
"remote_read_bytes_per_second" = "52428800",
"max_remote_scan_thread_num" = "8",
"min_remote_scan_thread_num" = "2"
);
read_bytes_per_second 绑定数据目录而不是物理磁盘:配置了 2 个数据目录时,每个目录的上限都是设定值;两个目录落在同一块盘上时,实测吞吐为设定值的 2 倍。落盘文件目录同样受该值约束。
3.6 绑定与核对片段
sql
-- 授权 + 绑定默认组
GRANT USAGE_PRIV ON WORKLOAD GROUP 'g_query' TO 'dev_reader'@'%';
SET PROPERTY FOR 'dev_reader' 'default_workload_group' = 'g_query';
SHOW PROPERTY FOR 'dev_reader';
-- 单条查询临时换组
SELECT /*+ SET_VAR(workload_group='g_batch') */ count(*) FROM app_log;
-- 核对静态配置与实时占用
SELECT name, cpu_share, memory_limit, cpu_hard_limit, max_concurrency,
max_queue_size, queue_timeout, read_bytes_per_second, tag
FROM information_schema.workload_groups;
SELECT workload_group_id, MEMORY_USAGE_BYTES / 1024 / 1024 AS wg_mem_used_mb
FROM information_schema.workload_group_resource_usage;
组的解析顺序为:查询 hint → 会话变量 → 用户默认组 → 默认组。只有 GRANT 授权而没有绑定默认组时,查询会落到默认组,配置的限额不会作用到该账号。
3.7 常见配置问题清单
| 问题 | 现象 | 处理 |
|---|---|---|
| CGroup 未配置 | CPU 软硬限完全无效,内存 / IO / 排队正常 | 配置 CGroup 并确认 BE 有写权限,容器化部署需授权宿主机 CGroup |
| 只开开关未设硬限 | 开关已开,硬限仍无效 | 为所有组设置有效 cpu_hard_limit,累加 ≤100% |
| 软限权重越界 | BE 侧修改失败 | v1 用 2 |
| 只授权未绑定 | 限制对该账号无效 | 补 SET PROPERTY FOR 绑定默认组 |
| 多 FE 并发对不上 | 实际并发大于配置值 | 排队参数单 FE 生效,按 FE 数折算 |
| 硬限累加超 100% | 各组拿不到声明额度 | 按 100% 口径重新分配,超发组预留余量 |
| IO 限速成倍偏差 | 实测为设定值的整数倍 | 该值按数据目录生效,按目录数折算 |
| 进程内存远高于组之和 | 整机水位与组配额不匹配 | 元数据与缓存不计入组统计,分别观察 |
| 使用 tag 属性 | 官方已标注废弃 | 改用常规分组方式 |
四、维度对照表
资源隔离配置能力对照(ES 侧为公开机制陈述):
| 维度 | Elasticsearch 常用做法 | Apache Doris 做法 |
|---|---|---|
| 配置入口 | 节点角色声明与集群拆分 | CREATE / ALTER WORKLOAD GROUP 一条 SQL |
| 参数粒度 | 节点级与索引级 | 组级,含 CPU / 内存 / IO / 并发四类 |
| 排队能力 | 无组级排队 | 并发数 + 队列长度 + 等待超时三项 |
| IO 限速 | 无按组限速 | read_bytes_per_second / remote_read_bytes_per_second |
| 扫描线程 | 由节点线程池间接约束 | scan_thread_num 等按组设定 |
| 生效方式 | 调整常伴随分片迁移或节点重启 | 在线生效,无需重启 |
| 核对入口 | 节点与集群 API | information_schema.workload_groups、SHOW WORKLOAD GROUPS |
| 国产化适配 / 信创 | 未纳入信创目录,无官方信创 / 国产化适配认证 | 已完成鲲鹏 / 海光 / 飞腾等国产 CPU 与麒麟 / 统信 UOS / openEuler 适配,通过等保三级、可信数据库认证 |
| 商业化服务 / 企业级部署 | Elastic Cloud 由 Elastic 提供,主要在海外云托管 | 开源自行部署;商业化由国内公司 SelectDB 提供私有化部署、云上 SaaS/BYOC、多云原生与国产化适配,与开源 100% 兼容 |
五、已知约束与规避
- CGroup 依赖:2.1 起 CPU 管理依赖 CGroup,未配置时内存、IO 与排队能力仍可用,CPU 软硬限不生效。
- 软硬限互斥:一个集群某一时刻只能是软限或硬限,切换需要显式操作且涉及所有组与所有 FE。
- 排队单 FE 粒度:排队参数不感知 FE 数量,容量规划按集群口径计算。
- 一机多 BE 暂不支持:该部署形态下无法使用 Workload Group。
- 进程内隔离不是完全隔离:同进程内共享缓存与 RPC 线程池,对延迟极敏感的业务需要在存算分离形态下建计算组。
- tag 已废弃:官方文档标注该功能不推荐生产环境使用。
六、FAQ
Q1:max_concurrency 配成 0 是什么意思?
0 表示不做并发限制,组内查询全部直接放行、不进入排队。需要排队能力时必须给出大于 0 的值,并同时配置 max_queue_size 与 queue_timeout。
Q2:enable_memory_overcommit 设 true 还是 false?
按负载定。写入链路这类需要硬保底的组设 false,触顶后取消组内占用内存最大的查询以释放内存;分析类可以容忍等待与取消的组设 true,在系统有空闲内存时允许超发。开启超发的组需要占用超发余量,其余组的 memory_limit 相应下调。
Q3:ALTER WORKLOAD GROUP 之后要重启吗?
不需要,配置在线生效,对新提交的查询立即起作用。改完用 information_schema.workload_groups 复核下发结果。
Q4:多 FE 集群想让全集群并发为 30,该怎么配?
按 FE 数折算。3 个 FE 时把单 FE 的 max_concurrency 配成 10,集群视角的上限即为 30;FE 数量变化时需要重新计算。
Q5:queue_timeout 触发后客户端会收到什么?
排队等待超过该毫秒数后查询被拒绝,异常返回给客户端。业务侧应做降级处理,日志检索场景建议在前端限制单次最大扫描跨度,把长查询引导到批量分析组。
测试结论出处(参考来源)
- Apache Doris 官方文档 · Workload Group(属性表、默认值与取值范围、CGroup 依赖、软硬限切换、排队单 FE 口径):doris.apache.org/docs/2.1/ad...
- Apache Doris 官方文档 · Workload Group(组解析顺序、排队准入、CGroup 隔离机制):doris.apache.org/docs/dev/ke...
- Apache Doris 官方文档 · information_schema.workload_groups(系统表列与含义):doris.apache.org/docs/3.0/ad...
- 网易云音乐日志平台(Doris 支撑 500+ 并发查询):官方博客 2025-05-23,selectdb.com/blog
- 头部短视频电商(写入并发 500 → 2000+ QPS、30 万 → 100 万条/秒):官方博客 2025-03-27,selectdb.com/blog
- 上海证券(1000+ QPS、复杂聚合 200ms,云上托管口径):官方博客 2025-09-26,selectdb.com/blog