news 2026/9/16 14:01:40

StarRocks 中间结果落盘(Spill to Disk)实战指南:从本地磁盘到对象存储的内存保护方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
StarRocks 中间结果落盘(Spill to Disk)实战指南:从本地磁盘到对象存储的内存保护方案

StarRocks 中间结果落盘(Spill to Disk)实战指南:从本地磁盘到对象存储的内存保护方案

【免费下载链接】starrocksThe world's fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocks

本文是一份针对 StarRocks 的中间结果落盘(intermediate result spilling)技术指南。当聚合(Aggregate)、排序(Sort)、Hash Join 等内存密集型算子在超大数据集上执行时,StarRocks 可能因内存耗尽(OOM)而强制终止查询;落盘功能允许将这些算子的中间结果暂存到本地磁盘或对象存储,用可接受的性能损耗换取内存占用的大幅下降。读完本文,你将掌握spill_local_storage_dir等 BE/CN 配置项的设置、enable_spillspill_mode会话变量的完整用法、对象存储落盘的开启方式,以及落盘功能的边界与限制。

概述:为什么需要中间结果落盘

StarRocks 是典型的依赖内存计算执行查询的数据库系统。当针对大数据集执行包含聚合(aggregate)、排序(sort)、连接(join)算子的查询时,内存资源的消耗会非常可观。一旦达到内存上限,这些查询会被强制终止,即发生 OOM。

然而,在实际运维中,仍有一些场景希望某些内存密集型任务稳定完成,而对性能不是首要诉求,例如:

  • 构建物化视图(materialized view);
  • 执行轻量级 ETL(例如INSERT INTO SELECT语句)。

这类任务很容易耗尽集群内存资源,从而阻塞集群中其他正在运行的查询。传统上,只能逐一对这些任务进行调优,并依赖资源隔离策略(如资源组 Resource Group)控制查询并发度,这在某些极端场景下既不方便,也容易失败。

从 StarRocks v3.0.1 起,StarRocks 支持将部分内存密集型算子的中间结果落盘(spill)。借助这一能力,可以"用可接受的性能下降,换取内存占用的大幅削减",从而显著提升系统可用性。

从源码结构看,该能力在 BE 侧由 compute_env/spill 目录下的一整套落盘组件支撑,包括块管理(block_manager.hfile_block_manager.hlog_block_manager.hhybird_block_manager.h)、目录管理(dir_manager.h)、数据流(data_stream.h)、序列化(serde.h)、内存表(mem_table.h)以及查询级落盘管理器(query_spill_manager.h)等;FE 侧则由 SessionVariable.java 中的一系列会话变量控制开关与行为。

支持落盘的算子

目前,StarRocks 的落盘功能支持以下算子:

  • 聚合算子(Aggregate)
  • 排序算子(Sort)
  • Hash Join 算子(LEFT JOIN、RIGHT JOIN、FULL JOIN、OUTER JOIN、SEMI JOIN、INNER JOIN)
  • CTE 算子(自 v3.3.4 起支持)

对应的可落盘算子类型定义在 InternalService.thrift 的TSpillableOperatorType枚举中(HASH_JOIN = 0AGG = 1AGG_DISTINCT = 2SORT等)。FE 侧的spillable_operator_mask会话变量(默认-1,表示所有算子均可落盘)通过位掩码按算子类型控制落盘是否生效,其注释说明目前仅最低 4 位有意义,分别对应 HASH_JOIN、AGG、AGG_DISTINCT 和 SORT(参见 SessionVariable.java)。

启用中间结果落盘

启用中间结果落盘分为三步:配置落盘目录(BE 静态配置)、开启落盘开关(会话变量)、设置落盘模式(会话变量)。

步骤一:配置本地落盘目录spill_local_storage_dir

在 BE 配置文件be.conf或 CN 配置文件cn.conf中指定本地落盘目录,然后重启集群使修改生效:

spill_local_storage_dir=/<dir_1>[;/<dir_2>]

要点:

  • 可以通过分号(;)分隔,同时指定多个spill_local_storage_dir,实现跨多块磁盘的负载分担。
  • 生产环境强烈建议为数据存储和落盘使用不同的磁盘。当中间结果落盘时,写入负载和磁盘占用都可能显著上升;若与数据共用同一块盘,这种突增可能影响集群中其他查询或任务的运行。

从配置源码看,该配置项定义于 config.h:CONF_String(spill_local_storage_dir, "${STARROCKS_HOME}/spill"),默认目录为${STARROCKS_HOME}/spill。围绕目录与磁盘使用,仓库中还提供了一批可选的调优参数(同样位于 config.h):

