Apache Doris资源管理实战:Workload Group与存储分层
2026/9/10 17:15:23 网站建设 项目流程

1. 资源管理为什么成了 Doris 集群的头等大事

搞数据平台的人这几年应该都有同感:Apache Doris 早就不只是“一个能跑 SQL 的分析型数据库”那么简单了。现在生产环境里动辄上百张表、几十个业务方共用一个集群,有人跑大宽表关联,有人做高并发点查,还有人天天凌晨跑全量 ETL。表面上大家共用一套 Doris,实际上彼此之间争 CPU、抢内存、挤磁盘 IO,稍微有个“大查询”就能把整个集群拖垮。这时候你再回头看“doris资源管理”这个话题,它就不只是一个功能开关,而是生产环境能不能稳定运行的生命线。

资源管理在 Doris 里的定位,简单说就是给不同业务、不同查询划分“用多少算力”的边界。它解决的不是“能不能查到数据”,而是“这个查询能不能在不影响别人的前提下跑完”的问题。我见过不少团队,Doris 装好了、数据导进去了、报表也通了,结果一上生产就频繁超时,查一下 BE 日志全是内存溢出或者磁盘排队,根源就是从来没做过资源隔离。

这篇内容主要面向两类人:一类是刚把 Doris 部署完、准备接真实业务的平台工程师,另一类是被“集群又变慢了”弄得焦头烂额的运维同学。我会把 Doris 资源管理涉及的计算资源、存储资源、运维工具、同步链路评估、基础设施编排这些维度都拆开来讲,既有原理也有可直接抄的配置,希望你看完能对自己的集群有个清晰的治理思路。

2. 计算资源治理:Workload Group 的分组隔离思路

2.1 为什么单靠“限流”解决不了问题

很多人在接触 Doris 的资源管理之前,习惯用一句“别跑大查询”来约束业务方。这话说了等于没说。业务方根本不知道自己的 SQL 算不算大查询,等发现的时候往往已经拖垮集群了。Doris 官方的答案是 Workload Group——也就是把查询分成不同的组,每组独立设置 CPU、内存、并发度的上限,组与组之间互不干扰。

这个设计思路类似于把一套房子隔成几个房间:厨房里可以开大火爆炒(跑批任务),卧室里只需要小功率照明(高并发点查),互不抢电闸。具体的实现上,Doris 通过workload_group表来定义分组,再通过用户或者查询标签把 SQL 路由到对应分组。

我建议你至少划分出三组:etl_group给离线同步和 ETL 任务,adhoc_group给分析师跑临时查询,point_query_group给线上高并发接口。这三个业务的资源特征完全不同,混在一起必然互相踩踏。

2.2 关键参数怎么定:CPU、内存、并发度

创建 Workload Group 的 SQL 不复杂,难的是参数怎么定。先看一个实际可用的配置:

CREATE WORKLOAD GROUP etl_group PROPERTIES ( "cpu_share" = "50", "memory_limit" = "60%", "max_concurrency" = "10", "max_queue_size" = "20", "queue_timeout" = "30000" ); CREATE WORKLOAD GROUP point_query_group PROPERTIES ( "cpu_share" = "30", "memory_limit" = "20%", "max_concurrency" = "100", "max_queue_size" = "500", "queue_timeout" = "1000" );

cpu_share是相对权重而不是绝对核数。比如两个组分别是 50 和 30,在有竞争时按 5:3 分配 CPU。这里有个容易踩的坑:cpu_share 只在 CPU 争抢时生效,如果 CPU 还有大量空闲,即使 cpu_share 很小也能跑满。所以不要以为设置了 cpu_share 就万事大吉,还要结合并发限制一起用。

memory_limit是这个组最多能用 BE 总内存的百分比。我见过有人把三个组的 memory_limit 加起来设到 150%,结果查询大量排队,还以为是 Doris 出 bug 了。切记所有组的 memory_limit 之和不要超过 100%,而且建议预留 10% 到 20% 给系统开销和元数据缓存。

max_concurrencymax_queue_size是一对搭档。前者决定同时跑多少个查询,后者决定排队的长度。queue_timeout则是排队超过多少毫秒直接报错给客户端。对于线上点查接口,queue_timeout 一定要设置得很短,比如 1000 毫秒,宁可让个别请求快速失败让调用方重试,也不能让请求堆积成雪崩。

