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

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.dtcms.com/a/353428.html

相关文章:

  • 图表可视化地理趋势-Telerik WPF Chart
  • 智能汽车制造:海康NVR管理平台/工具EasyNVR多品牌NVR管理工具/设备实现无插件视频监控直播方案
  • R语言贝叶斯方法在生态环境领域中的技术应用
  • 攻克 Java 分布式难题:并发模型优化与分布式事务处理实战指南
  • APP与WEB测试的区别?
  • 人工智能在医疗领域中辅助外科手术的应用综述
  • 【VSCode】使用VSCode创建Java C/S架构项目
  • 如何用Renix实现网络测试自动化: 从配置分离到多厂商设备支持
  • 【网络编程】NtyCo协程服务器的框架(轻量级的协程方案,人称 “小线程”)
  • 从浏览器无法访问到Docker容器的 FastAPI 服务地址【宿主机浏览器和容器不在同一个网络层面:端口映射】
  • 前端AI应用实践指南:从基础概念到高级实现
  • 云手机的未来发展怎么样?
  • 数据结构(C语言篇):(二)顺序表
  • 状态设计模式
  • 手机冻结技术发展时间轴
  • Flutter项目详解
  • 深度学习实战117-各种大模型(Qwen,MathGPT,Deepseek等)解高考数学题的应用,介绍架构原理
  • C++工程实战入门笔记6-函数(三)关于base16编码的原理和函数模块化实战
  • LINUX --- 网络编程(二)
  • OpenAi在中国拿下“GPT”商标初审!
  • October 2019 Twice SQL Injection
  • Qt图片上传系统的设计与实现:从客户端到服务器的完整方案
  • 对比视频处理单元(VPU)、图形处理器(GPU)与中央处理器(CPU)
  • 多模态模型如何处理和理解图片
  • PPT处理控件Aspose.Slides教程:在.NET中开发SVG到EMF的转换器
  • STM32学习日记
  • 替身演员的艺术:pytest-mock 从入门到飙戏
  • Java基础 8.27
  • 如何使用windows实现与iphone的隔空投送(AirDrop)
  • 【Docker基础】Docker-compose数据持久化与卷管理:深入解析docker volume命令集