存算分离冷查询提速 7.5 倍!Apache Doris 4.2 Peer Read 实现跨计算组缓存复用

简介: Apache Doris 4.2 引入 Peer Read 机制,实现存算分离架构下跨计算组缓存复用,解决冷查询延迟高、扩缩容后缓存失效等问题。实测主键点查冷查询提速约 7.5 倍,P99 延迟降低约 80%,对象存储请求减少约 98%,全面解析工作原理、性能测试与配置方法。

导读:存算分离架构下,计算组间缓存无法共享,容易导致冷查询延迟高、扩缩容后性能抖动等问题。即将发布的 Apache Doris 4.2 引入 Peer Read 机制,实现跨计算组缓存复用。实测主键点查冷查询性能提升约 7.5 倍,有效降低冷读延迟与对象存储访问开销。

作者:邓鑫,SelectDB 存储研发工程师


在 Apache Doris 存算分离架构中,部署多个计算组时,通常会遇到以下三类问题:

  • 读写分离后的首次查询延迟:新导入的数据已缓存在写入组,读取组首次查询时仍需从对象存储回源读取,单条主键点查的延迟可达数秒。

  • 扩缩容后的性能抖动:计算组扩容或 Tablet 重新均衡后,新节点的本地缓存为空,查询性能需要一段时间才能恢复。

  • 缓存淘汰后的重复回源:读取组的缓存容量有限,数据被淘汰后再次被访问,又要重新从对象存储读取。

这些问题的根源在于:存算分离让各计算组共享了数据,却没有共享缓存。

Apache Doris 4.2 新增的 Peer Read 机制,正是为解决这一问题设计:当本地缓存未命中时,优先从可能已缓存该数据的其他节点读取,包括其他计算组的节点;对方没有数据或响应过慢时,再回源对象存储。

在某用户的真实业务场景中,开启 Peer Read 后:

  • 主键点查的冷查询平均耗时从 4.45 秒降至 0.59 秒,查询速度提升约 7.5 倍;

  • P99 延迟从 7.69 秒降至 1.52 秒,对象存储请求次数减少约 98%。

  • 在 TPC-H 1TB 冷读测试中,22 条查询的总耗时降低约 51%。

一、缓存孤岛:数据共享,缓存不共享

存算分离架构下,一个 Doris 集群可以挂载多个计算组,用于读写分离、在离线隔离和弹性扩缩容。数据和元数据在各计算组之间共享,任一计算组写入后,其他计算组立即可见。

但为了保证查询性能,每个计算组的 BE 都有各自的本地 File Cache,这一层并不共享:写入组已缓存的数据,读取组无法直接使用;读取组 A 已缓存的数据,读取组 B 同样用不上。每个计算组都成了一座“缓存孤岛”。前面提到的三类问题,都源于此。

cache-islands.png

各计算组共享对象存储中的数据,但本地缓存互不共享,读取组未命中时只能各自回源。

1.1 冷读为什么慢

对象存储擅长大块数据的吞吐,但单次请求的延迟远高于本地磁盘和同机房网络。很多查询在读取数据之前,需要先读取一批 Segment Footer 和索引,这些读取单次数据量很小,次数却很多。在第四节的主键点查测试中,每条查询平均发起 200 多次远端 IO,大部分是 Footer 和索引这类小块读取。这类查询的耗时,主要花在逐次等待对象存储的请求延迟上。

1.2 缓存预热与 Peer Read

Doris 在之前版本中,已经提供了缓存预热能力,包括写入后主动通知读取组的增量预热。预热的前提是事先知道哪些数据会被访问,在查询到来之前把数据从对象存储拉取到本地缓存。

对于预热尚未覆盖、只有在查询时才发现缓存未命中的数据,则可以通过 Peer Read 进行补充。

对比维度 缓存预热 Peer Read
触发时机 查询之前,主动将数据从对象存储拉取到本地缓存 查询时本地缓存未命中,从其他节点读取
前提 事先知道哪些数据会被访问,并配置预热任务或预热关系 无需预判数据冷热
适用场景 已知的热点数据、新导入数据的增量同步 预热未覆盖的冷读:扩缩容之后、缓存淘汰之后、预热尚未完成时
代价 每个读取组都需预留缓存空间,预热本身也要读取对象存储 读取时占用对端节点的网络和磁盘资源

两者可以配合使用:缓存预热提前加载已知热点数据,Peer Read 则在查询时补足未命中的缓存。

