当前位置: 首页 > ai >正文

Elasticsearch 启动反复重启排查实录:从“内存不足”到“vm.max\_map\_count 过小”

这是一篇按实际故障排查顺序整理的笔记,覆盖症状 → 定位 → 根因 → 解决 → 验证 → 最佳实践,同时给出 systemd 与 Docker 两套可复制命令及一键脚本。


一、环境信息(按现场日志复盘)

  • Elasticsearch:7.15.0(Docker 镜像,bundled JDK)

  • JVM:OpenJDK 16.0.2(日志显示 JVM arguments ... -Xms16062m -Xmx16062m

  • 内核 & 架构:Linux 4.14,aarch64

  • 集群/节点:cluster.name=es-cluster,node.name=es2

  • 可用内存概览(现场输出):

    free -htotal        used        free      shared  buff/cache   available
    Mem:            47G         32G        3.6G        2.4G         11G        5.7G
    Swap:            0B          0B          0B
    
  • 关键报错 1(JVM 内存申请失败)

    There is insufficient memory for the Java Runtime Environment to continue.
    Native memory allocation (mmap) failed to map 12884901888 bytes for committing reserved memory.
    error='Not enough space' (errno=12)
    
  • 关键报错 2(Bootstrap check 未通过)

    bootstrap check failure [1] of [1]: max virtual memory areas vm.max_map_count [65530] is too low,
    increase to at least [262144]
    

二、问题现象

  1. 节点 es2 启动过程中反复退出重启。
  2. 初期日志显示 JVM 需一次性映射 ~12GB 内存 失败(errno=12),同时机器 无 swap
  3. 随后日志显示通过一段初始化后 Bootstrap Checks 失败,因 vm.max_map_count 过小(65530 < 262144)。

三、快速结论

  • 阶段一根因:JVM 初始堆或直接内存等配置偏大 + 无 swap/连续内存不足 → mmap 失败。
  • 阶段二根因:系统参数 vm.max_map_count 低于 Elasticsearch 启动要求 → Bootstrap Checks 拦截 → 进程退出 → 容器/服务反复重启。

两个问题互相独立:先解决内存分配问题能让 ES 走到后续引导检查;再把内核参数调到位才能稳定起来。


四、定位思路与要点

1)从日志抓关键线索

  • 看到 mmap failed ... 12884901888 byteserrno=12 Not enough space,说明 不是磁盘空间,而是 无法获取足够大的连续虚拟内存
  • 配合 free -h 发现 Swap 为 0,物理内存还有余量但不连续,JVM 预触碰(-XX:+AlwaysPreTouch)+ G1 Region 分配需要较大连续空间;
  • 再看 JVM 启动参数:-Xms16062m -Xmx16062m,堆初始即 15.7GB;在容器或内存紧张场景容易失败;
  • 后续日志提示 vm.max_map_count 过小,属于 Elasticsearch 的强制启动检查

2)为什么 available 还有 5.7G 也会失败?

  • JVM 需要一整块连续虚拟内存 来 commit 预留空间;
  • 内存碎片化 + 无 swap 时,内核更难为大块映射腾挪空间;
  • Docker/K8s 限制(如 -m)若存在,也会导致映射失败。

五、解决方案(按顺序执行)

建议先确保 JVM 内存设置与宿主机/容器限制匹配,再处理 内核参数,最后统一验证。

方案 A:下调 JVM 堆/直接内存(首选快速解法)

1. systemd 部署

编辑 jvm.options(常见路径 /etc/elasticsearch/jvm.options 或安装目录下 config/jvm.options):

# 将初始堆和最大堆设置为合理值,例如 4G(按物理内存的一半以内)
-Xms4g
-Xmx4g

经验:堆大小不超过物理内存的一半,并且不超过 30~31GB(超过大约 32GB 会失去 Compressed Oops,指针膨胀导致性能下降)。

重启服务:

systemctl restart elasticsearch
2. Docker 部署
  • 使用环境变量覆盖 JVM:
# docker run 示例
docker run -d --name es \-e ES_JAVA_OPTS="-Xms4g -Xmx4g" \-p 9200:9200 -p 9300:9300 \elasticsearch:7.15.0
  • docker-compose:
environment:- ES_JAVA_OPTS=-Xms4g -Xmx4g

若使用了 -m/--memorymem_limit 等容器内存限制,请确保 容器可用内存 > Xmx,通常至少预留 1~2GB 额外空间给非堆/直接内存/线程栈等。

方案 B:为宿主机添加 Swap(当确需较大堆或内存紧张时)

# 创建 16G 的 swap 文件(按需调整)
dd if=/dev/zero of=/swapfile bs=1G count=16
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile# 开机自启
echo '/swapfile none swap sw 0 0' >> /etc/fstab# 验证
free -h
swapon --show

性能敏感业务可适当调低 vm.swappiness(例如 1~10),避免频繁换页:

sysctl -w vm.swappiness=10
sed -i '$a vm.swappiness=10' /etc/sysctl.conf

方案 C:通过内核参数通过 Bootstrap Checks(必做)

