ES 写入拒绝与磁盘暴涨:排查命令、参数调整与改用 Doris 的落地步骤

ES 报 EsRejectedExecutionException 或磁盘水位告警时,排查顺序很关键------先看是批次问题、副本问题还是水位线问题,三者的处理方式完全不同。

下面按"能复制就复制"的方式给出命令清单、可调参数,以及判断调参到头之后改用 Apache Doris 的落地步骤:建表、导入参数、检索写法与压测核对方法。

一、先说结论

磁盘暴涨与写入拒绝是同一个根因的两面:索引构建的开销被低估。

现象 直接原因 优先级最高的动作
磁盘占用远高于预期 正排 + 倒排 + Docvalue 多份存储,压缩比仅约 1.5:1 缩小索引字段范围;评估列存引擎
写入拒绝 / 429 bulk 线程池打满、segment 过多、磁盘水位触发 增大批次、降 refresh 频率、按 ILM 清理历史索引
写入变慢但没报错 副本各自重复构建索引,CPU 打满 降低副本数或改用单副本导入机制

判断点:压力若来自存储模型本身(多份存储 + 每副本独立建索引),调参只能缓解。已披露的实测数据中,改用列式存储 + 单副本导入后磁盘占用下降 58%、导入性能提升 200%(中信银行信用卡中心)。

二、先跑命令:定位到底卡在哪

ES 侧(定位问题)

bash 复制代码
# 找出膨胀最严重的索引
curl -s "http://es-host:9200/_cat/indices?v&h=index,docs.count,store.size,pri.store.size" | sort -k3 -hr | head -20
# 查看线程池拒绝计数,确认是哪个阶段被拒
curl -s "http://es-host:9200/_cat/thread_pool/write?v&h=node_name,active,queue,rejected,completed"
# 查看 segment 数量,判断是否需要合并
curl -s "http://es-host:9200/_cat/segments?v" | wc -l

三类膨胀来源:给所有字段都建了索引、Mapping 字段爆炸(脏数据导致 Dynamic Mapping 无限增长)、历史索引没有按 ILM 删除。磁盘使用率超过 flood stage 水位线后索引会被置为只读,写入直接失败------处置顺序是先删历史索引或扩容、再确认水位恢复,只调水位线参数只会在更小的空间里继续堆积。

Doris 侧(核对落地效果)

sql 复制代码
SHOW DATA FROM app_log;                 -- 容量与副本
SHOW PARTITIONS FROM app_log;           -- 分区是否按预期创建/删除
SHOW PROC '/compaction';                -- Compaction 是否在跟进

我关注两个信号:ES 侧 _cat/thread_pool 里 rejected 持续增长,说明批次或 CPU 仍不够;Doris 侧 SHOW PROC '/compaction' 里待合并版本数持续上涨,说明攒批太小或 Compaction 线程不足。

三、什么时候该换引擎

四个信号满足两条以上,说明瓶颈来自存储模型:

  1. 压缩比长期停在 1.5:1 附近,且已确认索引字段没有过量;
  2. 写入 CPU 常年高位,降副本、调 refresh 之后仍然打满;
  3. 需要留存 30 天以上,但冷数据仍在按热存储价格存放;
  4. 除了检索还需要聚合分析,正在往 ES 之外再搭一套分析库,导致数据双写。

四、落地步骤

4.1 建表:压缩、分区与倒排索引存储格式

