检索分析服务 Batch Commit:对高并发小批量写入的优化

在日志类业务、埋点收集等高并发小批量写入场景中,系统往往面临写入请求频繁、单次数据量较小的问题。传统“请求即落盘”的写入路径会为每个独立的 bulk 请求生成一个数据 Part 并立即写入磁盘,进而导致。

相关产品
检索分析服务 产品页,含版本规格、价格与购买入口。

一、背景

·Part 文件数量激增,系统在短时间内生成大量细小的碎片文件;

·后台合并(Merge)压力上升,频繁的小文件合并严重消耗 I/O 和 CPU;

·写入性能抖动,前台写入受后台 Merge 任务拖累;

·存储资源浪费,过多小文件占用 inode,压缩比下降;

·系统稳定性下降,Merge 队列堆积时易产生请求排队和延迟波动。

为解决以上结构性瓶颈,我们引入了写入攒批能力,在引擎层新增写入缓冲逻辑,实现在内存中对数据进行按需积累、统一提交的策略。

写入攒批能力主要面向以下场景:

·高并发、小批量写入频繁的在线日志接入

·多分区散写场景,如设备 ID、用户 ID 为分区键

·对写入性能、Merge 成本、稳定性有更高要求的业务系统

该能力通过在内核中延迟生成 Part,控制写入节奏,主动将多个小写入合并为一个紧凑的落盘操作,有效提升系统在高并发接入下的整体写入质量和资源效率。

二、写入缓冲(攒批)机制详解

写入攒批的核心思路是在内存中暂存批量数据,满足特定条件后再统一生成 Part 落盘,从而以更少、更大、更紧凑的 Part 替代大量零散小 Part。该机制包括以下几个关键阶段:

三、1. 请求解析为 Block(延迟生成 Part)

当接收到一个 bulk 请求后,系统会对其中的文档进行解析,构造成内部的 Block 数据结构。每个 Block 相当于一个逻辑上的写入批次,但此时不会立即生成 Part 文件,即不会触发磁盘写入。此步骤的意义在于打破“请求即落盘”的链路,将写入节奏从请求驱动转为数据积累驱动,为后续缓冲与合并创造条件。

四、2. 写入 WAL(保证数据可靠性)

解析后的 Block 会首先写入到 WAL(Write-Ahead Log),这是一个顺序写入的日志文件,确保数据在内存攒批期间即使发生故障也不会丢失。WAL 写入具有以下特性:

·支持快速追加写,性能高

·后续落盘成功后即可被安全清理

·在系统异常恢复时可重放

该步骤确保攒批过程在保证性能的同时不牺牲可靠性。

五、3. 写入内存缓冲区(攒批)

Block 会写入引擎中的 MutableBuffer(可变缓冲区),这是内存中的临时数据结构,用于对多个请求的数据进行聚合缓冲。多个 bulk 请求的数据可以持续累积到这个缓冲区中,直到触发条件满足。这一步是核心的“攒批”行为,通过有序缓存数据,为后续生成更大、更连续的 Part 打下基础。

六、4. 提交触发机制(可配置)

为了控制攒批时长与写入时机,系统提供了灵活的触发策略,满足任一条件即可触发 Commit:

·数量阈值触发:缓冲区内数据达到预设的行数或字节数,

·时间阈值触发:距离本轮攒批的第一次写入时间已超过一定时长,可保证低频写入不会长时间滞留

该机制在写入吞吐与写入延迟之间实现动态平衡:高频写入以数据量触发,低频写入以时间触发,确保既能合并批次,又能保障响应性。

七、5. 批量生成 Part(统一落盘)

一旦触发条件满足,系统将当前缓冲区中的所有数据一次性转为一个或多个 紧凑型 Part 文件 并写入磁盘。这些 Part 比原始单个请求生成的小 Part 更大、更稠密、更适于后续合并和扫描。生成 Part 时的优化包括:

·对同一分区的多条数据批量处理,避免分散写入多个文件

·更好的数据局部性和列压缩比

·降低文件数量、目录层级与 inode 占用

八、6. 清理 WAL 与内存缓存(释放资源)

在 Part 落盘完成后,系统会:

·清理对应的 WAL 段,释放磁盘空间

·回收已写入的 MutableBuffer 区域

·为下一批次写入腾出空间

整个攒批流程至此完成一个闭环。整体设计图如下:

九、机制总结与优势对照

对应问题 传统写入 攒批写入
小文件碎片 每请求一个小 Part 多请求合并生成大 Part
Merge 压力 Merge 次数频繁 Merge 次数减少,合并效率更高
IO 效率 频繁小写,压缩差 批量写入,压缩更优
系统稳定性 Merge 队列堆积风险高 写入平稳,资源利用更均衡
写入延迟 每次落盘受 Merge 干扰 Merge 异步,前台更流畅

通过在引擎层引入攒批机制,不仅优化了写入链路的结构与节奏,更显著提升了系统对高并发、高频次、小体量数据写入的处理能力,是日志型、埋点型等写密集型场景的重要内核能力升级。

十、索引级配置

参数 说明 默认值
index.tsearch.engine.batch_commit.enable 是否开启攒批写入 false
index.tsearch.engine.batch_commit.refresh_buffer_size Cache 在内存中的 Blocks commit 为 Part 的阈值。配置范围[4MB, 64MB] 8MB
index.tsearch.engine.batch_commit.refresh_interval 一批 Blocks 如果在 refresh_interval 时间范围内未达到 refresh_buffer_size 指定的阈值,则也 commit 为 Part 30s
index.tsearch.engine.batch_commit.refresh_rows_count Cache 在内存中的 Blocks commit 为 Part 的阈值。为0时,此参数不生效 0
index.tsearch.engine.batch_commit.allow_back_off_native_write 如果达到了内存限制(全局2GB),是否允许回退到直接写 Part 到逻辑 true

十一、配置示例

PUT /http_logs{ "settings": { "number_of_shards": 1, "number_of_replicas": 1, "index.tsearch.engine.batch_commit.enable": true, "index.tsearch.engine.batch_commit.refresh_buffer_size": "16MB", "index.tsearch.engine.batch_commit.refresh_interval": "30s", "index.tsearch.engine.batch_commit.refresh_rows_count": 0, "index.tsearch.engine.batch_commit.allow_back_off_native_write": true }, "mappings": { "properties": { "foo": { "type": "text" }, "myint": { "type": "long" } } } }

十二、集群级配置

参数 说明 默认值
cluster.tsearch.engine.batch_commit.enable 集群内的索引是否默认开启 BatchCommit,即创建索引时,如果用户没有配置`index.tsearch.engine.batch_commit.enable`,则会使用`cluster.tsearch.engine.batch_commit.enable` false

十三、配置示例

PUT /_cluster/settings{ "persistent": { "cluster.tsearch.engine.batch_commit.enable": true }}

十四、使用限制

目前用于 Batch Commit 的全局内存限制为2GB。如果超过这个上限,则退化为直接写 Part 的逻辑或者返回错误,通过 allow_back_off_native_write 配置。

赞 (0)
上一篇 4天前
下一篇 4天前