ES 在绑定非本地地址时会开启 Bootstrap Checks,vm.max_map_count 必须 ≥ 262144。

1. systemd/物理机
# 临时生效(立即修复)
sysctl -w vm.max_map_count=262144# 永久生效(写入配置并加载)
echo 'vm.max_map_count=262144' >> /etc/sysctl.conf
sysctl -p
2. Docker / docker-compose
  • 宿主机先设置(容器内设置无效):
sysctl -w vm.max_map_count=262144
  • docker-compose(可选补充,便于编排记录):
sysctls:- vm.max_map_count=262144
  • 重新创建或启动容器:
docker-compose down && docker-compose up -d
# 或
docker stop es && docker rm es
docker run -d --name es \--sysctl vm.max_map_count=262144 \-e ES_JAVA_OPTS="-Xms4g -Xmx4g" \-p 9200:9200 -p 9300:9300 \elasticsearch:7.15.0

六、验证与健康检查

# 1) 核心内核参数
sysctl vm.max_map_count
# 期望:vm.max_map_count = 262144# 2) 内存与 swap
free -h
swapon --show# 3) 容器资源限制(如使用 Docker)
docker inspect es | egrep -i 'Memory|NanoCpus'# 4) ES 进程与监听端口
ss -lntp | egrep '9200|9300'# 5) 集群健康(需启用 9200)
curl -s http://127.0.0.1:9200/_cluster/health?pretty# 6) 查看最近错误日志
# systemd:
journalctl -u elasticsearch -n 200 --no-pager
# Docker:
docker logs es --tail=200

七、最佳实践与避坑指南

  1. 合理的堆内存Xms=Xmx,一般为物理内存的一半以内,上限 30~31GB

  2. 预留额外内存:堆外(直接内存、页缓存、线程栈、Lucene 结构)也吃内存;容器限制需预留余量。

  3. Swap 合理有益:线上不等于禁止 swap;适度 swap + 低 vm.swappiness 可以提升稳定性,避免突发 OOM。

  4. vm.max_map_count 与映射:索引分段与 mmap 文件较多,262144 是官方最低建议,节点高并发场景可适当再高一些。

  5. 透明大页(THP):延迟敏感可以考虑关闭以减少抖动:

    echo never > /sys/kernel/mm/transparent_hugepage/enabled
    echo never > /sys/kernel/mm/transparent_hugepage/defrag
    # 开机加入 rc.local 或 systemd unit
    
  6. 观察 GC 与段合并:定期检查 logs/gc.log_cat/segments,及时做 ILM/索引生命周期管理,控制段数量与内存占用。


八、一键修复脚本

两套脚本仅对常见场景做“安全默认值”处理:设置 vm.max_map_count,若无 swap 则创建 8G,且将 JVM 堆调整为 4G(可按需修改)。

1)systemd 部署一键脚本

cat > /tmp/fix_es_systemd.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail# === 1. 调整 vm.max_map_count ===
echo "[+] set vm.max_map_count=262144"
sysctl -w vm.max_map_count=262144 >/dev/null
if ! grep -q '^vm.max_map_count=262144' /etc/sysctl.conf 2>/dev/null; thenecho 'vm.max_map_count=262144' >> /etc/sysctl.conf
fi
sysctl -p >/dev/null# === 2. 若无 swap 则创建 8G swap ===
if [ "$(swapon --noheadings | wc -l)" -eq 0 ]; thenecho "[+] create 8G swap at /swapfile"dd if=/dev/zero of=/swapfile bs=1G count=8 status=progresschmod 600 /swapfilemkswap /swapfileswapon /swapfileif ! grep -q '^/swapfile' /etc/fstab; thenecho '/swapfile none swap sw 0 0' >> /etc/fstabfi
fi# === 3. 降低 vm.swappiness(可选) ===
if ! grep -q '^vm.swappiness=' /etc/sysctl.conf; thenecho 'vm.swappiness=10' >> /etc/sysctl.confsysctl -w vm.swappiness=10 >/dev/null
fi# === 4. 调整 JVM 堆(若>8g则改为4g) ===
JVM_OPTS_FILE="/etc/elasticsearch/jvm.options"
if [ -f "$JVM_OPTS_FILE" ]; thenXMX=$(grep -E '^\-Xmx' "$JVM_OPTS_FILE" | head -n1 | sed 's/[^0-9]//g' || true)if [ -n "$XMX" ] && [ "$XMX" -gt 8000 ]; thenecho "[+] tune heap to 4g in $JVM_OPTS_FILE"sed -ri 's/^(-Xms)(.*)$/\14g/' "$JVM_OPTS_FILE"sed -ri 's/^(-Xmx)(.*)$/\14g/' "$JVM_OPTS_FILE"fi
fi# === 5. 重启服务 ===
echo "[+] restart elasticsearch"
systemctl restart elasticsearch || true
sleep 2
systemctl --no-pager -l status elasticsearch || trueecho "[DONE]"
EOFchmod +x /tmp/fix_es_systemd.sh
bash /tmp/fix_es_systemd.sh