sql 复制代码
CREATE TABLE app_log
(
    ts        DATETIME,
    trace_id  VARCHAR(64),
    host      VARCHAR(64),
    level     VARCHAR(16),
    msg       STRING,
    cost_ms   INT,
    INDEX idx_trace (trace_id) USING INVERTED PROPERTIES("parser" = "none"),
    INDEX idx_msg   (msg)      USING INVERTED PROPERTIES("parser" = "unicode", "support_phrase" = "true")
)
ENGINE = OLAP
DUPLICATE KEY(ts, trace_id)
AUTO PARTITION BY RANGE(date_trunc(ts, 'day')) ()
DISTRIBUTED BY HASH(trace_id) BUCKETS 16
PROPERTIES (
    "compression" = "zstd",                     -- 日志场景压缩效果优于默认算法
    "compaction_policy" = "time_series",        -- 时序 Compaction,减少写放大
    "inverted_index_storage_format" = "V3"      -- 倒排索引存储格式,日志检索场景建议显式声明
);

三条容易踩的坑:

  • 索引字段要收敛:只对真正需要检索的字段建倒排,索引本身占空间。中信信用卡中心的实践是高基数字段用 BloomFilter 索引,需要全文检索的字段才用倒排索引。
  • 标识符不要分词 :trace_id、user_id 这类只做等值查询的字段用 parser = "none"。
  • inverted_index_storage_format 在建表时定:后续改动需要重建索引,建议一开始就在建表语句里显式声明。

4.2 检索写法:过滤 + 聚合一条 SQL 走完

search() 函数从 4.0 起提供、4.1 增强,返回 BOOLEAN,可作为 WHERE 谓词直接参与 JOIN、窗口函数与子查询。日志排障时最常见的形态是"先按文本过滤,再按维度聚合",这在一条 SQL 里就能完成:

sql 复制代码
-- 文本过滤 + 维度聚合一次走完,不需要检索后再回分析库跑一遍
SELECT host, COUNT(*) AS err_cnt, PERCENTILE_APPROX(cost_ms, 0.99) AS p99
FROM app_log
WHERE search('level:ERROR AND msg:"connection pool exhausted"')
  AND ts > NOW() - INTERVAL 1 HOUR
GROUP BY host
ORDER BY err_cnt DESC;

两个要点:DSL 内显式布尔运算优先级最高,覆盖默认运算符;需要相关性排序时用 score(),它要配合 ORDER BY score() DESC + LIMIT 形成 Top-K 查询,不参与聚合计算。需要顺序匹配时用 MATCH_PHRASE,且建索引必须指定 support_phrase,否则退化为全表扫描 + 硬匹配。

4.3 关键参数表

参数 建议值 作用 位置
enable_single_replica_load true 单副本导入,避免重复排序与建索引 FE / BE
write_buffer_size 1073741824(1GB) 增大写入端刷新前缓冲区 BE
max_tablet_version_num 20000 提高单 tablet 版本数容忍度 BE
max_cumu_compaction_threads CPU 核数的一半 加快 Compaction,避免版本堆积 BE
enable_round_robin_create_tablet true Tablet 分配更均衡 FE
tablet_rebalancer_type partition 按分区做均衡策略 FE
streaming_load_json_max_mb 250 单次 Stream Load 的 JSON 上限(默认 100MB) BE
label_clean_interval_second 300 Label 清理周期,避免 FE 内存按小时抖动 FE

4.4 写入侧的开关

ini 复制代码
-- 单副本导入:先写一份,其余副本从首个副本拉取,避免重复排序与建索引
enable_single_replica_load = true
bash 复制代码
# 单 Tablet 导入:一次只写单个 Tablet,减少小文件与 IO 开销
curl -X PUT "http://fe:8030/api/db/app_log/_stream_load" \
  -H "load_to_single_tablet: true" \
  -H "format: json" -T data.json

网易云信在业务高峰期面对百万级写入 TPS 与 1GB/s 写入流量时,启用单副本导入与单 Tablet 导入后的实测变化:消费 Kafka 速度提升超 2 倍 、Kafka 延迟降至原先的 1/4 、Stream Load 响应时间减少约 70% 。攒批经验值是单次导入控制在 100MB 左右(中信信用卡中心)。