二、Peer Read 的工作原理

Peer Read 不引入新的缓存服务,直接复用各个 BE 已有的 File Cache。它只在本地 File Cache 未命中时介入,本地命中时读取路径不变。一次缓存未命中的处理流程如下:

peer-read-flow.png

Peer Read 处理一次缓存未命中:找到候选节点,只读取缺失的缓存块,必要时回源对象存储,最后回填本地缓存。

2.1 候选节点的来源

候选节点(下文称 Peer)有两个来源:

  • 扩缩容时由 FE 指定:在同一计算组内,Tablet 从原 BE 迁移到新 BE 时,FE 会将原 BE 告知新 BE,作为最高优先级的候选。新 BE 首次读取即可从原 BE 获取缓存块,无需直接回源。

  • 按需向 FE 查询:本地没有候选时,BE 在后台向 FE 查询该 Tablet 在各计算组的分布,当前读取不等待查询结果,先回源对象存储。一次冷查询内部有大量并发读取,读取第一个 Footer 时就会触发查询,因此同一条查询的后续读取通常已能使用 Peer。

此外,BE 会记录每个 Tablet 上次成功读取的计算组,下次优先向它请求。

2.2 只读取缺失的缓存块,并回填本地缓存

请求方只向 Peer 请求本地缺失的缓存块。数据返回后,一份交给当前查询,一份写入本地 File Cache,下次相同的读取即可命中本地缓存。

2.3 与对象存储竞速:Peer 优先 20 毫秒

Peer Read 默认与对象存储读取竞速。请求先发往 Peer,并给予 Peer 20 毫秒(可配置)的优先时间:Peer 在 20 毫秒内返回,就不再发起对象存储请求;超过 20 毫秒仍未返回,则同时读取对象存储,采用先返回的结果。

race-timeline.png

Peer 优先 20 毫秒:Peer 及时返回时不访问对象存储;Peer 较慢时两路同时读取,采用先返回的结果。

这一设计在两种极端之间取得平衡:如果 Peer 与对象存储同时发起请求,每次未命中都会多产生一次对象存储请求;如果一直等待 Peer,一个慢节点就会拖慢整条查询。

2.4 失败时自动回源

Peer 不可达、超时、没有对应数据或正在限流时,查询会自动回源对象存储,不会报错。系统还会持续维护候选列表:没有数据的节点移到列表末尾,连续失败的节点被剔除;某个 Tablet 的所有候选都反复未命中时,暂停一段时间的 Peer 尝试,避免反复请求无效节点。

2.5 由写入组代为回源

在一写多读场景下,可以将写入组指定为读取组的“填充计算组”。读取组向写入组请求数据时,如果写入组 BE 本身也没有缓存,就由它代为回源对象存储,先写入自己的 File Cache,再将数据返回给读取组。

fill-compute-group.png

写入组作为填充计算组:冷数据只回源一次,多个读取组共享写入组的缓存。

这样,多个读取组对同一份冷数据只需回源一次,缓存也集中在写入组上,其他读取组后续访问即可直接命中。填充有并发和超时上限,超过上限时由请求方自行回源。

三、TPC-H 1TB:冷读总耗时减少约一半

我们先用 TPC-H 1TB 数据集,在写入组和读取组之间做了冷读对照测试:写入组已缓存数据,读取组在每条查询执行前清空缓存,依次执行 22 条查询。

tpch-cold-read.png

读取方式 22 条查询总耗时 对比直读对象存储
冷读,直读对象存储 323.3 秒 基准
冷读,开启 Peer Read 158.6 秒 快约 2 倍,耗时减少 51%
热读,本地缓存命中(参照) 59.5 秒 —

测试条件:TPC-H 1TB;1 个 FE(4 核 16GB),6 个 BE(32 核 128GB,每个 BE 3 块 500GB 云盘),写入组和读取组各 3 个 BE;缓存块 1MB;Peer Read 使用默认的竞速模式。

开启 Peer Read 后,冷读总耗时从 323.3 秒降至 158.6 秒,整体查询速度提升约 2 倍。

进一步改用“先 Peer、失败再回源”的串行模式,总耗时为 155.5 秒,结果相近;在串行模式下逐条对比,22 条查询均快于直读对象存储,单条加速 1.4~3.3 倍。

3.1 写入组也未缓存时:代为回源的额外开销约 3%

