跳到主要内容
版本:Candidate-3.3

Data Cache

本文介绍 Data Cache 的原理,以及如何开启 Data Cache 加速外部数据查询。

在数据湖分析场景中,StarRocks 作为 OLAP 查询引擎需要扫描 HDFS 或对象存储(下文简称为“外部存储系统”)上的数据文件。查询实际读取的文件数量越多,I/O 开销也就越大。此外,在即席查询 (ad-hoc) 场景中,如果频繁访问相同数据,还会带来重复的 I/O 开销。

为了进一步提升该场景下的查询性能,StarRocks 2.5 版本开始提供 Data Cache 功能。通过将外部存储系统的原始数据按照一定策略切分成多个 block 后,缓存至 StarRocks 的本地 BE 节点,从而避免重复的远端数据拉取开销,实现热点数据查询分析性能的进一步提升。Data Cache 仅在使用外部表(不含 JDBC 外部表)和使用 External Catalog 查询外部存储系统中的数据时生效,在查询 StarRocks 原生表时不生效。

原理

StarRocks 将远端存储文件缓存至本地 BE 节点时,会将原始文件按照一定策略切分为相等大小的 block。block 是数据缓存的最小单元,大小可配置。当配置 block 大小为 1 MB 时,如果查询 Amazon S3 上一个 128 MB 的 Parquet 文件,StarRocks 会按照 1 MB 的步长,将该文件拆分成相等的 128 个 block,即 [0, 1 MB)、[1 MB, 2 MB)、[2 MB, 3 MB) ... [127 MB, 128 MB),并为每个 block 分配一个全局唯一 ID,即 cache key。Cache key 由三部分组成。

hash(filename) + fileModificationTime + blockId

说明如下。

组成项说明
filename数据文件名称。
fileModificationTime数据文件最近一次修改时间。
blockIdStarRocks 在拆分数据文件时为每个 block 分配的 ID。该 ID 在一个文件下是唯一的,非全局唯一。

假如该查询命中了 [1 MB, 2 MB) 这个 block,那么:

  1. StarRocks 检查缓存中是否存在该 block。
  2. 如存在,则从缓存中读取该 block;如不存在,则从 Amazon S3 远端读取该 block 并将其缓存在 BE 上。

开启 Data Cache 后,StarRocks 会缓存从外部存储系统读取的数据文件。如不希望缓存某些数据,可进行如下设置。

SET enable_populate_datacache = false;

关于 enable_populate_datacache 的更多信息,参见 系统变量

缓存介质

StarRocks 以 BE 节点的内存和磁盘作为缓存的存储介质,支持全内存缓存或者内存+磁盘的两级缓存。 注意,当使用磁盘作为缓存介质时,缓存加速效果和磁盘本身性能直接相关,建议使用高性能本地磁盘(如本地 NVMe 盘)进行数据缓存。如果磁盘本身性能一般,也可通过增加多块盘来减少单盘 I/O 压力。

缓存淘汰机制

在 Data Cache 中,StarRocks 采用 LRU (least recently used) 策略来缓存和淘汰数据,大致如下:

  • 优先从内存读取数据,如果在内存中没有找到再从磁盘上读取。从磁盘上读取的数据,会尝试加载到内存中。
  • 从内存中淘汰的数据,会尝试写入磁盘;从磁盘上淘汰的数据,会被废弃。

开启 Data Cache

Data Cache 默认关闭。如要启用,则需要在 FE 和 BE 中同时进行如下配置。

FE 配置

支持使用以下方式在 FE 中开启 Data Cache:

  • 按需在单个会话中开启 Data Cache。

    SET enable_scan_datacache = true;
  • 为当前所有会话开启全局 Data Cache。

    SET GLOBAL enable_scan_datacache = true;

BE 配置

在每个 BE 的 conf/be.conf 文件中增加如下参数。添加后,需重启每个 BE 让配置生效。

参数说明默认值
datacache_enable是否启用 Data Cache。
  • true:启用。
  • false:不启用。
