StarRocks Block Cache Warmup 实战指南:用 CACHE SELECT 主动预热远端数据
2026/9/16 19:36:30 网站建设 项目流程

StarRocks Block Cache Warmup 实战指南:用 CACHE SELECT 主动预热远端数据

【免费下载链接】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

缓存预热(Cache Warmup)是 StarRocks 应对数据湖分析、共享数据集群(shared-data)高要求查询场景的重要能力。本文围绕 StarRocks v3.3 引入的 Block Cache Warmup 特性,系统讲解其原理、CACHE SELECT 语法、四类返回指标、与 SUBMIT TASK 结合的周期调度方案,以及源码级实现细节与使用限制,帮助你在 BI 报表、PoC 性能测试等场景中把远端数据提前"搬到"本地磁盘缓存,显著降低查询延迟。

在数据湖分析和共享数据集群场景中,查询引擎需要从 HDFS 或对象存储等远端存储反复拉取数据,远程 I/O 开销和热点数据重复读取是两大性能瓶颈。Block Cache 把远端文件按块切分后缓存到 BE/CN 节点的本地磁盘,而 Block Cache Warmup 则进一步把"查询时被动填充缓存"升级为"主动预取",让热数据在查询真正到来之前就绪。

从被动填充到主动预热:Block Cache Warmup 的定位

要理解 Block Cache Warmup,先要清楚它与 Block Cache 的关系。Block Cache 是 StarRocks 自 v2.5 引入的磁盘级缓存:当查询首次读取远端数据时,系统将原始文件按固定大小切分成数据块(block),以块为最小缓存单元写入本地磁盘;后续查询命中缓存后直接从本地读取,避免重复访问远端存储。其缓存命中与读取流程可概括为三步:

  1. 系统按缓存键(cache key)检查本地节点 Block Cache 中是否存在目标块;
  2. 命中则直接从本地磁盘读取;
  3. 未命中则从远端存储拉取,并同步写入本地 Block Cache 供后续查询复用。

这里的缓存键由三部分构成:hash(filename) + fileModificationTime + blockId。文件名哈希用于定位文件,修改时间用于感知远端文件是否变化,blockId 则标识文件切分后的第几个块。

从缓存填充方式看,普通 Block Cache 是被动填充——数据在查询过程中被顺带写入缓存;而 Block Cache Warmup 是主动填充——它通过 CACHE SELECT 语句,在查询发生前主动从远端存储抓取目标数据写入缓存。两者互补:被动填充覆盖"已查询过的数据",主动预热覆盖"将要被查询的数据"。

关于 Block Cache 的切分机制、SLRU/LRU 替换策略、Data Cache 的整体架构与 BE 配置项,可参考同一目录下的 Data Cache 文档。

适用场景与前置条件

什么场景值得预热

  • 磁盘容量远大于待预热数据量:如果块缓存磁盘容量小于待预热数据量,预热效果会大打折扣。例如需要预热 100 GB 数据但磁盘只有 50 GB,则只能缓存 50 GB,且后写入的 50 GB 会替换先前缓存的 50 GB,最终可能什么都没留下。
  • 缓存磁盘上的数据访问相对稳定:如果预热期间出现访问量激增,预热效果同样难以保证。例如磁盘 200 GB、待预热 100 GB,条件一满足;但若预热过程中有 150 GB 新数据写入缓存,或一个异常的大冷查询需要装载 150 GB 数据,都可能触发缓存淘汰(eviction),导致已预热的数据被挤出。

换句话说,预热的前提是"有足够空间装下热数据,且空间不会被意外的数据洪峰冲垮"。

使用前必须确认

  • 已启用 Block Cache 特性。Data Cache 自 v3.3.0 起默认开启,由 BE 配置项datacache_enable(默认true)控制总开关;Block Cache 独立开关为block_cache_enable(默认true)。若你曾手动关闭过,需要先恢复启用。
  • 具备目标表的 SELECT 权限。CACHE SELECT 的执行走正常查询链路,权限校验与普通 SELECT 一致。

CACHE SELECT 语法与参数详解

CACHE SELECT 是实现 Block Cache Warmup 的核心语法,完整形式如下:

CACHE SELECT <column_name> [, ...] FROM [<catalog_name>.][<db_name>.]<table_name> [WHERE <boolean_expression>] [PROPERTIES("verbose"="true")]
参数说明
column_name要获取的列,可使用*获取外部表的全部列
catalog_nameCatalog 名称,默认为 DEFAULT_CATALOG;使用SET CATALOG切换后可不指定
db_name数据库名称,切换到目标库后可不指定
table_name要获取数据的表名
boolean_expressionWHERE 中的过滤条件,用于细粒度预热
PROPERTIES目前仅支持verbose属性,用于返回更详细的预热指标

CACHE SELECT 是同步过程,一次只能预热一张表。执行成功后返回预热相关指标。

从语法解析层看,这条语句在 StarRocks.g4 中定义:

CACHE SELECT selectItem (',' selectItem)* FROM qualifiedName (WHERE where=expression)? properties?

它被解析为 DataCacheSelectStatement,内部实际包装了一个InsertStmt——这也解释了为什么预热能"按正常查询流程"执行:CACHE SELECT 本质上是一条特殊的 INSERT 语句(目标为 BLACKHOLE,见下文"实现原理"一节)。

分析器对参数与属性的校验

DataCacheStmtAnalyzer 在分析阶段会完成以下校验与解析:

  • 查询必须为纯表扫描:查询关系必须是TableRelation,否则报错 "Cache select only support olap table, external table or materialized view.";
  • 共享无共享(shared-nothing)模式不支持本地 OLAP 表CACHE SELECT若针对默认内部 Catalog 的表且集群为 shared-nothing 模式,会报错 "Currently cache select is not supported in local olap table";
  • verbose属性:通过Boolean.parseBoolean(properties.getOrDefault("verbose", "false"))解析,默认关闭;
  • priority属性:只能取 0 或 1(默认为 0),用于标记缓存数据的优先级;
  • ttl属性:采用 ISO-8601 时长格式(如P1YPT0M),表示缓存数据保持有效的时间;当priority > 0必须指定非零 TTL,否则报错 "TTL must be specified when priority > 0"。

这些属性校验在仓库单元测试 DataCacheStmtAnalyzerTest.java 中有完整覆盖,例如校验 verbose 大小写不敏感、priority=1必须搭配 TTL、TTL 格式非法时报错等场景。

预热实操:四种典型用法

预热外部表全量数据

下面的例子将 Hive Cataloghive_catalogtest_db.lineitem表的所有数据预热到缓存:

mysql> cache select * from hive_catalog.test_db.lineitem; +-----------------+------------------+----------------------+-------------------+ | READ_CACHE_SIZE | WRITE_CACHE_SIZE | AVG_WRITE_CACHE_TIME | TOTAL_CACHE_USAGE | +-----------------+------------------+----------------------+-------------------+ | 48.2MB | 3.7GB | 59ms | 96.83% | +-----------------+------------------+----------------------+-------------------+ 1 row in set (19.56 sec)

返回字段含义:

  • READ_CACHE_SIZE:所有节点从块缓存中读取的数据总大小;
  • WRITE_CACHE_SIZE:所有节点写入块缓存的数据总大小;
  • AVG_WRITE_CACHE_TIME:每个节点写入块缓存的平均耗时;
  • TOTAL_CACHE_USAGE:本次预热完成后整个集群块缓存的磁盘空间使用率,可用于评估块缓存空间是否充足。

指定列 + 过滤条件细粒度预热

通过指定列与谓词可以实现细粒度预热,显著减少预热数据量,降低磁盘 I/O 与 CPU 消耗:

mysql> cache select l_orderkey from hive_catalog.test_db.lineitem where l_shipdate='1994-10-28'; +-----------------+------------------+----------------------+-------------------+ | READ_CACHE_SIZE | WRITE_CACHE_SIZE | AVG_WRITE_CACHE_TIME | TOTAL_CACHE_USAGE | +-----------------+------------------+----------------------+-------------------+ | 957MB | 713.5MB | 3.6ms | 97.33% | +-----------------+------------------+----------------------+-------------------+ 1 row in set (9.07 sec)