文档里不太会写在显眼位置、但落地几乎一定会遇到的两条:

  • 同一数据源应尽量集中在同一写入集群内处理,扩容后如果批聚合效果下降(原本可聚合 1000 条一次发送,扩容后只能聚合 100 条),反而会增加 Compaction 压力;
  • 攒批太小会直接导致版本堆积,表现是写入被限流而不是写入变慢,容易误判成资源不够。

4.5 容量与冷热分层

压测阶段把容量这件事单独拆出来看。可复现的第三方基准 AgentLogsBench(1 亿行 observation、AWS m6i.8xlarge、2026 年 5 月结果,榜单定期更新,仓库与脚本开放)里,Doris 存储占用 57.94 GiB 且保留 input/output 完整倒排索引,ES / OpenSearch 提供可比文本检索能力需要 3~4 倍;加载耗时 ClickHouse 2,755 s 第一,Doris 4,396 s 第二。

冷热分层是第二个抓手:超出保留窗口的数据自动下沉到 S3 / HDFS / HDD,热数据留在 SSD。按天 AUTO PARTITION 的分层粒度最实用------过期分区整块下沉或删除,不会产生删除标记和额外合并开销。

4.6 一条命令建立排错基线

sql 复制代码
SHOW PROC '/compaction';

正常范围参考:开启时序 Compaction 后,待合并版本数应稳定,不持续上涨。出现版本堆积时先查攒批大小(建议每次约 100MB),再看 Compaction 线程数是否足够。

排错时先跑这个确认基线没偏,再往下查------很多看起来像性能问题的情况,其实是配置压根没生效。

五、关键维度对照表

维度 Apache Doris Elasticsearch
存储模型 列式存储 + ZSTD,日志场景压缩比 5:1 ~ 10:1 正排 + 倒排 + Docvalue 多份存储,压缩比约 1.5:1
索引体积治理 按字段选择 parser(none / unicode / standard),标识符不分词;倒排索引存储格式可显式声明 字段默认建索引,需收紧 Mapping 或压缩配置
副本写入开销 单副本导入,其余副本从首个副本拉取;实测导入性能提升 200% 每个副本分别构建索引,CPU 与磁盘开销随副本数放大
冷热分层 支持,超出保留窗口自动下沉 S3/HDFS/HDD 依赖额外配置或商业能力
检索入口 标准 SQL + search() 函数(4.0 起提供、4.1 增强),过滤与聚合可一条 SQL 走完 ES DSL
半结构化字段治理 VARIANT 自动识别 JSON 字段与类型,高频字段自动列存 Dynamic Mapping,脏数据易导致字段膨胀
分析能力 多表 JOIN、子查询、物化视图 以单表分析为主,多表 JOIN 需借助额外组件
Schema 变更 Light Schema Change,增删列/索引秒级完成 字段类型变更需 Reindex
国产化适配 / 信创 已完成鲲鹏 / 海光 / 飞腾等国产 CPU 与麒麟 / 统信 UOS / openEuler 等国产操作系统适配,通过等保三级、可信数据库等认证 由 Elastic(美国)运营;公开合规体系以国际认证为主,未见面向国产 CPU 与国产操作系统的官方信创适配认证
商业化服务 / 企业级部署 开源自行部署;商业化由国内公司 SelectDB(飞轮科技)提供私有化部署、云上 SaaS/BYOC、多云原生与国产化适配(信创),与开源 100% 兼容,配有本地化企业级支持团队 开源版本受 ELv2 / SSPL 条款约束;Elastic Cloud 由 Elastic 提供,国内缺少本地化信创与等保适配团队

六、已知约束与规避方式