false
datacache_disk_path磁盘路径。支持添加多个路径,多个路径之间使用分号(;) 隔开。建议 BE 机器有几个磁盘即添加几个路径。BE 进程启动时会自动创建配置的磁盘缓存目录(当父目录不存在时创建失败)。${STARROCKS_HOME}/datacache
datacache_meta_pathBlock 的元数据存储目录,一般无需配置。${STARROCKS_HOME}/datacache
datacache_mem_size内存缓存数据量的上限,可设为比例上限(如 "10%")或物理上限(如 "10G", "21474836480"等)。推荐将该参数值设置不低于 10 GB。10%
datacache_disk_size单个磁盘缓存数据量的上限,可设为比例上限(如 "80%")或物理上限(如 "2T, "500G"等)。举例:在 datacache_disk_path 中配置了 2 个磁盘,并设置 datacache_disk_size 参数值为 21474836480,即 20 GB,那么最多可缓存 40 GB 的磁盘数据。0 表示仅使用内存作为缓存介质,不使用磁盘。

示例如下:

# 开启 Data Cache。
datacache_enable = true

# 设置磁盘路径,假设 BE 机器有两块磁盘。
datacache_disk_path = /home/disk1/sr/dla_cache_data/;/home/disk2/sr/dla_cache_data/

# 设置内存缓存数据量的上限为 2 GB。
datacache_mem_size = 2147483648

# 设置单个磁盘缓存数据量的上限为 1.2 TB。
datacache_disk_size = 1288490188800

查看 Data Cache 命中情况

您可以在 query profile 里观测当前 query 的 cache 命中情况。观测下述三个指标查看 Data Cache 的命中情况:

  • DataCacheReadBytes:从内存和磁盘中读取的数据量。
  • DataCacheWriteBytes:从外部存储系统加载到内存和磁盘的数据量。
  • BytesRead:总共读取的数据量,包括从内存、磁盘以及外部存储读取的数据量。

示例一:StarRocks 从外部存储系统中读取了大量的数据 (7.65 GB),从内存和磁盘中读取的数据量 (518.73 MB) 较少,即代表 Data Cache 命中较少。

 - Table: lineorder
- DataCacheReadBytes: 518.73 MB
- __MAX_OF_DataCacheReadBytes: 4.73 MB
- __MIN_OF_DataCacheReadBytes: 16.00 KB
- DataCacheReadCounter: 684
- __MAX_OF_DataCacheReadCounter: 4
- __MIN_OF_DataCacheReadCounter: 0
- DataCacheReadTimer: 737.357us
- DataCacheWriteBytes: 7.65 GB
- __MAX_OF_DataCacheWriteBytes: 64.39 MB
- __MIN_OF_DataCacheWriteBytes: 0.00
- DataCacheWriteCounter: 7.887K (7887)
- __MAX_OF_DataCacheWriteCounter: 65
- __MIN_OF_DataCacheWriteCounter: 0
- DataCacheWriteTimer: 23.467ms
- __MAX_OF_DataCacheWriteTimer: 62.280ms
- __MIN_OF_DataCacheWriteTimer: 0ns
- BufferUnplugCount: 15
- __MAX_OF_BufferUnplugCount: 2
- __MIN_OF_BufferUnplugCount: 0
- BytesRead: 7.65 GB
- __MAX_OF_BytesRead: 64.39 MB
- __MIN_OF_BytesRead: 0.00

示例二:StarRocks 从 data cache 读取了 46.08 GB 数据,从外部存储系统直接读取的数据量为 0,即代表 data cache 完全命中。

 Table: lineitem
- DataCacheReadBytes: 46.08 GB
- __MAX_OF_DataCacheReadBytes: 194.99 MB
- __MIN_OF_DataCacheReadBytes: 81.25 MB
- DataCacheReadCounter: 72.237K (72237)
- __MAX_OF_DataCacheReadCounter: 299
- __MIN_OF_DataCacheReadCounter: 118
- DataCacheReadTimer: 856.481ms
- __MAX_OF_DataCacheReadTimer: 1s547ms
- __MIN_OF_DataCacheReadTimer: 261.824ms
- DataCacheWriteBytes: 0.00
- DataCacheWriteCounter: 0
- DataCacheWriteTimer: 0ns
- BufferUnplugCount: 1.231K (1231)
- __MAX_OF_BufferUnplugCount: 81
- __MIN_OF_BufferUnplugCount: 35
- BytesRead: 46.08 GB
- __MAX_OF_BytesRead: 194.99 MB
- __MIN_OF_BytesRead: 81.25 MB

Data Cache 填充

异步填充

Data Cache 支持以同步或异步的方式进行缓存填充。

  • 同步填充(默认方式)

    使用同步填充方式时,会将当前查询所读取的远端数据都缓存在本地。同步方式填充效率较高,但由于缓存填充操作在数据读取时执行,可能会对首次查询效率带来影响。

  • 异步填充(3.2.7 及以后)

    使用异步填充方式时,系统会尝试在尽可能不影响读取性能的前提下在后台对访问到的数据进行缓存。异步方式能够减少缓存填充对首次读取性能的影响,但填充效率较低。通常单次查询不能保证将访问到的所以数据都缓存到本地,往往需要多次。

当前系统默认以同步方式进行缓存,您可以通过修改 session 变量 enable_datacache_async_populate_mode 来启用异步填充:

  • 按需在单个会话中开启 Data Cache 异步填充。

    SET enable_datacache_async_populate_mode = true;
  • 为当前所有会话开启 Data Cache 异步填充。

    SET GLOBAL enable_datacache_async_populate_mode = true;