BE/CN 配置项默认值说明
spill_local_storage_dir${STARROCKS_HOME}/spill本地落盘目录,可配置多个,用分号分隔
spill_max_dir_bytes_ratio0.8(80%)单个落盘目录的最大使用比例;当已用空间超过该比例时,落盘将返回错误(当落盘目录与存储目录重合时尤其重要)
spill_max_partition_level7落盘分区最大层级(需保证2^spill_max_partition_level < spill_max_partition_size
spill_max_partition_size1024落盘分区最大大小
spill_init_partition16落盘初始分区数
spill_max_log_block_container_bytes10737418240(10GB)单个日志块容器文件的最大尺寸(非硬限制,超出会新建文件)
spill_read_buffer_min_bytes1048576落盘读缓冲的最小字节数,小于该值将禁用缓冲读
experimental_spill_skip_synctrue发生落盘时是否跳过同步刷盘
enable_spill_sort_eventsfalse是否将可落盘排序算子调度到管道事件调度器而非忙轮询

注意:以上参数属于内部实现细节,日常使用只需关注spill_local_storage_dir;其余参数在官方文档未展开说明前,建议保持默认值,仅在排查性能/容量问题时结合源码评估。

步骤二:开启落盘开关enable_spill

执行以下语句开启中间结果落盘:

SET enable_spill = true;

步骤三:设置落盘模式spill_mode

执行以下语句配置落盘执行模式:

SET spill_mode = { "auto" | "force" };

两个会话变量的含义与默认值如下:

变量默认值说明
enable_spillfalse是否启用中间结果落盘。设为true后,StarRocks 在处理查询中的聚合、排序或连接算子时,会将中间结果落盘以减少内存占用。
spill_modeauto中间结果落盘的执行模式。合法取值:
  • auto:当内存使用达到阈值时,自动触发落盘。
  • force:无论内存使用情况如何,对所有相关算子强制执行落盘。
该变量仅在enable_spill设为true时生效。

说明:每次涉及落盘的查询完成后,StarRocks 会自动清理该查询产生的落盘数据。如果 BE 在清理前崩溃,StarRocks 会在 BE 重启时清理残留数据。

从 FE 源码可以确认上述默认值:SessionVariable.java 中enableSpill默认false(L1756-1757)、spillMode默认字符串"auto"(L1780-1781),且二者均通过@VariableMgr.VarAttr暴露为可动态设置的会话变量,因此无需重启 FE/BE 即可通过SET语句即时生效——这与spill_local_storage_dir必须重启集群才能生效形成了鲜明对比。

[预览] 将中间结果落盘到对象存储

v3.3.0起,StarRocks 支持将中间结果落盘到对象存储。

:::tip 在启用对象存储落盘之前,必须先创建一个存储卷(storage volume)以定义要使用的对象存储。创建存储卷的详细说明,参见 CREATE STORAGE VOLUME。 :::

完成上一节的落盘启用步骤后,进一步设置以下系统变量,即可让中间结果落盘到对象存储:

SET enable_spill_to_remote_storage = true; -- 将 <storage_volume_name> 替换为你要使用的存储卷名称 SET spill_storage_volume = '<storage_volume_name>';

开启对象存储落盘后,触发落盘的查询所产生的中间结果会首先存储在 BE 或 CN 节点的本地磁盘当本地磁盘容量达到限制后,再写入对象存储。

请注意:如果你为spill_storage_volume指定的存储卷不存在,则不会启用对象存储落盘。

从 BE 源码可以印证这一"本地优先、远端兜底"的实现策略:在 query_spill_manager.cpp 的init_block_manager中,当enable_spill_to_remote_storage开启时,会构建一个HyBirdBlockManager,它同时持有一个基于LogBlockManager的本地块管理器和一个基于FileBlockManager的远端块管理器,从而支持数据先写本地、容量受限后写对象存储的混合模式;若进一步设置disable_spill_to_local_disk(FE 侧存在该会话变量,见 SessionVariable.java),则直接使用远端块管理器、完全绕过本地磁盘。远端文件系统的创建经由FileSystemFactory::CreateUniqueFromString依据存储卷配置完成。

相关会话变量速查

FE 侧围绕落盘还提供了若干与本文主题相关的会话变量(位于 SessionVariable.java):

会话变量默认值说明
enable_spillfalse落盘总开关
spill_modeauto落盘模式:auto/force
enable_spill_to_remote_storagefalse是否允许落盘到对象存储
disable_spill_to_local_diskfalse是否禁用本地磁盘落盘(开启后仅落盘到对象存储)
spill_storage_volume空字符串指定用于对象存储落盘的存储卷名称
spillable_operator_mask-1(全部算子)以位掩码控制哪些算子可以落盘(HASH_JOIN / AGG / AGG_DISTINCT / SORT),默认所有算子均可
spill_operator_max_bytes单个算子触发落盘的内存上限
spill_revocable_max_bytes可回收(revocable)内存上限
spill_enable_compaction是否启用落盘文件的压缩合并
spill_enable_direct_iofalse是否启用直接 I/O 读写

其中spillable_operator_maskenable_spill_buffer_readspill_partitionwise_agg等标注为INVISIBLE的变量主要供内部与测试使用,生产环境不建议手动调整。

物化视图刷新中的落盘应用

落盘功能在构建物化视图这一典型场景中已得到原生集成。FE 的 MVRefreshProcessor.java 中实现了如下逻辑:当Config.enable_materialized_view_spill开启、且用户既未显式设置session.enable_spill会话变量、也未在物化视图属性中配置session.enable_spill时,物化视图刷新会自动将enable_spill置为true。这意味着在默认配置下,重型物化视图刷新任务会自动受益于落盘机制,避免因内存不足导致刷新失败或拖垮集群。

限制与注意事项

在使用落盘功能时,需要清楚以下边界:

  • 并非所有 OOM 问题都能靠落盘解决。例如,StarRocks 无法释放表达式求值(expression evaluation)所占用的内存。
  • 涉及落盘的查询通常会有约一个数量级(十倍)的查询延迟增加。建议通过设置会话变量query_timeout为这些查询延长查询超时时间。
  • 落盘到对象存储的性能下降相比落盘到本地磁盘更为显著
  • 每个 BE 或 CN 节点的spill_local_storage_dir由该节点上运行的所有查询共享。目前 StarRocks 不支持为单个查询单独设置落盘数据的大小上限。因此,并发执行涉及落盘的查询时,彼此之间可能相互影响(例如某节点上落盘数据量过大会挤占其他查询的落盘空间)。

小结

中间结果落盘是 StarRocks 在内存计算与稳定性之间提供的关键权衡机制:它允许聚合、排序、Hash Join、CTE 等内存密集型算子在大数据集上以性能换内存,显著降低 OOM 风险,尤其适合物化视图构建与INSERT INTO SELECT这类轻量 ETL 场景。启用路径清晰——静态配置spill_local_storage_dir后,通过SET enable_spill = trueSET spill_mode = 'auto'/'force'即可动态控制;自 v3.3.0 起还可借助存储卷将中间结果进一步溢写至对象存储,实现本地与远端的混合落盘。在部署使用时,务必结合"不同盘存放数据与落盘、延长query_timeout、控制并发落盘查询"等最佳实践,并接受十倍量级的延迟代价与表达式求值内存不可释放的局限。

延伸阅读

  • CREATE STORAGE VOLUME:创建存储卷以支持对象存储落盘
  • ALTER STORAGE VOLUME / SHOW STORAGE VOLUMES:管理存储卷
  • BE 落盘实现:compute_env/spill(含块管理、目录管理、序列化、数据流等核心组件)
  • BE 落盘配置定义:config.h
  • FE 落盘会话变量定义:SessionVariable.java
  • 物化视图刷新自动启用落盘:MVRefreshProcessor.java
  • 可落盘算子类型定义:InternalService.thrift

【免费下载链接】starrocksThe world's fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocks

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 13:57:57

MATLAB数值优化源码解析:共轭梯度法与罚函数实现

简介&#xff1a;面向MATLAB优化算法学习与研究者的实用源码包&#xff0c;覆盖梯度法、内点法、外点法、罚函数及线性梯度法等经典约束与无约束优化方法。全部程序为可直接运行的.m脚本&#xff0c;用户只需在命令窗口按提示输入参数即可得到结果&#xff0c;免去重复编写调试…

作者头像 李华
网站建设 2026/9/16 13:56:23

51单片机温室闭环控制系统:ADC0832多传感器采集与LCD动态显示

简介&#xff1a;本资源是一套面向电子类专业学生与单片机初学者的温室环境自动监控系统完整开发套件&#xff0c;聚焦农业物联网场景下的多参数采集与闭环控制实践。项目以STC89C52等51系列单片机为核心&#xff0c;集成DHT11温湿度、ADC0832光照、二氧化碳传感器数据采集模块…

作者头像 李华
网站建设 2026/9/16 13:54:11

Django在线考试系统:从模型设计到部署的完整实战解析

简介&#xff1a;面向计算机相关专业学生的Django在线考试系统毕业设计源码包&#xff0c;基于Python与MySQL实现&#xff0c;个人项目评审得分97分&#xff0c;经过严格调试确保可直接运行。这套系统覆盖用户登录、试题管理、在线答题、成绩统计等典型考试模块&#xff0c;适合…

作者头像 李华
网站建设 2026/9/16 13:53:43

非线性模型预测控制在双电机电动汽车扭矩分配中的Simulink实现

简介&#xff1a;这份资源围绕双电机电池电动汽车的扭矩分配问题&#xff0c;提供一套基于非线性模型预测控制&#xff08;NMPC&#xff09;的Simulink实现方案&#xff0c;适合车辆控制、能量管理方向的研究者与工程师参考。包内共27个文件&#xff0c;包含Simulink整车/电气架…

作者头像 李华