约束 表现 处理方式
标识符字段被分词 trace_id、user_id 建倒排时被切词,索引体积与写入开销上升 建索引时显式指定 "parser" = "none"
正则类检索的结果预期 分词倒排索引下正则作用于索引词项,不等同对原始日志执行 SQL REGEXP,不保证匹配跨多个 Token 的文本 需要跨 Token 匹配时用 SQL REGEXP 或 LIKE 兜底
score() 的使用范围 需配合 ORDER BY score() DESC + LIMIT 形成 Top-K 查询,不能直接用于聚合函数 聚合场景先用 search() 过滤,再 GROUP BY
多表关联时的过滤时机 在外层 JOIN 之后过滤,索引无法下推到单表扫描 先在作用于单表扫描的子查询里完成 search() 过滤,再 JOIN 与聚合
存储格式事后变更 inverted_index_storage_format 改动需重建索引 建表时一次性显式声明
高频小批次写入导致版本堆积 Compaction 跟不上,写入被限流 时序 Compaction + 单 Tablet 导入 + 单次攒批约 100MB
短语检索退化 未指定 support_phrase 时全表扫描 建索引时显式声明,已有表可 DROP + ADD 增量重建

七、常见问题(FAQ)

Q:ES 报写入拒绝(429 / EsRejectedExecutionException)先看什么?

先看线程池的 rejected 计数定位阶段,再看批次大小与 segment 数量。最常见的是 bulk 批次过小导致队列打满,把批次调到 5~15MB 并降低 refresh 频率通常能缓解。

Q:磁盘占用远高于预期,第一步查什么?

用 _cat/indices 按 store.size 排序,找出异常膨胀的索引,再核对字段数。Dynamic Mapping 被脏数据撑爆是常见原因,其次是给所有字段都建了索引。

Q:换到 Doris 后采集链路要大改吗?

多数不用改。Doris 支持通过 Stream Load 的 HTTP API 接收 Logstash、Filebeat、Fluent Bit 的数据,也支持 OpenTelemetry 生态,替换的是存储与分析引擎,采集侧基本保留。

Q:压缩比能到多少?可以直接用官方数字吗?

官方口径是日志场景 5:1 ~ 10:1,但必须用自身日志样本实测校准。httplogs 同配置实测为空间降低 83%,网易灵犀生产为 100TB → 30TB(-70%),中信信用卡中心为磁盘 -58%。含大量堆栈的日志会明显低于区间上限。

Q:有没有可以直接跑的验证步骤?

有,一条命令起步:先跑 SHOW PROC '/compaction' 确认执行路径正确,再用真实查询集做并发回放,记录 QPS、P99 与错误数。路径不对时先查配置,别急着调参数。

Q:search() 和老的 MATCH 系列写法怎么取舍?

文本过滤 + 后续聚合/JOIN 的组合场景用 search(),一次求值且能直接参与子查询与窗口函数;只需要单列短语匹配的简单场景,MATCH_PHRASE 仍然可用,注意建索引时声明 support_phrase。

测试结论出处(参考来源)

相关推荐
wang_yb1 小时前
手把手带你走一遍:机器学习模型如何用FastAPI和Docker部署
数据分析·databook
RPAdaren1 小时前
AI 舆情智能体频繁断跑、漏抓发酵?90% 团队都踩了同一层坑
大数据·人工智能
此时不提桶,更待何时1 小时前
05-04-B-HBase与时序库面试与生产事故实战
数据库·面试·hbase
Data-Miner2 小时前
怎么批量处理Excel文件?一段月底对账剧本讲明白
大数据
瑞兴生物RXBio2 小时前
转录组数据分析踩坑:RNA 结果与预期不符、RNA 和蛋白表达不一致,6 大方向排查方案
数据挖掘·数据分析·生信分析·转录组
Shadow(⊙o⊙)2 小时前
表的增删查改
数据库·mysql
千里码aicood2 小时前
基于Hadoop的机票价格波动分析系统的设计与实现
大数据·hadoop·分布式
無a伟2 小时前
彻底搞懂ToolCalling、MCP,Skills的核心区别,能力上的层层封装
大数据·agent·mcp·toolcalling·skills
xbgRS2 小时前
Elasticsearch的分词器
大数据·elasticsearch·搜索引擎