Broker Load 性能优化实战
适用人群:数据开发初学者、初级数据工程师、刚接触 MPP 数据库导入的同学
文章目标:把 Broker Load 的性能优化讲清楚,尤其是“指定分区导入”“为什么不建议并行写同一张表”“多批次大文件写单表如何稳又快”
版本说明:
- StarRocks:4.0.2(本文所有 StarRocks 示例以 4.0.2 为基准)
- Apache Doris:2.x(用于对比思路,具体参数以 Doris 对应版本文档为准)
- 示例说明:本文 SQL / 路径 / 表名均为独立示例,不引用任何现有业务项目文件
1. 先用一句话讲明白:什么是 Broker Load?
Broker Load是一种异步批量导入方式:你提交一个LOAD作业后,系统后台执行,前台可以继续做别的事。
它常用于从 HDFS、对象存储(S3/OSS/OBS/GCS/Azure)等外部存储,把大批量离线文件导入到 StarRocks / Doris 表中。
你可以把它理解成:
INSERT INTO:更像“即时写入”Broker Load:更像“提交一个离线批处理任务”
2. 必懂术语(新手建议先看)
2.1 MPP
MPP (Massively Parallel Processing):大规模并行处理架构。
简单说就是把任务拆分给多个节点同时做,适合大数据分析和批量加载。
2.2 Label
Label是一次导入任务的“唯一名字”(在同一数据库里唯一)。
它有两个核心价值:
- 跟踪任务状态(成功/失败/取消)
- 防止重复导入(实现“幂等”或接近 Exactly-Once 语义)
2.3 分区(Partition)
分区是把一张大表按时间或维度切成多个逻辑分片(如按天dt=2026-04-16)。
导入指定分区可以显著降低扫描范围和写入干扰。
2.4 并发导入
同时跑多个Broker Load任务就是并发导入。
并发不是越大越好,过高并发会造成:
- FE/BE 任务调度压力增大
- compaction(数据合并)压力增加
- 导致吞吐下降甚至任务失败
3. Broker Load 基础语法(StarRocks 4.0.2)
LOADLABEL db_name.label_name(DATAINFILE("s3://bucket/path/file1.parquet","s3://bucket/path/file2.parquet")INTOTABLEtarget_tablePARTITION(p20260416)FORMATAS"parquet")WITHBROKER("aws.s3.access_key"="xxx","aws.s3.secret_key"="yyy","aws.s3.region"="ap-southeast-1")PROPERTIES("timeout"="7200","max_filter_ratio"="0.01");常见监控方式(StarRocks 4.0.2):
SELECT*FROMinformation_schema.loadsWHERElabel='label_name'ORDERBYcreate_timeDESC;4. 性能优化总原则(先记住这 6 条)
- 优先按分区导入,避免“全表无差别写入”。
- 控制单任务文件数与文件大小,避免“超碎小文件”或“超大单文件”。
- 不要盲目并发写同一张表,尤其是同分区并发。
- 用多批次顺序导入大文件集合,比一把梭并发更稳定。
- 监控导入状态 + 错误行 + 失败原因,快速闭环。
- 围绕“吞吐、稳定、可回滚”平衡调优,不是只追求峰值速度。
4.1 4.0.2 版本下的实践提醒
- 语法和 3.x 主体一致,但上线前仍要在 4.0.2 环境做一次端到端压测。
- 导入监控建议统一走
information_schema.loads,并配合 FE/BE 资源监控看瓶颈。 - 调优优先级不变:先分区、再批次、最后微调并发和参数。
4.2 核心瓶颈:ScanRows与SinkRows怎么看、怎么优化
很多团队把 Broker Load 调优做成“调并发玄学”,其实真正核心是两段:
- 扫描阶段(Scan):从外部存储读取并解析文件,核心指标是
ScanRows。 - 写入阶段(Sink):把处理后的数据写入 StarRocks 表,核心指标是
SinkRows。
可以先记住一句话:
Scan 慢,就优化“读和解析”;Sink 慢,就优化“写入路径和表设计”。
A. 先判断瓶颈在哪一段
建议每次导入都做两类观察:
- 作业结果层(是否成功、总耗时、错误信息):
information_schema.loads。 - 执行细节层(Scan/Sink 哪段耗时高):导入作业的 Profile / Tracking 信息。
实操上,如果你发现:
ScanRows增长慢、读取耗时长:通常是扫描瓶颈。SinkRows推进慢、写入阶段长尾:通常是写入瓶颈。ScanRows很高但SinkRows明显偏低:通常伴随过滤/脏数据/表达式转换开销。
B. 扫描瓶颈(ScanRows)优化清单
优先列式格式
优先使用Parquet / ORC,通常比 CSV 文本解析更省 CPU。
如果是 CSV,尽量避免高压缩比且不可切分的压缩格式导致单线程读取热点。控制文件粒度,减少极端文件分布
避免“海量小文件”(元数据与打开文件开销大),也避免“超大单文件”(并行度不够)。
建议把文件整理为中等粒度(常见为数百 MB ~ 1 GB,再按集群压测微调)。减少导入时重计算
SET里的复杂表达式、过多字段转换、复杂WHERE过滤都会增加扫描阶段 CPU。
能前置到离线 ETL 的计算,尽量前置。优化对象存储读取链路
确认 BE 到对象存储网络稳定、带宽充足;跨地域读取会显著拉低ScanRows/s。
尽量把计算集群与数据存储放在同地域或低延迟网络。
C. 写入瓶颈(SinkRows)优化清单
避免并行写同一张表同一分区
这是最常见写入瓶颈放大器。并发写同分区会让写入与 compaction 竞争更重。按分区分批提交,降低单事务体量
单批过大时,写入、发布、后续合并都会拖慢。
实践上用“多批次顺序提交 + 小并发”通常更稳。校验分桶与数据分布是否合理
分桶过少会限制并行写入;分桶过多又会带来管理和合并压力。
目标是让写入并行度与 BE 资源匹配,而不是盲目增桶。关注 compaction 压力
当导入频繁、批次碎片化时,后台 compaction 堆积会拖慢后续SinkRows。
出现“越导越慢”时,优先检查 compaction 与磁盘 IO,而不是先加并发。
D. 一套新手可执行的 4 步调优法
- 固定同一批数据,先用“单任务”跑基线,记录总耗时。
- 对比 Scan/Sink 耗时占比,先优化占比更高的一段。
- 每次只改一个变量(文件粒度、批次大小、并发数三选一),重复压测。
- 选“吞吐更高且失败率稳定”的参数作为生产默认值。
E. 经验结论(非常实用)
- 当瓶颈在
ScanRows:优先改文件格式、文件粒度、网络链路、转换复杂度。 - 当瓶颈在
SinkRows:优先改分区批次策略、同表并发、分桶与 compaction 压力。 - 真正有效的优化,不是单点提速,而是让 Scan 和 Sink 两段都不“卡脖子”。
5. 场景一:把数据加载到指定分区(强烈推荐)
为什么更快?
- 只写目标分区,减少不必要的数据路由和元数据处理。
- 降低对历史分区的干扰,减少 compaction 冲突概率。
- 回溯和重跑更可控(按分区重导入)。
实战模板(按天分区)
LOADLABEL dwd.load_order_20260416_01(DATAINFILE("s3://warehouse/order/dt=2026-04-16/*.parquet")INTOTABLEdwd_orderPARTITION(p20260416)FORMATAS"parquet")WITHBROKER("aws.s3.access_key"="${ak}","aws.s3.secret_key"="${sk}","aws.s3.region"="ap-southeast-1")PROPERTIES("timeout"="10800","max_filter_ratio"="0.001");新手避坑
- 分区名要和表定义一致(不是随便写字符串)。
- 文件路径里
dt=...和分区值要一致,避免“逻辑错分区”。 - 避免一次任务跨太多分区,建议按批次拆开。
6. 场景二:为什么“不建议并行写单表”(尤其同分区)?
很多同学第一反应是:开更多并发就更快。
在 Broker Load 场景里,这经常是错的,原因如下:
写放大与合并压力
并行任务越多,底层生成的数据片段越多,后续 compaction 更重。资源竞争
多个任务同时抢 BE 的 CPU、内存、IO、网络,最终每个任务都变慢。元数据与事务负载
高并发导入会增加 FE 端事务和调度压力,失败率可能升高。同分区并发冲突风险更高
同一分区被多任务同时写入,更容易触发性能抖动和尾延迟。
更好的做法
- 对同一张大表:小并发(如 1~3)+ 分批次 + 分区隔离。
- 对不同表/不同分区:可适度提高并发。
- 先压测得到“平台甜点值”(吞吐最高且失败率可接受的并发)。
7. 场景三:多批次大文件写入单表(重点)
这是最常见的生产场景:每天数百 GB 到数 TB 文件,要导入同一事实表。
7.1 推荐策略:分批次顺序提交(而不是全量并发)
步骤建议
- 按分区切批(例如按
dt),每批一个或少量分区。 - 每批再按文件量切块(例如每批 50~200 个文件,视集群能力调整)。
- 同时运行 1~3 个 load 任务,观察 BE 负载后再调。
- 每批完成后校验行数,再进下一批。
- 异常批次用相同 label 重试策略(结合业务幂等设计)。
为什么有效?
- 控制单次事务体量,降低失败重试成本。
- 降低 compaction 峰值压力,系统更稳。
- 出问题容易定位(知道是第几批、第几个分区)。
7.2 文件大小建议(经验值)
- 避免大量超小文件(例如 KB~几 MB)
- 也避免单文件过大(例如 50+ GB 单文件)
- 常见实践是把文件整理到“中等粒度”(比如几百 MB 到 1 GB 量级)再导入
注:最佳值受网络、对象存储吞吐、BE 磁盘与 CPU 影响,必须压测确认。
8. 关键参数怎么理解(新手版)
timeout
单次导入任务超时时间。大文件批量导入必须适当拉长,避免误超时。
max_filter_ratio
允许脏数据(过滤行)占比。
例如设0.01表示最多允许 1% 错误行。新手不建议一开始设太大,否则会掩盖数据质量问题。
label
用于任务幂等和追踪。
建议命名规范:表名_分区_批次_时间戳,如dwd_order_20260416_b03_20260416103000。
9. 生产级落地方案(可直接照搬)
9.1 导入流程(StarRocks 4.0.2 基线)
- 预处理文件:合并小文件、校验格式。
- 生成批次清单:按分区 + 文件数切批。
- 提交 Broker Load:控制并发,不要全开。
- 轮询状态:
information_schema.loads(StarRocks 4.0.2)。 - 校验结果:行数、分区数据量、错误日志。
- 失败重试:优先重试失败批,不影响成功批次。
9.2 可观测性指标
- 单批耗时(P50/P95)
- 单批吞吐(MB/s 或 rows/s)
- 失败率与重试率
- compaction 排队/耗时
- FE/BE CPU、内存、磁盘 IO、网络带宽
9.3 4.0.2 可直接复用的“多批次单表示例”
下面示例演示“单表 + 指定分区 + 多批次顺序提交”的标准写法(示意):
-- Batch 1: 先导入 2026-04-01 分区LOADLABEL demo_db.fact_order_p20260401_b01(DATAINFILE("s3://demo-bucket/fact_order/dt=2026-04-01/part-*.parquet")INTOTABLEfact_orderPARTITION(p20260401)FORMATAS"parquet")WITHBROKER("aws.s3.access_key"="your_ak","aws.s3.secret_key"="your_sk","aws.s3.region"="ap-southeast-1")PROPERTIES("timeout"="14400","max_filter_ratio"="0.001");-- Batch 2: Batch 1 完成并校验后,再导入下一批LOADLABEL demo_db.fact_order_p20260401_b02(DATAINFILE("s3://demo-bucket/fact_order/dt=2026-04-01/part2-*.parquet")INTOTABLEfact_orderPARTITION(p20260401)FORMATAS"parquet")WITHBROKER("aws.s3.access_key"="your_ak","aws.s3.secret_key"="your_sk","aws.s3.region"="ap-southeast-1")PROPERTIES("timeout"="14400","max_filter_ratio"="0.001");配套查询(建议每批都查):
SELECTlabel,state,progress,create_time,finish_timeFROMinformation_schema.loadsWHEREdb_name='demo_db'ANDlabelLIKE'fact_order_p20260401_%'ORDERBYcreate_timeDESC;10. StarRocks 4.0.2 与 Doris 的实践差异(怎么理解)
二者在 Broker Load 的核心思想高度一致:
- 都是异步批量导入
- 都依赖外部存储访问与后台任务执行
- 都需要用“分区 + 批次 + 并发控制”做性能优化
差异主要在于:
- 部分参数名和默认值可能不同
- 系统视图、监控项、报错文案可能不同
- 某些版本功能细节(例如信息_schema 可观测能力)存在差异
建议:先在目标版本做小规模压测,再固化你自己的“标准导入模板”。
11. 常见问题 FAQ
Q1:并发从 2 提到 10,为什么反而更慢?
因为你的瓶颈可能在 BE IO、对象存储吞吐或 compaction,不在“任务数量”。并发过高只会放大竞争。
Q2:一次导入跨很多分区可以吗?
可以,但不建议太大批。分区太多会让任务复杂度上升,失败回滚和问题定位成本更高。
Q3:如何做到“可重复执行不重复入库”?
使用规范化label+ 分批次导入 + 失败批重试机制,并在业务侧做幂等校验。
Q4:什么时候考虑改用其他导入方式?
如果你是实时高频写入,优先考虑流式导入(如 Routine Load / Stream Load);Broker Load更适合离线批量。
12. 结语
对 Broker Load 来说,稳定吞吐 > 峰值吞吐。
最实用的优化路线不是“参数玄学”,而是这三件事:
- 分区化导入
- 批次化执行
- 并发可控
只要这三点做对,StarRocks / Doris 在大文件离线导入场景里通常都能做到“快、稳、可运维”。
参考文档
- StarRocks 官方文档(Broker Load):https://docs.starrocks.io/zh/docs/sql-reference/sql-statements/loading_unloading/BROKER_LOAD
- Apache Doris 官方文档(建议对照你线上版本):https://doris.apache.org/zh-CN/docs/