2.3 查询路由:绑定用户还是按标签

定义好分组之后,要让查询进到对应分组里,通常有两种方式。

第一种是绑定用户,非常直接:

SET PROPERTY FOR 'etl_user' 'resource_tags.location' = 'group:etl_group';

第二种是使用查询标签,适合同一个用户跑多种类型任务的情况。在连接初始化的时候执行:

SET workload_group = 'adhoc_group';

或者在 JDBC URL 里直接带上:

jdbc:mysql://127.0.0.1:9030/db?workload_group=adhoc_group

标签这种方式更灵活,但需要业务方配合改连接串。我的实际经验是:能绑用户就绑用户,运维成本最低。只有在同一个账号确实无法拆分时,才用标签方式。

2.4 软限与硬限:别把资源卡得太死

Workload Group 还有两个容易被忽略的参数:read_bytes_per_second(软限)和max_read_bytes_per_sec(硬限)。软限是尽力而为,超过后只做标记;硬限是超过就限速。

我建议在生产环境先只设置软限,观察一段时间业务表现后再决定要不要上硬限。直接上硬限很可能把正常的大查询也给误伤了——这个“误伤”问题,后面第四节讲 Doris Manager 诊断案例时会具体展开。总之,资源管理是逐步收紧的过程,不是一次配好就完事。

3. 存储资源管理:分层存储与冷热分离

3.1 存储也是资源,而且往往最先爆

说到资源管理,很多人只盯着 CPU 和内存,忽略了磁盘。但对于 Doris 这种列式存储的 OLAP 数据库,磁盘空间和 IO 能力往往比计算资源更早成为瓶颈。Doris 的 BE 节点把数据以 Tablet 的形式落盘,每个 Tablet 包含若干 Rowset,数据量大了之后,磁盘空间、写入放大、查询扫描的 IO 开销都会迅速上升。

Doris 从 2.0 版本开始正式支持分层存储,可以把冷数据放到对象存储或者 HDFS 上,本地只保留热数据。这个能力在实际生产中非常实用——你不需要为了那 20% 很少被访问的历史数据不停扩本地盘。

3.2 冷热数据分层的配置思路

创建一个分层的分区表,核心是设置STORAGE_POLICY

CREATE STORAGE POLICY s3_cold_policy PROPERTIES ( "storage_resource" = "s3_cold", "cooldown_ttl" = "7d", "cooldown_datetime" = "2025-01-01 00:00:00" );

这里的cooldown_ttl表示数据写入后 7 天自动迁到冷存储。cooldown_datetime则是设定一个具体时间点,到达之后数据就降冷。

建表时引用这个策略:

CREATE TABLE user_behavior ( user_id BIGINT, event_time DATETIME, behavior STRING ) DUPLICATE KEY(user_id) PARTITION BY RANGE(event_time) (...) PROPERTIES ( "storage_policy" = "s3_cold_policy" );

存储策略可以细化到分区级别。我处理过一个场景:订单表按月份分区,管理层要求最近 3 个月的数据必须本地毫秒级响应,三个月前的历史数据只需要偶尔跑一次分析。我的做法是每个月新分区使用本地热存储策略,三个月后手动把该分区迁移到 S3 策略,这样既控制了成本又保证了热点查询性能。

3.3 本地盘IO的隔离技巧

如果你暂时没有对象存储,所有数据都堆在本地盘上,那就要注意磁盘 IO 的隔离。Doris 的 BE 配置项里有一个容易被忽视的参数:storage_high_burst_max_secondsstorage_cooldown_seconds,它们影响写入时是否需要控制峰值。

实际运维中更常用的是BE节点上挂多块盘时,按目录隔离业务。比如一块 SSD 放热数据表,一块 HDD 放冷数据表,Doris 会按照目录的medium属性自动调度:

storage_root_path = /data1/ssd,medium:ssd;/data2/hdd,medium:hdd

设置好之后,建表时可以指定:

PROPERTIES ( "storage_medium" = "SSD", "storage_cooldown_time" = "2025-06-01 00:00:00" );

到了storage_cooldown_time,Doris 会自动把数据迁移到 HDD 目录。这个机制在表级实现了冷热分离,不需要额外引入外部存储。

3.4 存储配额和回收:防患于未然