预热共享数据集群中的云原生表(cloud-native table)同理。下面的示例预热ssb库中lineorder表的lo_orderkey列:

mysql> cache select lo_orderkey from ssb.lineorder; +-----------------+------------------+----------------------+-------------------+ | READ_CACHE_SIZE | WRITE_CACHE_SIZE | AVG_WRITE_CACHE_TIME | TOTAL_CACHE_USAGE | +-----------------+------------------+----------------------+-------------------+ | 118MB | 558.9MB | 200.6ms | 4.66% | +-----------------+------------------+----------------------+-------------------+ 1 row in set (29.88 sec)

注意此例中TOTAL_CACHE_USAGE仅为 4.66%,说明缓存空间非常充裕,预热数据可长期驻留,无需担心 SLRU 淘汰。

Verbose 模式:查看每个 BE 的明细指标

默认返回的指标是所有 BE 聚合后的结果。在语句末尾追加PROPERTIES("verbose"="true"),可获取每个 BE 的详细指标:

mysql> cache select * from hive_catalog.test_db.lineitem properties("verbose"="true"); +---------------+-----------------+---------------------+------------------+----------------------+-------------------+ | IP | READ_CACHE_SIZE | AVG_READ_CACHE_TIME | WRITE_CACHE_SIZE | AVG_WRITE_CACHE_TIME | TOTAL_CACHE_USAGE | +---------------+-----------------+---------------------+------------------+----------------------+-------------------+ | 172.26.80.233 | 376MB | 127.8micros | 0B | 0s | 3.85% | | 172.26.80.231 | 272.5MB | 121.8micros | 20.7MB | 146.5micros | 3.91% | | 172.26.80.232 | 355.5MB | 147.7micros | 0B | 0s | 3.91% | +---------------+-----------------+---------------------+------------------+----------------------+-------------------+ 3 rows in set (0.54 sec)

Verbose 模式会额外返回一个指标:

  • AVG_READ_CACHE_TIME:块缓存命中时,每个节点读取数据的平均耗时。

从 DataCacheSelectMetrics.java 的实现可以看到两种输出模式的差异:简单模式将各 BE 的读写字节数取平均、写入耗时按总次数平均后聚合成一行;verbose 模式则按 BE 逐行输出 IP、读写大小、平均读写时间与缓存使用率,其中平均读写时间是readTimeNs / count计算得到的纳秒值再格式化输出。聚合模式下TOTAL_CACHE_USAGE的计算方式是:所有 BE 的(磁盘已用 + 内存已用) / (磁盘配额 + 内存配额)之和的比值。

用 SUBMIT TASK 实现周期调度预热

CACHE SELECT 是一次性的同步操作,配合 SUBMIT TASK 即可实现周期性自动预热。下面的示例每 5 分钟预热一次lineitem表的l_orderkey列:

mysql> submit task always_cache schedule every(interval 5 minute) as cache select l_orderkey from hive_catalog.test_db.lineitem where l_shipdate='1994-10-28'; +--------------+-----------+ | TaskName | Status | +--------------+-----------+ | always_cache | SUBMITTED | +--------------+-----------+ 1 row in set (0.03 sec)

查看已创建的任务

任务提交后,可查询default_catalog.information_schema.tasks查看任务定义与调度信息:

mysql> select * from default_catalog.information_schema.tasks; +--------------+---------------------+-----------------------------------------------------+---------------+------------------------------+---------------------------------------------------------------------+---------------------+------------+ | TASK_NAME | CREATE_TIME | SCHEDULE | CATALOG | DATABASE | DEFINITION | EXPIRE_TIME | PROPERTIES | +--------------+---------------------+-----------------------------------------------------+---------------+------------------------------+---------------------------------------------------------------------+---------------------+------------+ | always_cache | 2024-04-11 16:01:00 | PERIODICAL START(2024-04-11T16:01) EVERY(5 MINUTES) | emr_hive_test | zz_tpch_sf1000_hive_orc_zlib | cache select l_orderkey from lineitem where l_shipdate='1994-10-28' | NULL | | +--------------+---------------------+-----------------------------------------------------+---------------+------------------------------+---------------------------------------------------------------------+---------------------+------------+ 1 row in set (0.21 sec)