2)Docker 部署一键脚本(容器名假设为 es

cat > /tmp/fix_es_docker.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail# === 1. 宿主机内核参数 ===
echo "[+] set vm.max_map_count=262144"
sysctl -w vm.max_map_count=262144 >/dev/null
if ! grep -q '^vm.max_map_count=262144' /etc/sysctl.conf 2>/dev/null; thenecho 'vm.max_map_count=262144' >> /etc/sysctl.conf
fi
sysctl -p >/dev/null# === 2. 若无 swap 则创建 8G swap ===
if [ "$(swapon --noheadings | wc -l)" -eq 0 ]; thenecho "[+] create 8G swap at /swapfile"dd if=/dev/zero of=/swapfile bs=1G count=8 status=progresschmod 600 /swapfilemkswap /swapfileswapon /swapfileif ! grep -q '^/swapfile' /etc/fstab; thenecho '/swapfile none swap sw 0 0' >> /etc/fstabfi
fi# === 3. 重建容器,指定合理堆与 sysctl ===
CN=${1:-es}
if docker ps -a --format '{{.Names}}' | grep -qx "$CN"; thenecho "[+] recreate container: $CN"IMAGE=$(docker inspect -f '{{.Config.Image}}' "$CN")docker stop "$CN" || truedocker rm "$CN" || truedocker run -d --name "$CN" \--restart=always \--sysctl vm.max_map_count=262144 \-e ES_JAVA_OPTS="-Xms4g -Xmx4g" \-p 9200:9200 -p 9300:9300 \"$IMAGE"
elseecho "[i] container $CN not found, skip recreate"
fi# === 4. 健康检查 ===
sleep 5
docker logs "$CN" --tail=200 || trueecho "[DONE]"
EOFchmod +x /tmp/fix_es_docker.sh
bash /tmp/fix_es_docker.sh es

提示:如需保留原容器的数据与配置,请补充 -v 卷挂载参数与原容器一致;生产环境建议使用 docker-compose 管理。


九、最终结果

  • 通过下调 JVM 堆或添加 swap,消除了 mmap 失败
  • 通过将 vm.max_map_count 提升到 262144,通过了 Bootstrap Checks
  • 节点 es2 正常启动,集群恢复服务。

十、附:快速自检清单(复制即用)

# 1) JVM 参数与堆大小
jcmd $(pgrep -f Elasticsearch | head -n1) VM.flags 2>/dev/null | head -n5 || true# 2) 内存 & swap
free -h && swapon --show# 3) 内核参数
sysctl vm.max_map_count# 4) 容器限制
[ -x "$(command -v docker)" ] && docker inspect es | egrep -i 'Memory|NanoCpus' || true# 5) ES 健康
curl -s http://127.0.0.1:9200/_cluster/health?pretty || true# 6) 最近错误
journalctl -u elasticsearch -n 200 --no-pager 2>/dev/null || docker logs es --tail=200 || true

http://www.xdnf.cn/news/18865.html

相关文章:

  • 力扣hot100:字母异位词分组和最长连续序列(49,128)
  • 【重学 MySQL】九十、Linux下MySQL的安装与卸载指南
  • Go 1.25新特性之容器感知功能详解
  • 嵌入式C语言进阶:位操作的艺术与实战
  • 8.27 网格memo
  • STM32 入门实录:从 0 到 3 色 LED 呼吸式闪烁
  • 【C++】菱形继承深度解析+实际内存分布
  • 2025.8.27链表_链表逆置
  • 科技赋能生态,智慧守护农林,汇岭生态开启农林产业现代化新篇章
  • TensorFlow 面试题及详细答案 120道(21-30)-- 模型构建与神经网络
  • 斯塔克工业技术日志:用基础模型打造 “战甲级” 结构化 AI 功能
  • uniapp H5禁止微信浏览器长按出菜单,只针对图片
  • 全球首款Al勒索软件PromptLock:跨平台攻击新威胁, Windows/macOs/Linux均受影响
  • 【生产事故处理--kafka日志策略保留】
  • 深入解析达梦数据库:模式分类、状态管理与实操指南
  • 【数据分享】安徽省安庆市地理基础数据(道路、水系、铁路、行政边界(含乡镇)、DEM等)
  • 如何用Renix实现网络测试自动化: 从配置分离到多厂商设备支持
  • WebConfig的登录与放行
  • 对比视频处理单元(VPU)、图形处理器(GPU)与中央处理器(CPU)
  • 前端-从零开始在本机部署一个前端项目
  • 流程控制语句(1)
  • Dify 从入门到精通(第 59/100 篇):Dify 的自动化测试(进阶篇)
  • 野火STM32Modbus主机读取寄存器/线圈失败(一)-解决接收中断不触发的问题
  • 嵌入式-定时器的时基单元,自制延迟函数-Day21
  • AI驱动的前端性能优化:从监控到自动化修复
  • C# 字符和字符串
  • 《信息检索与论文写作》实验报告三 中文期刊文献检索
  • 【算法速成课1 | 题解】洛谷P3366 【模板】最小生成树 MST(Prim Kruskal)
  • GitHub 宕机自救指南:保障开发工作连续性
  • Android中点击链接跳转到对应App页面的底层原理