Doris 的磁盘配额管理相对基础,不会像 HDFS 那样直接拒绝写入,而是依赖 BE 的磁盘剩余空间判断。建议你在监控系统里对每个 BE 的磁盘使用率设置 70% 告警阈值,超过 80% 必须立即处理,否则一旦磁盘写满,整个 BE 会进入异常状态,甚至影响副本机制的正常工作。

清理空间时优先处理两类数据:一是废弃表的 Tablet,二是过期的分区。Doris 的DROP TABLEDROP PARTITION会异步删除底层文件,如果磁盘长期不释放,可以手动触发一次 BE 的垃圾回收:

ADMIN CLEAN TRASH;

这条命令对中小集群很有效,我每次清理完分区之后都会执行一次,实测能快速释放本地磁盘空间。

4. Doris Manager:可视化资源治理的实用姿势

4.1 Manager 到底能帮我们做什么

很多 DBA 习惯命令行操作,对可视化运维工具有点不屑一顾。但 Doris Manager(官方运维管理平台)在资源治理方面的价值,远远超出了“看到监控图表”这个层面。它相当于给 Doris 集群装了一个“带仪表盘的中控台”,能直观看到每个 BE 的 CPU、内存、磁盘 IO、查询延迟,还能做告警和诊断。

对于资源管理来说,Manager 最大的价值是把“不知道资源去哪了”变成“能快速定位谁在抢资源”。

部署 Doris Manager 本身不复杂,官方支持 Docker 一键起,也支持 RPM 包安装。我比较推荐 Docker Compose 方式,配置简单,后续升级也方便。需要提醒的是 Manager 服务本身不要和 Doris 集群部署在同一批机器上,否则监控系统出问题时会连带影响集群稳定性。

4.2 用 Manager 做资源水位分析

登录 Manager 之后,建议先看“节点管理”里的资源总览页面。重点关注两个指标:CPU 使用率的均值和峰值、内存使用率的均值和峰值。均值高说明负载确实重,峰值高但均值低说明有瞬时大查询,需要检查 Workload Group 的排队和超时设置。

还有一个容易被忽视的点:Doris Manager 的“查询管理”页面能看到当前正在执行的所有 SQL 及其所属 Workload Group、内存占用、扫描行数。我排查“集群突然变慢”时,第一个动作就是打开这个页面,按“内存占用”降序排列——通常顶部那条 SQL 就是罪魁祸首。

之前遇到过一个案例:某业务方跑了一条扫描 20 亿行的大关联查询,内存占用直接打到 BE 总内存的 40%。好在 Workload Group 里有memory_limit兜底,没把整个集群搞挂,但其他查询已经被挤到严重排队。通过 Manager 定位到这条 SQL 之后,我直接联系业务方改 SQL,同时把该用户绑定到低优先级的 adhoc 组,集群立刻恢复正常。

4.3 告警规则设置建议

Manager 的告警配置非常有价值,关键是别乱配。我的实践经验是告警项宁少勿多,优先覆盖这四类:

  • BE 节点宕机或心跳丢失(这是最严重的,必须电话级别告警)
  • 磁盘使用率超过 75%(预留缓冲时间来处理)
  • 查询成功率低于 99%(说明资源已经明显不足)
  • Workload Group 队列堆积超过 5 分钟(说明并发配置不合理)

告警渠道建议同时配置邮件和 webhook,webhook 可以接到飞书或钉钉群。阈值不要设太敏感,否则天天报警,真正出问题时反而没人管了。

5. CCR 同步链路的资源成本评估

5.1 CCR 是什么,和资源管理有什么关系

CCR(Cross Cluster Replication)是 Doris 提供的一种跨集群数据同步能力,通过ccr-syncer这个独立进程来调度。很多团队用它在两个机房部署双集群,做容灾或者读写分离。

但 CCR 有一个特点经常被忽略:同步链路本身会消耗源集群和目标集群的资源。源集群需要额外读 Binlog 产生同步任务,目标集群需要执行写入和 compaction。如果没有给 CCR 的同步流量预留资源空间,它就会和正常业务查询抢资源,造成双向影响。

5.2 建立 CCR 同步前的资源预检清单