查看任务执行历史

查询default_catalog.information_schema.task_runs可查看每次预热执行的明细,其中EXTRA_MESSAGE字段记录着 CACHE SELECT 的指标:

mysql> select * from default_catalog.information_schema.task_runs; +--------------------------------------+--------------+---------------------+---------------------+---------+---------------+------------------------------+---------------------------------------------------------------------+---------------------+------------+---------------+----------+------------------------------------------------------------------------------------------------------------------------+------------+ | QUERY_ID | TASK_NAME | CREATE_TIME | FINISH_TIME | STATE | CATALOG | DATABASE | DEFINITION | EXPIRE_TIME | ERROR_CODE | ERROR_MESSAGE | PROGRESS | EXTRA_MESSAGE | PROPERTIES | +--------------------------------------+--------------+---------------------+---------------------+---------+---------------+------------------------------+---------------------------------------------------------------------+---------------------+------------+---------------+----------+------------------------------------------------------------------------------------------------------------------------+------------+ | 55b30204-f7da-11ee-b03e-7ea526d0b618 | always_cache | 2024-04-11 16:06:00 | 2024-04-11 16:07:22 | SUCCESS | emr_hive_test | zz_tpch_sf1000_hive_orc_zlib | cache select l_orderkey from lineitem where l_shipdate='1994-10-28' | 2024-04-12 16:06:00 | 0 | NULL | 100% | AlreadyCachedSize: 15.7GB, AvgReadCacheTime: 1ms, WriteCacheSize: 0B, AvgWriteCacheTime: 0s, TotalCacheUsage: 75.94% | | | a2e3dc7e-f7d9-11ee-b03e-7ea526d0b618 | always_cache | 2024-04-11 16:01:00 | 2024-04-11 16:02:39 | SUCCESS | emr_hive_test | zz_tpch_sf1000_hive_orc_zlib | cache select l_orderkey from lineitem where l_shipdate='1994-10-28' | 2024-04-12 16:01:00 | 0 | NULL | 100% | AlreadyCachedSize: 15.7GB, AvgReadCacheTime: 1.2ms, WriteCacheSize: 0B, AvgWriteCacheTime: 0s, TotalCacheUsage: 75.87% | | +--------------------------------------+--------------+---------------------+---------------------+---------+---------------+------------------------------+---------------------------------------------------------------------+---------------------+------------+---------------+----------+------------------------------------------------------------------------------------------------------------------------+------------+ 2 rows in set (0.04 sec)

注意上例中第二次执行WriteCacheSize: 0BAlreadyCachedSize: 15.7GB,说明该表数据此前已全部预热,本次任务仅做了命中验证,未产生新的写入——这正是周期调度预热场景中常见的"缓存已就绪"状态。

删除任务

不再需要周期预热时,使用 DROP TASK 删除:

DROP TASK <task_name>

调度任务的实现路径

从源码结构看,周期调度下的 CACHE SELECT 由 DataCacheSelectProcessor 处理:它作为BaseTaskRunProcessor的子类,在任务运行时通过ctx.executeSql(context.getDefinition())重新执行 CACHE SELECT 语句,从子执行器(sub StmtExecutor)的 Coordinator 中取回预热指标,写回任务状态EXTRA_MESSAGE,并调用updateBackendDataCacheMetrics刷新各节点的缓存用量指标。这就是task_runs.EXTRA_MESSAGE中能看到完整预热指标的原因。

