灯下哥谭 灯下哥谭
首页
关于
  • Hermes Agent 平台
  • Claude Code
  • OpenClaw
  • GPU 推理节点运维
  • DeepSeek Harness
  • MySQL 运维知识地图
  • Elasticsearch 运维知识地图
  • Redis 运维知识地图
  • TiDB 体系
  • DBA 常用 SQL 与命令
  • Nginx 运维知识地图
  • Prometheus 监控
  • Docker
  • Systemd
  • Iptables
  • Firewalld
  • Sshd
  • MySQL8 运维 SOP 手册
  • MySQL 实战 45 讲(读书笔记)
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

灯下哥谭

灯还亮着
首页
关于
  • Hermes Agent 平台
  • Claude Code
  • OpenClaw
  • GPU 推理节点运维
  • DeepSeek Harness
  • MySQL 运维知识地图
  • Elasticsearch 运维知识地图
  • Redis 运维知识地图
  • TiDB 体系
  • DBA 常用 SQL 与命令
  • Nginx 运维知识地图
  • Prometheus 监控
  • Docker
  • Systemd
  • Iptables
  • Firewalld
  • Sshd
  • MySQL8 运维 SOP 手册
  • MySQL 实战 45 讲(读书笔记)
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • MySQL

  • Redis

  • 高性能KV

  • TiDB

  • Elasticsearch

    • Elasticsearch 运维知识地图:从安装配置到排障加速恢复
    • Elasticsearch 集群安装:RPM 裸机生产部署 vs docker-compose 快速起集群
    • 给Elasticsearch集群添加用户密码
    • Elasticsearch 分片和副本:容量怎么规划,改分片数为什么这么麻烦
    • Elasticsearch集群节点磁盘使用分配不均解决办法
    • Elasticsearch 索引模板与映射:Composable 模板、mapping 与动态模板
    • Elasticsearch 分页查询三种方案:from/size、search_after、scroll 怎么选
    • Elasticsearch字符串搜索方式
    • Elasticsearch使用wildcard字段模糊匹配
    • Elasticsearch 数据迁移方案对比:esm vs Logstash
    • Nginx Mirror 模块实现三套ES写入网关
    • ES排障两件套:慢查询日志阈值配置 + tcpdump 抓包看真实请求
      • 1. 慢查询日志:按阈值分级记录
        • 1.1 慢日志是按分片记录的
        • 1.2 写入慢日志(indexing.slowlog)
        • 1.3 慢日志级别与输出位置
      • 2. 慢日志不够用时:tcpdump 直接抓 HTTP 请求体
        • 2.1 tcpdump 的 8.x TLS 硬边界
        • 2.2 落盘后用 Wireshark 分析
      • 3. 两件套之外的第三件:tasks 与 nodes/hot_threads
      • 4. 可复用要点
    • ES 集群恢复太慢?三个参数加速节点/分片恢复
    • Elasticsearch 常用 DSL 语句(速查表)
    • ES 集群 Yellow 复盘:1023 个副本永远分配不出去,问题不在磁盘
  • 数据管道

  • 其他数据库

  • 数据库
  • Elasticsearch
灯下哥谭
2023-02-08
目录

ES排障两件套:慢查询日志阈值配置 + tcpdump 抓包看真实请求

排查 Elasticsearch 查询变慢,通常分两个层次:先用慢查询日志锁定"哪些查询慢",如果日志信息还不够(比如想确认客户端到底发了什么原始请求),再用 tcpdump 直接抓包看线上真实流量。

同时,慢日志还有一些容易被忽视的陷阱——比如它按分片记录、日志量可能看起来被放大 N 倍;写入也有独立的慢日志配置;以及 8.x 默认开启 HTTP 层 TLS 后,tcpdump 可能抓到的是密文。

以下记录完整的配置方法、常见坑与避坑要点。

版本说明

本文原写于 2023-02,2026-09 补充。慢日志阈值设置项在 7.x/8.x 通用;8.x 默认开启 HTTP 层 TLS,本文的 tcpdump 明文抓包方式在 8.x 默认配置下不可用。

# 1. 慢查询日志:按阈值分级记录

ES 的慢日志按 warn/info/debug/trace 四级阈值记录,而不是简单的"超过 N 秒就记"——这样可以在日志量和信息粒度之间取平衡:查询稍慢记一条 info,非常慢的才升级到 warn,方便后续按级别过滤。

按合理阈值记录(生产环境常态配置):

PUT /_all/_settings
{
    "index.search.slowlog.threshold.query.warn": "5s",
    "index.search.slowlog.threshold.query.info": "2s",
    "index.search.slowlog.threshold.query.debug": "1s",
    "index.search.slowlog.threshold.query.trace": "400ms",
    "index.search.slowlog.threshold.fetch.warn": "1s",
    "index.search.slowlog.threshold.fetch.info": "800ms",
    "index.search.slowlog.threshold.fetch.debug": "500ms",
    "index.search.slowlog.threshold.fetch.trace": "200ms"
}
1
2
3
4
5
6
7
8
9
10
11