我建议在开启 CCR 任务之前,先对照这个清单做一次资源检查:

  • 源集群的 CPU 使用率是否长期在 60% 以上?如果是,同步任务可能会加剧 CPU 竞争。
  • 源集群的 BE 内存是否有 10% 以上的余量?Binlog 读取和同步状态维护需要额外内存。
  • 目标集群是否有足够的磁盘空间?CCR 同步本质上是全量加增量,目标集群数据量最终会和源接近。
  • 网络带宽是否够用?尤其是在跨机房场景下,带宽不足会导致同步延迟持续拉大。

如果以上某项不满足,建议先扩容再建同步任务,否则同步性能上不去,还会拖累两边集群的在线业务。

5.3 同步延迟和资源消耗的平衡

实际操作中,ccr-syncer 通过binlog_fetch_concurrencyworker_count控制同步的并发度。默认参数偏保守,如果你的网络和磁盘够好,可以适当调高来降低同步延迟:

binlog_fetch_concurrency = 5 worker_count = 8

但同时要给 ccr-syncer 运行的机器配置足够资源。我这里有个经验值:单机的 CPU 核数建议不低于 4 核,内存不低于 8GB,磁盘的随机读写 IOPS 不低于 3000。否则同步任务一多,syncer 进程自身就会成为瓶颈。

6. 用 Terraform 编排 Doris 资源集群

6.1 为什么资源管理也需要 IaC

很多团队对 Doris 的部署和资源规划停留在“手动操作”阶段:建机器、装环境、改配置、拉副本。这种方式在小规模场景下没问题,但一旦涉及多套环境(开发、测试、生产),或者需要在云上快速拉起一套集群,手动操作的低效率和失误率就会暴露出来。

Terraform 的价值在于把基础设施的资源定义变成代码,存储库管理、走评审、可回滚。对于 Doris 资源管理来说,Terraform 能管的是“底层资源的申请和配置”,比如云上的 ECS 实例规格、数量、磁盘大小、网络分组,以及节点的初始化脚本。

6.2 一个最小可用的 Terraform 配置实例

假设你的 Doris 集群需要 3 个 FE、5 个 BE,每个节点要求 8 核 32GB 内存、200GB SSD。用 Terraform 管理云资源时,核心配置大致如下:

# 定义 BE 节点资源 resource "alicloud_instance" "doris_be" { count = 5 instance_type = "ecs.g6.2xlarge" system_disk_category = "cloud_ssd" system_disk_size = 200 vswitch_id = var.vswitch_id security_groups = [var.security_group_id] user_data = <<-EOF #!/bin/bash cd /opt/doris ./be/bin/start_be.sh --daemon EOF tags = { Name = "doris-be-${count.index}" Cluster = var.cluster_name Role = "BE" } } # 定义 FE 节点资源 resource "alicloud_instance" "doris_fe" { count = 3 instance_type = "ecs.g6.2xlarge" system_disk_size = 100 vswitch_id = var.vswitch_id security_groups = [var.security_group_id] user_data = <<-EOF #!/bin/bash cd /opt/doris ./fe/bin/start_fe.sh --daemon EOF tags = { Name = "doris-fe-${count.index}" Cluster = var.cluster_name Role = "FE" } }

Terraform 的优势在于,可以通过count和参数化变量灵活调整节点数量。比如预发环境,只需要把var.be_count从 5 改成 2,然后执行terraform apply,就能拉起一套缩小版的资源环境。相比手动登录云控制台一个个点按钮,效率和准确性都高了一个量级。

6.3 资源编排的两个重要提醒

第一个提醒:Terraform 只管到“机器层面”,Doris 内部的资源参数(Workload Group、存储策略、副本数)还是要用 SQL 或 Doris Manager 来配置。所以完整的自动化思路是:用 Terraform 管基础设施,用 SQL 脚本或 Ansible 管 Doris 内部的资源策略,两个层面配合而不是替代。

第二个提醒:云盘规格的选择会直接影响 Doris 的 IO 性能。生产环境不要用突发性能型的云盘(比如 burst 类型的实例),否则一旦 IO 积分耗尽,整个集群的查询延迟会突然暴涨,而且很难排查。选型时优先保证磁盘的 IOPS 和吞吐量指标,CPU 核数不足可以靠扩节点弥补,磁盘 IO 受限则几乎无解。

7. Doris 和 StarRocks 在资源管理上的取舍

7.1 两者的资源管理思路差异

这里想单独聊聊 Doris 和 StarRocks 的对比,因为这两者的资源管理思路确实有差异,但网络上很多说法其实不够严谨。