典型业务场景

  1. PoC 性能测试:评估 StarRocks 性能时,如果不想让外部存储系统的网络延迟干扰测试结果,可先用 CACHE SELECT 把待测表数据全部装入块缓存,再进行基准查询。这样测得的查询性能即为纯本地缓存命中下的表现。

  2. 固定时点的 BI 报表:业务团队每天早晨 8 点查看 BI 报表。为保证查询性能相对稳定,可在每天 7 点调度一个预热任务,将报表涉及的数据提前装好:

    mysql> submit task BI schedule START('2024-02-03 07:00:00') EVERY(interval 1 day) AS cache select * from hive_catalog.test_db.lineitem where l_shipdate='1994-10-28'; +--------------+-----------+ | TaskName | Status | +--------------+-----------+ | BI | SUBMITTED | +--------------+-----------+ 1 row in set (0.03 sec)
  3. 最小化资源消耗的预热:为减少预热对常规查询的影响,可在 SUBMIT TASK 中通过 session 变量控制资源占用,例如指定资源组、调整并行度(DOP)、用 WHERE 缩小预热范围:

    mysql> submit task cache_select properties("pipeline_dop"="1", "resource_group"="warmup") schedule EVERY(interval 1 day) AS cache select * from hive_catalog.test_db.lineitem where l_shipdate>='1994-10-28'; +--------------+-----------+ | TaskName | Status | +--------------+-----------+ | cache_select | SUBMITTED | +--------------+-----------+ 1 row in set (0.03 sec)

实现原理:CACHE SELECT 底层是如何工作的

深入 DataCacheSelectExecutor.java 可以看到 CACHE SELECT 的执行骨架:

  • CACHE SELECT 语句在 AST 层包装了一个InsertStmt(目标为 BLACKHOLE),即它本质上是"INSERT INTO BLACKHOLE() SELECT ...",因此走的是完整查询执行链路,预热开销与普通查询相当;
  • 执行器会按 warehouse 下可用的计算资源(Compute Resource)拆分出多个子执行上下文(sub ConnectContext),逐一创建内部StmtExecutor执行同一个 INSERT 语句,再聚合各子执行器的指标;
  • 关键的一点是,buildCacheSelectConnectContext 在克隆会话变量时强制设置了与缓存相关的参数,保证预热必然写入缓存:
    • setEnableScanDataCache(true)setEnablePopulateDataCache(true):强制开启扫描缓存与缓存填充;
    • setDataCachePopulateMode(ALWAYS):填充模式固定为"始终填充",确保所有被访问的数据都必须写入缓存;
    • setEnableDataCacheAsyncPopulateMode(false):关闭异步填充,采用同步填充保证一次预热完成全部写入;
    • setEnableDataCacheIOAdaptor(false):关闭 I/O 适配器,避免磁盘高负载时部分请求被路由回远端存储而漏缓存;
    • setDataCacheEvictProbability(100)与可选的priorityttl:控制缓存写入的淘汰概率、优先级与有效期。

这解释了为什么 CACHE SELECT 与普通查询行为不同:普通 SELECT 会受populate_datacache_mode等会话变量影响决定是否填充缓存,而 CACHE SELECT 无条件强制执行填充。

使用限制与注意事项

  • 使用 CACHE SELECT 前必须启用 Block Cache 特性,且对目标表拥有SELECT 权限
  • CACHE SELECT只支持单表预热,不支持 ORDER BY、LIMIT、GROUP BY 等操作符——分析器要求查询关系必须是对单张表的直接扫描(TableRelation)。
  • CACHE SELECT 在shared-nothing 与 shared-data 集群中均可使用;但 shared-nothing 模式下仅支持外部表(本地 OLAP 表会被拒绝),共享数据集群中可预热云原生表。
  • 可预热的远端文件格式包括TEXT、ORC、Parquet
  • 已预热的数据不保证永久驻留:仍可能依据 Block Cache 的 SLRU 规则被淘汰。
    • 数据湖用户可通过SHOW BACKENDS\GSHOW COMPUTE NODES\G查看块缓存剩余容量,评估 SLRU 淘汰风险;
    • 共享数据集群用户可通过集群指标查看块缓存使用情况。
  • 当前 CACHE SELECT 的实现基于 INSERT INTO BLACKHOLE(),走正常查询流程,因此性能开销与普通查询相当。官方说明未来版本会优化性能。

后续版本展望

官方文档指出,未来 StarRocks 将引入自适应 Block Cache Warmup(adaptive Block Cache Warmup),结合数据访问模式与缓存命中情况动态调整预热策略,以进一步提升缓存命中率。当前版本下,建议你结合上文的磁盘容量评估、细粒度列/谓词筛选与周期调度手段,把预热成本与收益控制在合理范围内。

【免费下载链接】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),仅供参考

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

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

立即咨询