万级JSON字段如何拖垮Doris性能
摘要:Apache Doris 4.1针对AI Agent场景下万级JSON字段导致的元数据膨胀问题,提出了DocMode和SegmentV3优化方案。DocMode通过延迟物化策略,将写入时的即时列化压力后移至Compaction阶段,显著提升写入吞吐;SegmentV3采用元数据按需加载机制,使查询仅加载相关列元数据,降低I/O和内存开销。测试显示,优化后的Doris在万级JSON场景下写入性
·
在 AI Agent 场景下,万级 JSON 字段导致的元数据膨胀问题,会通过以下路径严重影响 Apache Doris 的写入与查询性能:
1. 对写入性能的影响
- 写入路径阻塞与吞吐下降:在传统处理方式(如即时物化)下,每个新出现的 JSON key 都会在写入时被尝试物化为独立的子列。当 key 数量达到万级时,写入过程需要处理海量的列创建、类型推断和编码操作,这会导致单次写入的 I/O 和 CPU 开销急剧增加,严重拖慢写入速度,形成写入瓶颈 。
- Compaction 压力与写放大:频繁的写入会产生大量数据碎片(Segment)。后台的 Compaction 进程在合并这些碎片时,如果面对的是数万列的元数据,其合并、排序和重写的成本会变得极高。这会导致 Compaction 任务积压,不仅占用大量系统资源(CPU、I/O),还可能因来不及合并而影响新数据的导入,甚至引发写入失败 。
2. 对查询性能的影响
- 元数据加载开销巨大:在 Doris 4.1 之前的 Segment V2 存储格式中,所有列的元数据(如列名、类型、统计信息、索引位置等)都集中存储在文件尾部(Footer)。查询时,即使只访问其中几个字段,也需要先加载整个文件的完整元数据(可能包含上万列的信息)。这带来了巨大的、不必要的 I/O 和内存解析开销,显著延长了查询的初始响应时间(冷启动延迟)。
- 内存占用激增:将万级字段的元数据全部加载到内存中,会消耗大量的内存资源。在高并发查询场景下,多个查询同时打开不同的数据文件,会导致内存中充斥着大量本次查询并不需要的列元数据,造成内存资源的严重浪费,甚至可能因内存不足而影响查询稳定性或触发 OOM 。
- 随机读放大:对于未物化或未建立高效索引的字段,查询可能需要回退到扫描原始的文档存储(如 Sharded Map)。虽然 Doris 的 Doc Mode 通过哈希分片减少了扫描范围,但相比直接读取物化后的纯列式数据,其 I/O 效率仍然较低。在极端情况下,对冷字段的查询延迟可能比热点字段高出数十倍 。
3. Apache Doris 4.1 的针对性优化方案
为了应对上述挑战,Apache Doris 4.1 引入了 Doc Mode(延迟物化) 和 Segment V3(按需加载元数据) 两项核心优化。
优化方案对比
| 性能瓶颈 | 传统方案的问题 | Doris 4.1 优化方案 | 优化原理与效果 |
|---|---|---|---|
| 写入与Compaction压力 | 写入时立即物化所有JSON path为子列,导致写入慢、Compaction任务重。 | Doc Mode(延迟物化) | 写入时仅将JSON编码为分片的文档结构(Sharded Map)落盘,优先保障写入吞吐。仅在后台Compaction时,根据访问频率将高频path物化为子列,显著降低写入放大和Compaction压力 。 |
| 元数据加载开销 | 查询需加载包含万列信息的完整Footer,I/O与内存开销大。 | Segment V3(按需加载) | 将列级元数据从集中式的Footer中拆解出来,独立存储。查询时仅加载与查询相关的列的元数据,极大减少了冷启动时的I/O和内存消耗。在万列场景下,文件打开速度提升可达16倍,内存占用降低可达60倍。 |
| 冷字段查询效率 | 未物化字段查询需全量扫描原始JSON,效率低下。 | Doc Mode的三档读路径 | 系统根据字段物化状态自动选择最优路径:1. 列式路径(对已物化字段);2. 分片扫描(对未物化字段,仅扫描对应哈希分片);3. 全文档读取(用于SELECT *)。实现了性能与灵活性的平衡 。 |
4. 实际效果与代码示例
根据基准测试(万级JSON path,1亿行数据),优化后的Doris在宽JSON场景下表现均衡:
- 写入性能:Variant Doc Mode的写入吞吐优于ClickHouse和Elasticsearch,接近PostgreSQL JSONB的水平 。
- 查询性能:在聚合与过滤场景下,Doris查询延迟稳定在百毫秒级,而受元数据与随机读影响的ClickHouse延迟在数秒级;相比行存的PostgreSQL JSONB,Doris有数量级的性能优势 。
- 存储效率:得益于纯列式存储和无需冗余副本,Doris的存储空间约为ClickHouse的60% 。
以下是一个启用Doc Mode和Segment V3的建表示例:
-- 建表语句示例,启用Doc Mode和Segment V3存储格式
CREATE TABLE IF NOT EXISTS ai_agent_trace (
trace_id VARCHAR(64) NOT NULL,
timestamp DATETIME NOT NULL,
agent_id VARCHAR(128),
-- 使用VARIANT类型并启用Doc Mode存储AI Agent复杂的交互数据
event_data VARIANT< -- :使用VARIANT类型处理半结构化JSON
'prompt' : STRING,
'tool_call' : ARRAY<STRING>,
'response' : STRING,
properties(
'variant_enable_doc_mode' = 'true' -- :关键配置,启用Doc Mode延迟物化
)
>,
-- 可以为高频查询的字段创建倒排索引加速过滤
INDEX idx_event_data(event_data) USING INVERTED PROPERTIES("field_pattern" = "status")
)
DUPLICATE KEY(`trace_id`, `timestamp`)
DISTRIBUTED BY HASH(`agent_id`) BUCKETS 16
PROPERTIES (
"replication_num" = "1",
"storage_format" = "V3" -- :启用Segment V3格式,实现元数据按需加载
);
查询时,可以像访问普通列一样访问JSON中的字段,优化器会自动选择最佳路径:
-- 查询示例:分析特定工具调用频率
SELECT
DATE(timestamp) as day,
-- 直接通过JSON路径访问已物化或未物化的字段,系统自动路由
event_data['tool_name'] as tool,
COUNT(*) as call_count
FROM ai_agent_trace
WHERE -- 条件过滤,可能利用Doc Mode的分片扫描或列式索引
event_data['tool_name'] IS NOT NULL
AND event_data['status'] = 'success'
GROUP BY day, tool
ORDER BY day DESC, call_count DESC
LIMIT 100;
综上所述,通过 Doc Mode 将写入时的即时列化压力后置到Compaction阶段,并结合 Segment V3 彻底改革元数据的加载方式,Apache Doris 4.1 有效地打破了万级JSON字段带来的元数据膨胀与性能恶化循环,在AI Agent这类高稀疏、高演化、混合读写负载的场景下,实现了写入吞吐、查询延迟与资源开销之间的良好平衡。
参考来源
更多推荐



所有评论(0)