上面的测试中,写入组已缓存了数据。如果数据刚刚写入、写入组自身也尚未读取过,读取组向写入组请求时,写入组同样未命中,就会代为回源:从对象存储读取数据,写入自己的缓存,再返回给读取组。

我们也测试了这种最坏情况:写入组和读取组都没有缓存,由写入组代为回源,22 条查询总耗时 332.4 秒,仅比读取组直读对象存储多约 3%。

测试条件同上,这组测试使用串行模式(先 Peer,失败再回源)。

这组数据说明两点:

  • 代为回源几乎不增加开销:多经过一跳转发,总耗时只增加约 3%,开启填充计算组在最坏情况下也不会明显变慢。

  • 收益体现在后续读取:这次读取之后,数据已保留在写入组的缓存中,其他读取组再读同一份数据,就相当于上表中“开启 Peer Read”的情形。多个读取组读同一份冷数据,原本需要各自回源,现在只需回源一次。

四、用户实践:一写多读 API 服务,冷查询提升约 7.5 倍

TPC-H 是标准的分析型负载,下面来看一个真实业务场景。

某用户在 SelectDB(基于 Apache Doris 的云服务)上采用一写多读架构:一个写入组持续导入新数据,多个读取组承载对外的 API 查询,查询以主键点查为主。新数据首次被查询时延迟波动明显;为了抑制波动,每个读取组都需要预留充足的缓存,同一份数据在多个计算组中各存一份。

接入 Peer Read 时,DBA 为该用户将写入组设为读取组的填充计算组:读取组本地未命中时,先从写入组读取;写入组也没有时,由写入组代为回源。

为了量化效果,该用户用业务表(Unique Key 主键模型)实测了 100 条主键点查:写入组先将数据读热;读取组清空缓存并重启后,分别在关闭和开启 Peer Read 时执行同样的 100 条查询,覆盖 100 个不同的 Tablet,串行执行,每条一次。

point-query-results.png

指标 冷读(关闭 Peer Read) 冷读(开启 Peer Read) 本地热读(参照)
平均耗时 4.45 秒 0.59 秒 0.06 秒
P99 耗时 7.69 秒 1.52 秒 0.09 秒
对象存储请求数 21,368 次 372 次 0
对象存储读取量 4.24 GiB 约 186 KiB 0

测试条件:每个计算组 1 个 BE,单轮串行执行。

开启 Peer Read 后,100 条查询都从 Peer 获取到了数据,且每一条都比关闭时快:平均耗时下降约 87%,提升约 7.5 倍;P99 下降约 80%。对象存储请求从 21,368 次降至 372 次,仅为原来的约 1.7%;由于对象存储按请求次数计费,这部分费用也随之下降。

相比如 TPC-H 这类以大块扫描为主的分析场景,点查场景提升更明显,原因在于第一节提到的小 IO:点查返回的数据量很少,耗时主要花在大量 Footer 和索引的小 IO 上,而 Peer Read 正好缩短了每一次小 IO 的等待时间。

注意,Peer Read 并不能替代本地缓存:它仍比本地热读慢一个数量级左右。它的作用是在本地缓存建立之前,先把冷读延迟降到可接受的水平。

五、在 Apache Doris 中启用 Peer Read

注意:Apache Doris 4.2 中,Peer Read 以实验特性提供,默认关闭。

5.1 开启步骤

  • 确认所有 BE 已开启 File Cache(enable_file_cache = true)。

  • 在所有 BE 上设置 enable_cache_read_from_peer = true。该开关同时控制同计算组和跨计算组的 Peer 读取。

  • 一写多读场景如需由写入组代为回源,在读取组的所有 BE 上设置 peer_cache_fill_compute_group_id,取值为写入组的计算组 ID(不是名称)。

5.2 验证是否生效

通过查询 Profile 中 SegmentIterator 节点下的以下指标,可以判断 Peer Read 是否生效、是否占优:

  • NumPeerIOTotal:通过 Peer 读取的次数;

  • CrossCGPeerIOTotal:其中跨计算组读取的次数;

  • PeerRaceWin / S3RaceWin:竞速中 Peer 与对象存储各自胜出的次数。