query 阶段对应查询解析和执行,fetch 阶段对应从各分片取回文档内容——两者耗时特征不同,所以分开设阈值。query 慢通常是查询本身复杂(聚合、脚本),fetch 慢通常是命中文档过多或 _source 太大。

临时排查时,把阈值全部降到 0,记录所有语句(跟 MySQL 的 long_query_time=0 是同一个思路):

PUT /_all/_settings
{
    "index.search.slowlog.threshold.query.warn": "0s",
    "index.search.slowlog.threshold.query.info": "0s",
    "index.search.slowlog.threshold.query.debug": "0s",
    "index.search.slowlog.threshold.query.trace": "0s",

    "index.search.slowlog.threshold.fetch.warn": "0s",
    "index.search.slowlog.threshold.fetch.info": "0s",
    "index.search.slowlog.threshold.fetch.debug": "0s",
    "index.search.slowlog.threshold.fetch.trace": "0s",

    "index.indexing.slowlog.threshold.index.warn": "0s",
    "index.indexing.slowlog.threshold.index.info": "0s",
    "index.indexing.slowlog.threshold.index.debug": "0s",
    "index.indexing.slowlog.threshold.index.trace": "0s"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

坑:跟 MySQL 全量慢日志一样,这是临时手段——全量记录会让日志量随 QPS 线性增长,排查完必须把阈值改回生产值,否则磁盘会被日志占满。

验证:跑几条查询后检查 logs/<cluster-name>_index_search_slowlog.log(路径见 path.logs 配置),应该能看到刚才的请求被记录,含耗时和查询体。

参考:官方文档 (opens new window)

# 1.1 慢日志是按分片记录的

一条查询会在它命中的每个分片上各记一条慢日志。这意味着:

  • 一条聚合查询命中 5 个主分片 → 5 条慢日志
  • 10 个副本分片也参与了查询 → 可能更多

直接数日志行数得出的 "QPS" 会被严重高估。读慢日志时要按 took 和查询体聚合去重,不要把分片日志当成查询日志。

# 1.2 写入慢日志(indexing.slowlog)

上述配置中的 index.indexing.slowlog.* 控制的是写入(索引)的慢日志:

  • index.indexing.slowlog.threshold.index.*:写入耗时阈值
  • index.indexing.slowlog.source:控制记录多少字节的原始文档
    • 默认 1000 字节
    • 设 false 关闭
    • 设 true 全量(文档体积大时会显著放大日志量)

# 1.3 慢日志级别与输出位置

慢日志走独立的 log4j2 appender,文件名形如 <cluster>_index_search_slowlog.log,与主日志分离。

  • 阈值设为 -1 表示关闭该级别
  • 这些是 index-level dynamic setting,可以只对某个索引开启,而不是 /_all

排查单索引问题时,只对该索引设阈值,避免全集群日志暴涨:

PUT /my-problem-index/_settings
{
  "index.search.slowlog.threshold.query.info": "1s"
}
1
2
3
4

# 2. 慢日志不够用时:tcpdump 直接抓 HTTP 请求体

慢日志记录的是 ES 解析后的查询信息,如果你怀疑问题出在客户端拼装的原始请求(比如某个 SDK 生成了意料之外的 DSL),或者想在不改集群配置的情况下临时观察流量,直接抓包更直接:

tcpdump -A -nn -s 0 'tcp dst port 9200 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)' -i lo
1

拆解这条命令:

  • -A:以 ASCII 显示包内容,这样能直接读出 HTTP 请求体里的 JSON,而不是十六进制
  • -s 0:不截断包,抓取完整长度(默认 snaplen 可能会把长查询体截断)
  • tcp dst port 9200:只抓发往 ES HTTP 端口的包
  • (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0):这是经典的"只保留有 payload 的包"过滤表达式(IP 总长度减去 IP/TCP 头长度 ≠ 0),排除掉纯 ACK 这类空包,避免抓包结果被大量噪音淹没
  • -i lo:抓本机回环网卡;如果 ES 客户端和服务端不在同一台机器,改成对应的物理网卡名

验证:另开一个终端跑一条 curl -XGET localhost:9200/_search ...,tcpdump 的终端应该实时打印出这条请求的 HTTP 头和 JSON body。

坑:-A 模式下二进制/gzip 压缩的请求体会显示成乱码——如果客户端启用了 Content-Encoding: gzip,先临时关掉压缩再抓包,否则抓到的内容不可读。

# 2.1 tcpdump 的 8.x TLS 硬边界

Elasticsearch 8.x 默认开启 HTTP 层 TLS(xpack.security.http.ssl.enabled: true)。此时:

  • tcpdump 抓到的是加密后的 TLS 记录层数据
  • -A 显示的是不可读的密文,看不到 JSON body

此时的替代手段:

  1. 改用慢日志 trace 级别(上面 1.2 节的配置),捕捉解析后的查询
  2. 在客户端侧开 SDK 的请求日志(如 Python elasticsearch 的 debug 级别 HTTP trace)
  3. 在测试环境关闭 TLS 复现(仅限非生产环境验证)

这是排查时必须知道的一条硬边界——8.x 上 tcpdump 不能作为首选手段了。

# 2.2 落盘后用 Wireshark 分析

长会话或复杂查询的抓包结果,直接 -A 看滚动太快了。建议落盘后用 GUI 工具分析:

tcpdump -w capture.pcap -s 0 'tcp dst port 9200 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)' -i lo
1
  • -w capture.pcap:把抓包结果写入文件(二进制格式)
  • 用 Wireshark 打开后:
    • 右键 Decode As → HTTP
    • 或用 Follow → HTTP Stream 查看完整请求响应

这对 "批量 bulk 请求" 尤其有用,HTTP Stream 会把几十条小请求合并成一次 TCP 传输,能还原实际操作序列。

# 3. 两件套之外的第三件:_tasks 与 _nodes/hot_threads

慢日志告诉你"哪条查询慢",但集群卡顿时还有另外两件工具:

工具 命令 告诉你什么 适用时机
Slowlog 监控日志文件 哪条查询超过阈值、耗时多久 已知慢的查询
hot_threads GET /_nodes/hot_threads 各节点此刻卡在什么调用栈上 集群整体变慢,怀疑 CPU 或 IO 瓶颈
_tasks GET /_tasks?actions=*search&detailed 正在执行的搜索任务列表 想看当前有哪些查询在跑、跑了多久

hot_threads 示例:

GET /_nodes/hot_threads
1

输出是类似 Java stack trace 的格式,能看到各节点的最"热"线程在做什么——比如卡在 IndexSearcher.search() 是查询阶段,卡在 BytesReference 相关方法是取文档阶段。

_tasks 示例:

GET /_tasks?actions=*search&detailed=true
1

这个会列出所有正在执行的搜索任务,包括:

  • _id:任务唯一标识,可用于 cancel
  • _source:原始查询 DSL
  • running_time_in_nanos:已运行时长
  • parent_task_id:如果这是子查询,它的父任务是谁

适用时机对照:

  • 慢日志有阈值,它只能告诉你「已经过去了的慢查询」
  • 如果只想知道「此刻卡在哪」,看 hot_threads
  • 如果想 kill 掉某个正在跑的慢查询,先用 _tasks 找到 task_id,再 DELETE /_tasks/{task_id}

# 4. 可复用要点

  1. 慢查询定位优先用慢日志(结构化、按阈值分级),只有怀疑"客户端发的东西不对"时才上 tcpdump。
  2. 全量记录(阈值设 0 / long_query_time=0)是排障期间的临时手段,排查完必须改回去。
  3. tcpdump 过滤表达式的核心技巧是"排除空 payload 包",否则会被 TCP 层的 ACK 噪音淹没。
  4. 8.x 默认开启 HTTP 层 TLS,tcpdump 抓到的是密文——此时优先用慢日志 trace 级别或客户端 SDK 日志。
  5. 总是按 took 和查询体聚合慢日志去重,不要把分片日志当成查询日志。
  6. 单索引问题只对该索引开慢日志,不要全集群都来。
  7. 集群卡顿但慢日志空白时,用 hot_threads 看进程状态,用 _tasks 看当前正在跑的任务。
Agent 可直接解析的元数据块
{
  "_meta": {
    "version": "1.0",
    "article_id": "es-slowlog-tcpdump-troubleshooting",
    "scope": "Elasticsearch 6.x+",
    "last_verified": "2023-02"
  },
  "quick_start": [
    "PUT /_all/_settings 配置 search.slowlog.threshold",
    "检查 logs/<cluster>_index_search_slowlog.log",
    "tcpdump -A -nn -s 0 'tcp dst port 9200 and payload!=0' -i lo",
    "GET /_nodes/hot_threads 排查当前卡顿",
    "GET /_tasks?actions=*search&detailed 查看正在执行的任务"
  ],
  "safety_rules": [
    "阈值设 0 是临时手段,排查完必须改回",
    "按 took 聚合去重,不要把分片日志当查询日志",
    "8.x 默认 TLS 启用,tcpdump 看不到明文",
    "单索引问题只对该索引开慢日志"
  ],
  "verification": [
    "跑 curl 测试后检查 slowlog 文件",
    "tcpdump -A 确认能看到 HTTP body",
    "hot_threads 输出包含 IndexSearcher.search 等关键词"
  ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#故障复盘#Elasticsearch
上次更新: 9/8/2026

← Nginx Mirror 模块实现三套ES写入网关 ES 集群恢复太慢?三个参数加速节点/分片恢复→

最近更新
01
DeepSeek Harness 实战 05|让两个编码 Agent 共用一份长期记忆 原创
09-09
02
DeepSeek Harness 实战 04|学习笔记:从「已知限制」里读出三处设计张力 原创
09-08
03
DeepSeek Harness 实战 03|学习笔记:读 12 篇 README 拿下 dsh 的五个核心心智模型 原创
09-08
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式