Doris 这边,资源管理的核心是 Workload Group,指标覆盖 CPU、内存、并发度、IO,而且从 2.1 开始能力逐渐完善,各个维度都能做硬限制。

StarRocks 则是通过 Pipeline 执行引擎来做资源隔离,同样支持资源组(Resource Group)的概念,可以限制 CPU、内存和并发。两个系统在大的思路上是相似的,都强调多租户场景下的查询隔离,但实现细节和演进时间点不太一样。

7.2 选型建议:别只看宣传特性

从我实际使用的感受来说,两者在资源管理上的差距并没有网上说的那么大。选型时更应该关注的是你周围的生态、团队的熟悉程度、以及已经跑的代码能不能平滑迁移。

有一个比较容易踩的坑:网上很多文章说 Doris 不支持条件删除,其实在Unique 模型下开启enable_unique_key_merge_on_write之后,DELETE配合 WHERE 条件是可以正常工作的。这类细节很多对比文章根本不会提到,但实际迁移时却能卡住整个项目。

如果你现在维护的是 Doris 集群,没必要因为“听说 StarRocks 资源管理更强”就盲目迁移。把 Doris 现有的 Workload Group 和存储策略用透彻,大多数场景都能覆盖。

8. 常见问题与排查实录

8.1 查询排队严重,但 CPU 占用很低

这是我被问过最多的问题。排查思路很明确:先看 Workload Group 的max_concurrencymax_queue_size是不是设置得太小。如果并发上限是 5,而有 30 个查询同时进来,25 个会排队,此时 CPU 可能才用 10%。这类问题不能靠加机器解决,而是调整并发配置。

ALTER WORKLOAD GROUP adhoc_group PROPERTIES ( "max_concurrency" = "30", "max_queue_size" = "100" );

8.2 设置了 memory_limit 却还是内存溢出

Workload Group 的memory_limit管的是查询执行的内存上限,但 BE 进程本身还有一些固定的内存开销,比如元数据缓存、compaction 内存等。如果你给所有组的 memory_limit 加起来等于 100%,那么一旦出现 compaction 高峰,还是会触发内存问题。建议所有组的 memory_limit 总和控制在 80% 以内,剩下的留给系统开销。

8.3 磁盘空间一直在涨,删了表也不释放

Doris 删除数据是异步的,标记删除后底层文件不会立刻消失。如果删完之后空间迟迟不释放,先确认是否有正在进行的 compaction,再用ADMIN CLEAN TRASH;触发清理。如果还是不行,检查一下 BE 日志里是否有副本修复任务,这类任务会重新拉取数据导致空间不降反升。

8.4 资源异常排查速查表

现象可能原因处理动作
查询成功率下降Workload Group 并发超额导致排队调高 max_concurrency 或拆分业务
CPU 使用不均衡数据倾斜或副本分布不均检查 tablet 分布手动均衡
同步任务延迟高ccr-syncer 并发不足或网络带宽受限调高 worker_count 并检查带宽
磁盘 IO 持续打满大量 compaction 或查询全表扫描错峰执行 ETL,开启冷热分层
内存缓慢增长不释放BE 缓存或查询泄漏重启 BE 观察,检查慢查询

9. 最后一次提醒:资源管理是持续治理,不是一锤子买卖

我个人折腾 Doris 资源管理这几年,最大的体会是:没有一劳永逸的配置,资源管理必须跟随业务形态持续迭代。每个季度我都会做一次集群资源盘点,看看哪些业务变了、哪些表冷了、哪些 Workload Group 的参数已经不适合当前负载。刚接手一个 Doris 集群时,先别急着调一堆参数,先观察两周真实负载,用 Doris Manager 把资源水位摸清楚,再动手微调。

另外想分享一个小技巧:每次调整 Workload Group 或存储策略之前,把当前所有组的参数用SHOW WORKLOAD GROUPS;SHOW STORAGE POLICY;导出保存。一旦调整后出现异常,可以快速回滚,不用靠记忆恢复原始配置。

Doris 的资源管理是个越用越有感觉的系统,一开始你可能觉得麻烦,但从“一个查询拖垮集群”的惨痛教训走出来之后,你会明白这些配置和策略,其实都是为集群的稳定运行买的一份长期保险。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询