5.3 使用建议

  • 跨计算组读取会占用对端计算组的网络和磁盘资源;被指定为填充计算组时,还会占用其对象存储带宽和缓存空间。对资源隔离有严格要求的业务,可以关闭 Peer Read。

  • 计算组跨可用区部署时,跨计算组的 Peer 读取会产生跨可用区流量费用。

  • 如果 S3RaceWin 明显多于 PeerRaceWin,说明当前环境下 Peer 并不比对象存储快:更关注对象存储请求费用时,可以调大优先时间(peer_race_hedge_delay_ms),让更多读取由 Peer 完成;更关注延迟时,可以直接关闭。

  • Peer Read 仅作用于存算分离模式下的内表,Hive、Iceberg 等外表的读取不经过 Peer Read。

完整参数和排障方法请参考 Apache Doris Peer 读文档。

六、结束语

存算分离让数据只需存储一份,Peer Read 则让缓存也能在计算组之间共享:一个计算组已缓存的数据,其他计算组同样可以使用。读取组首次查询的新数据、扩容后的新节点、被淘汰后再次访问的数据,都可以优先从其他节点读取,而不必每次都从对象存储重新读取。

Peer Read 不引入新组件,失败时自动回源。在 TPC-H 1TB 测试中,它将冷读总耗时减少了一半;在用户业务表的主键点查中,它将冷查询平均耗时从 4.45 秒降至 0.59 秒。

Peer Read 将随即将发布的 Apache Doris 4.2 正式推出。阿里云瑶池 SelectDB 已默认开启 Peer Read,欢迎使用。

目录
相关文章
|
5天前
|
JavaScript API iOS开发
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(DSH)是DeepSeek于2026年开源的MIT协议AI Agent框架,支持插件化组装模型、工具、沙箱与UI,兼容主流大模型。本文提供免Node.js的桌面端安装包(Win/macOS),含详细图文教程及热门插件推荐。
2483 17
|
6天前
|
iOS开发 Docker MacOS
【2026实测】Docker Desktop下载、安装、汉化、配置教程(附官网安装包)
Docker Desktop 是 Docker 官方推出的桌面容器管理工具,集成引擎、CLI、图形界面与 Kubernetes,支持 Win/macOS/Linux。2026 最新版 4.88.1 强化 ARM 原生运行、镜像加速及资源可视化,附中文汉化与国内镜像配置指南。
1085 3
|
云安全 安全 网络安全
|
5天前
|
Linux 开发工具 iOS开发
Codex保姆级教程(下载+安装+登录+使用,含所有版本,2026最新)
Codex是OpenAI推出的开源AI编程智能体,本地运行,可理解整个代码库,支持自然语言指令改代码、执行命令、跑测试、修Bug,兼容Win/macOS/Linux。(239字)
|
6天前
|
安全 算法 定位技术
《高性价比人生指南》完整原版:普通人用最少的资源,过好这一生的底层逻辑~How To Live Better
📖《高性价比人生指南》是一份基于实证、拒绝焦虑的生存手册,倡导以“人生时薪”为视角,重新计算时间、金钱与精力的成本与收益。它不承诺逆袭,只教人算清账:省下的钱若耗掉时间便亏;买体验比买物品更值;睡眠是最高杠杆的健康投资;关系贵在情绪价值而非表面热络;学习重在改变行为而非自我安慰。核心理念:用低成本、高回报的微小行动,换取长期的选择权——不是成为谁,而是掌控自己人生的主动权。
|
18天前
|
人工智能 API 开发工具
DeepSeek Harness 神插件:白嫖 13 家大厂模型
`dsh-our-free-model` 是 DeepSeek Harness 神级插件:零配置、零API Key、零账号,聚合13家大厂免费模型(含DeepSeek V4.1 Flash、Kimi K3等),支持本地网关、用量看板与自动降级,真正实现“白嫖即用”。
3240 51
|
12天前
|
JavaScript 安全 前端开发
Nodejs Brotli decoder 代码执行漏洞 (CVE-2026-111497)10629
Node.js发布安全更新修复Brotli解码器高危RCE漏洞(CVE-2026-111497),建议受影响版本用户立即升级。
2117 2
|
11天前
|
人工智能 JSON Linux
【保姆级】ComfyUI部署教程(下载+安装+配置+工作流,2026最新)
ComfyUI 是一款开源节点式AI生成工具,支持图像、视频、音频及3D内容创作。通过拖拽连线组合模型加载、提示词、采样等节点,构建可复用、易修改的工作流,兼容SD1.5、SDXL、Flux、Qwen Image等主流模型。

热门文章

最新文章