1. 别急着敲命令,先把安装位置和版本定下来
Elasticsearch 这个名字在搜索、日志、可观测性这几个圈子里出现频率太高了,但真到自己动手装的时候,很多人第一步就走偏。我见过太多同事,拿到一台机器就wget一个压缩包解压,然后一路报错,从内核参数一路改到 JVM 内存,最后两个小时过去服务还没起来。ES 安装教程这类内容网上遍地都是,但大多是复制粘贴的命令清单,很少有人把"为什么这么装"讲透。这篇东西我想换个写法:从选型开始,把每一步的动机、参数的计算依据、以及我在真实环境里踩过的坑,完整地摊开讲一遍。
这篇文章适合三类人看:完全没碰过 Elasticsearch、想在自己机器上跑一个来练手的新手;需要给公司内网搭一套日志检索或者业务搜索、但对 Linux 系统调优不熟的后端同学;以及那些装完能跑、但不清楚自己配置有没有留隐患、想回头补课的人。核心关键词就三个:Elasticsearch、ES、安装教程,所有内容都围绕"怎么把它稳稳当当装起来"这件事展开,不扯远的。
1.1 三种安装路径,先想清楚你要哪一种
装 ES 大致有三条路:官方 tar 压缩包裸机部署、Docker 容器化部署、Windows 本地解压运行。这三者没有绝对优劣,关键看你拿它干什么。
如果你只是想在本机试试语法、跑几个_search请求,那 Docker 一条命令最省事,五分钟出结果,玩完docker rm一删,系统干干净净。如果是 Windows 办公电脑上做开发调试,官方提供的 zip 包解压双击 bat 就能跑,也不用装虚拟机。但如果你要部署到内网服务器、要长期跑、要调优、要考虑后续扩容成集群,那就必须走 tar 包裸机部署这条路——因为容器里跑 ES 涉及内存锁定、文件句柄、数据卷挂载、内核参数透传一堆事,出了问题排查链路太长,而裸机部署的每一个参数你都能直接看到、直接改。
还有一个容易被忽略的维度:数据要不要保留。练手环境数据扔了无所谓,生产环境的数据目录必须独立规划,坚决不能跟系统盘、日志盘挤在一起。我见过有人把path.data放在/root下面,结果磁盘写满直接把系统搞挂,ES 进程和 sshd 一起罢工。所以选路径之前,先问自己三个问题:这是练手还是长期服务?数据丢了要不要紧?后面会不会加节点?答案不同,装法完全不一样。
1.2 版本选型:7.17 还是 8.x,JDK 怎么绑
版本这件事,网上的搜索结果很容易把人带偏。有人搜elasticsearch 7.17.0下载,有人问 8.x 的新特性,还有人担心elasticsearch 9的某些功能是不是要企业版。我的建议很直接:新项目一律上 7.17 之后的 8.x 稳定版,除非你的下游组件(比如某些同步工具、某些客户端 SDK)明确不支持 8.x。
为什么强调 7.17?因为 8.0 开始 ES 默认开启了安全认证,http.port不再是裸奔的,首次启动会生成证书和一堆密钥文件。对新手来说这是"劝退点",但实际上这是好事——它逼你从一开始就把安全配好,而不是等到上线前临时抱佛脚。很多人搜elasticsearch license,担心收费问题,这里说清楚:基础功能(Basic 授权)是免费的,包括搜索、聚合、索引、基础的安全认证,个人和小团队用完全够;需要付费的是部分高级特性,你装完练手阶段根本碰不到,不用纠结。
JDK 这块有个必须记住的规则:从 7.11 版本开始,ES 的发行包里已经内置了 JDK,你不需要自己装 Java,也不建议用系统自带的 JDK 去覆盖它。官方 tar 包里有一个jdk目录,启动脚本会自动用这个。为什么这么做?因为 ES 对 JVM 版本和 GC 行为很敏感,官方绑定 JDK 是为了避免"你换了别的 JDK 导致堆外内存行为不一致"这种玄学问题。所以看到JAVA_HOME相关的报错,先别急着配环境变量,先确认你解压的包里jdk目录在不在。有人为了省硬盘空间把jdk目录删了,结果启动直接失败,这种操作千万别干。
数据库连接工具、es查询语法、es异步写入java这些热词背后反映的其实是同一件事:大家装 ES 是为了让它接业务。既然是接业务,版本就必须跟客户端对齐。Java 项目用RestHighLevelClient的老代码,配 7.x 最稳;新项目用 8.x 的ElasticsearchClient,那就装 8.x。装之前先去翻一眼你项目里的客户端依赖版本,比什么攻略都管用。
2. 系统层面的准备工作,跳过这步后面全是坑
很多教程直接从解压开始讲,这是不负责任的。ES 是个吃资源的主,它对操作系统的要求写在官方文档里,但文档写得比较散。我把这些要求归拢成两类:内核参数和用户权限。这两块没弄好,你压缩包解压得再漂亮,启动脚本跑三秒就给你甩一堆bootstrap checks failed。
先说清楚为什么要调。ES 底层用 Lucene 做索引,索引文件通过内存映射(mmap)的方式读进内存,一个索引分片会占用大量的内存映射区域,操作系统对单个进程能创建的内存映射数量是有上限的,默认值(65530)对 ES 来说远远不够,所以第一件事就是把vm.max_map_count提上去。第二件事是文件句柄和进程数限制,ES 要同时打开大量索引文件和网络连接,ulimit -n默认 1024 也不够。
这两条如果不提前配,后面启动时一定会遇到那个经典报错:max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]。看到它别慌,就是参数没调,回头补上重启即可。
2.1 内核参数与资源限制,命令和持久化都要做
临时生效和永久生效是两回事,很多人只做了临时那条,重启机器后 ES 又起不来,白白排查半天。下面这一组操作请成套执行。
# 1. 内存映射区域数量,262144 是官方建议值 sudo sysctl -w vm.max_map_count=262144 # 2. 让它永久生效,否则重启后失效 echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf # 3. 验证是否写进去了 sysctl -p | grep max_map_count文件句柄和进程数走的是limits.conf。这里有个细节:配置要同时写在/etc/security/limits.conf和/etc/security/limits.d/目录下,并且要确认pam_limits.so被加载,否则某些发行版上根本不生效。ES 官方的 systemd 服务文件里其实也带了LimitNOFILE=65535,但如果你是手动su切换用户启动,那读的就是limits.conf,两条路都得覆盖。
# /etc/security/limits.conf 追加 esuser soft nofile 65535 esuser hard nofile 65535 esuser soft nproc 4096 esuser hard nproc 4096 esuser soft memlock unlimited esuser hard memlock unlimited最后那个memlock unlimited是给内存锁定用的,跟后面bootstrap.memory_lock: true配套。如果你打算开启内存锁定(强烈建议开),这条不能不配,否则启动时会报memory locking requested for elasticsearch process but memory is not locked。
注意:改完
limits.conf后,必须重新登录该用户才会生效,su - esuser这种方式有时不会重新加载 PAM 限制,最稳的做法是退出当前会话重新ssh登录。可以用ulimit -a确认max locked memory是不是 unlimited。
2.2 目录规划、专用用户与权限
ES 有个硬性规定:不能用 root 用户启动。启动脚本里专门写了检查,一旦检测到uid=0就直接退出,报错信息是can not run elasticsearch as root。这不是官方故意为难你,而是出于安全考虑——ES 曾经爆出过远程代码执行漏洞,用 root 跑等于把整台机器交出去。
所以第一步是建一个专用系统用户,建议去掉登录 shell,减少被利用的面:
sudo useradd -r -m -s /bin/bash esuser # 确认创建成功 id esuser然后是目录规划。我的习惯是数据、日志、安装目录三者分离,并且数据目录单独挂一块盘。三个目录的分工是这样的:安装目录放程序文件,升级时整个替换掉,不影响数据;数据目录是命根子,备份策略围绕它做;日志目录会疯狂增长,必须能单独清理和轮转,不能跟数据挤在一个分区里,否则日志写满导致整个盘不可写,ES 会直接进只读模式。
sudo mkdir -p /opt/es/app /data/es/data /data/es/logs sudo chown -R esuser:esuser /opt/es /data/es sudo chmod 755 /opt/es /data/es假设你有一块独立的盘,比如/dev/sdb,那就先格式化成ext4或xfs,再挂到/data。文件系统选哪个?xfs 在大文件和高并发写入场景下表现更稳,官方也比较推荐;ext4 更通用,运维熟悉度高。这个看团队习惯,没有绝对答案,但如果是新盘、新机器,我一般直接上 xfs。
提示:
/data/es/data这个目录的属主一定要是esuser。如果你是用 root 创建的目录但没改属主,启动时会报AccessDeniedException,日志里提示无法创建nodes目录,这个报错比较容易误判成磁盘权限问题。
3. Linux 环境下的完整安装流程
准备工作做完,接下来才是真正意义上的安装。我把这一节拆成四步:下载校验、配置文件拆解、堆内存计算、启动验证。这四步里最容易出错的是第二步和第三步,因为它们涉及大量参数,而且很多参数有隐藏的联动关系。比如你改了network.host,就会触发生产模式检查,接着就要求你配discovery相关参数,一环扣一环。
先说一下下载渠道。官网elastic.co/downloads/elasticsearch页面能选版本和平台,直接复制 tar.gz 的链接用wget拉就行。一定要校验 SHA512,别嫌麻烦,压缩包损坏导致解压后文件缺失、启动报一堆莫名错误的情况我遇到过不止一次,校验一次能省你半小时。
3.1 下载、校验与解压,一步都别省
cd /opt/es # 下载(版本号按需替换) wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.13.4-linux-x86_64.tar.gz wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.13.4-linux-x86_64.tar.gz.sha512 # 校验,输出 OK 才算过 shasum -a 512 -c elasticsearch-8.13.4-linux-x86_64.tar.gz.sha512 # 解压 tar -zxvf elasticsearch-8.13.4-linux-x86_64.tar.gz # 把解压出来的目录改名为 current,方便后续升级时做软链切换 mv elasticsearch-8.13.4 current # 属主交给专用用户 chown -R esuser:esuser /opt/es/current为什么要把目录改名成current?这是为将来升级做铺垫。ES 的升级方式是下载新版本的完整包解压,然后用滚动重启逐个替换节点。如果你用current做软链指向具体版本目录,升级时只要把软链从current -> 8.13.4改成current -> 8.15.0,配置文件和数据目录都不用动,回滚也快。这个习惯在小规模部署里能省不少事。
另外提醒一句,解压完后先ls一下目录结构,重点确认三样东西:bin/elasticsearch(启动脚本)、config/elasticsearch.yml(主配置)、jdk/(内置 JDK)。这三样齐了,后面的路就顺了。
3.2 elasticsearch.yml 逐行拆解,每个参数都有它的理由
配置文件是最容易照抄抄错的地方。我不打算贴一份完整的 yml 让你复制,而是把关键参数一条条讲清楚为什么这么配,你自己再根据环境填。
第一组是身份类参数:
cluster.name: prod-search # 集群名,同一网段内集群名相同会互相发现,务必唯一 node.name: node-1 # 节点名,不配会自动生成,但配了排查问题方便cluster.name这个参数要特别小心。默认值是elasticsearch,如果你的内网里有两套 ES 集群都用默认值,且网络互通,它们会尝试组成一个集群,节点数莫名其妙变多,分片乱分配。生产环境第一件事就是把它改成有辨识度的名字,比如带上业务线或者环境后缀。
第二组是路径类参数,一定要改成前面规划好的目录:
path.data: /data/es/data path.logs: /data/es/logs不改的话,数据默认写在解压目录下的data/里,升级时一替换目录,数据就跟着没了。这是新手最容易犯的致命错误,没有之一。
第三组是网络类参数,这组参数一改就会触发"生产模式":
network.host: 0.0.0.0 # 监听所有网卡;只允许本机访问就写 127.0.0.1 http.port: 9200 # REST 接口端口 transport.port: 9300 # 节点间通信端口这里有个关键机制需要理解:ES 有两种启动模式,开发模式和生产模式。当你把network.host设成0.0.0.0这种非回环地址时,ES 认为你要对外提供服务,会启动一整套"bootstrap checks"(引导检查),任何一项不通过就直接拒绝启动。这是保护机制,防止你把一个没做安全配置的实例暴露到公网上。所以改了network.host之后,discovery那组参数也必须一起配上,这就是下一组。
第四组是集群发现参数,单节点和多节点配法不同:
# 单节点场景,最简写法 discovery.type: single-node # 多节点集群场景 discovery.seed_hosts: ["192.168.1.11:9300", "192.168.1.12:9300"] cluster.initial_master_nodes: ["node-1", "node-2", "node-3"]cluster.initial_master_nodes这个参数有个非常经典的坑:它只在集群第一次启动、还没有任何数据的时候需要。等集群形成、有了集群状态元数据之后,这个参数就应该从配置里删掉或者注释掉,否则节点重启时会报IllegalArgumentException: node is not in the initial master nodes list之类的错误。我见过有人重启节点起不来,排查了半天就是忘了删这一行。
还有一组安全相关的参数,8.x 默认就开了:
xpack.security.enabled: true xpack.security.http.ssl.enabled: true xpack.security.transport.ssl.enabled: true首次启动时 ES 会自动生成 CA 证书和节点证书,并打印elastic用户的初始密码。这个密码只打印一次,一定要立刻复制下来存好,丢了只能用bin/elasticsearch-reset-password -u elastic重置。
3.3 堆内存到底给多少,jvm.options 的计算过程
堆内存配置是 ES 安装里技术含量最高的一块,也是最能体现"懂不懂"的地方。配置文件在config/jvm.options.d/下建一个独立的.options文件最规范,比如heap.options:
-Xms16g -Xmx16g为什么两行要写成一样的值?因为堆内存动态调整会带来额外的 GC 开销和停顿,生产环境追求的是稳定,直接固定住最省心。这是第一原则。
第二原则:不超过物理内存的 50%,且不超过 31GB。
前半句好理解——ES 除了堆内存,还要用堆外内存做文件缓存、mmap 索引文件,堆外内存不够会导致频繁读磁盘,性能断崖式下跌。留一半给系统是保守但稳妥的做法。一台 64G 内存的机器,堆给 16G~24G 之间比较常见,给到 32G 就开始吃紧了。
后半句是个很多人不知道的细节:JVM 在堆内存小于 32GB 时可以启用"压缩普通对象指针"(Compressed Oops),超过这个阈值指针会变成 8 字节,反而更费内存。所以理论上堆越大越好是错的,31GB 左右是那条收益曲线的拐点。官方文档里推荐的上限就是 31GB。
具体怎么算?给你一个我常用的对照表:
| 物理内存 | 建议堆大小 | 说明 |
|---|---|---|
| 4 GB | 1 ~ 2 GB | 只够练手,索引别放多 |
| 8 GB | 4 GB | 小规模日志场景可用 |
| 16 GB | 8 GB | 单节点中等负载的常见配置 |
| 32 GB | 16 GB | 生产单节点入门档 |
| 64 GB | 24 ~ 31 GB | 再往上堆收益很低,考虑加节点 |
| 128 GB 以上 | 保持 31 GB,加节点 | 水平扩展比堆大更有效 |
提示:如果你前进方向里打算用向量检索(
dense_vector字段 + kNN 查询),堆内存和堆外内存都要比同等规模的普通搜索场景给得更宽裕,因为向量索引构建阶段的内存占用相当可观。有人抱怨es向量检索时间太长,很多时候根子不在查询语句,而在安装阶段内存就给少了。
改完堆内存别忘了bootstrap.memory_lock:
bootstrap.memory_lock: true它的作用是防止 JVM 堆被交换到磁盘(swap)上。一旦发生 swap,ES 的响应时间会从毫秒级跳到秒级,而且是间歇性的,排查起来非常折磨。开了这个参数后,还要确认limits.conf里的memlock是 unlimited(第 2.1 节配过了),否则启动会报错。如果懒得配limits.conf,用 systemd 管理服务时加LimitMEMLOCK=infinity也行,但两种方式选一种覆盖到位。
3.4 启动、看日志与首次连通性验证
配置改完,切换用户启动:
su - esuser cd /opt/es/current # 前台启动,第一遍必须前台,方便看日志 ./bin/elasticsearch第一遍一定要前台启动,不要图省事加-d。因为 8.x 首次启动会生成证书、打印elastic用户密码和 enrollment token,这些信息都在标准输出里,后台跑容易漏掉。看到控制台打出"message": "started"这类字样,说明启动成功了。
如果要用后台方式,正确姿势是:
./bin/elasticsearch -d -p /data/es/es.pid # 之后通过 pid 文件优雅停止 kill $(cat /data/es/es.pid)-p参数指定 pid 文件路径,这样 stop 的时候不用满世界ps -ef | grep elastic。直接kill -9也能停,但强烈不建议,因为 ES 有大量索引文件需要正常关闭刷盘,强杀有极小概率导致分片需要恢复,得不偿失。
启动之后立刻做连通性验证:
# 8.x 需要带认证,先带 -u 参数 curl -k -u elastic:你记下的密码 https://localhost:9200/?pretty正常返回的 JSON 里会有cluster_name、version.number、tagline这几项,看到tagline: "You Know, for Search"就说明服务活了。如果连接被拒绝,九成是network.host配成了别的地址或者启动没成功,先回去看日志。如果返回 401,是密码不对或者没带认证。如果返回 403,多半是证书指纹没确认,需要重新走一遍 enrollment 流程。
日志文件的观察也有讲究。/data/es/logs/下会有几个文件,重点看集群名.log,里面按时间顺序记录了节点启动的每一步:加载配置、初始化插件、恢复分片、加入集群。排查启动问题时,永远从日志的最后 50 行往前看,报错一定是最后抛出来的,前面那些 INFO 大多是正常的流程记录。
4. Windows 本地跑起来与 Docker 快速验证
不是所有场景都需要上服务器。做开发的时候,本机装一个 ES 来调试查询语句、验证索引结构,效率高得多。这一节讲两种快速路径:Windows 原生和 Docker 容器。这两条路的共同点是快,共同的问题是别拿来跑生产。
4.1 Windows 解压即用,以及那几个必踩的坑
Windows 上的安装简单到有点不真实:去官网下载 zip 包,解压到任意目录(路径别带中文和空格),然后双击bin\elasticsearch.bat。第一次运行会弹防火墙提示,允许就行。之后浏览器打开https://localhost:9200,会要求输入用户名密码,用户名elastic,密码在第一次启动时那个 cmd 窗口里打印出来了,翻上去找。
网上的搜索结果里windows启动elasticsearch这个关键词热度很高,说明卡在 Windows 上的人不少。我把常见坑列一下:
第一个坑是路径带空格或中文。比如解压到C:\Program Files\或者D:\我的软件\,启动脚本会因为路径解析问题直接失败。解压到D:\es\这种纯英文短路径最保险。
第二个坑是内存不够。Windows 版默认在config\jvm.options里配了-Xms1g -Xmx1g,如果你机器内存吃紧,可以在同目录下建jvm.options.d\heap.options把它改小到512m,但注意别小于 256m,否则启动会失败。
第三个坑是杀毒软件。ES 在启动时会创建大量小文件、开启大量网络监听,某些安全软件会误判为异常行为并拦截,表现为启动卡住不动。遇到这种先把实时防护关掉试试。
第四个坑是 JDK 环境变量。前面说过 ES 自带 JDK,但 Windows 上如果你系统里配了JAVA_HOME指向一个低版本 JDK,启动脚本有时会优先用它,导致版本不兼容报错。可以在启动前临时set JAVA_HOME=清掉,确认是不是这个原因。
Windows 上还容易遇到端口占用。9200 被别的程序占了怎么办?netstat -ano | findstr 9200找到 PID,再到任务管理器里结束对应的进程。如果实在腾不出来,改config\elasticsearch.yml里的http.port换成 9201 也行,但记得同步改客户端的连接地址。
4.2 Docker 一条命令拉起单节点
Docker 路线的核心优势是环境隔离,装坏了删容器重来,不会污染宿主机。适合 CI 环境、临时验证、教学演示。
docker run -d \ --name es-single \ -p 9200:9200 \ -p 9300:9300 \ -e "discovery.type=single-node" \ -e "ES_JAVA_OPTS=-Xms1g -Xmx1g" \ -e "xpack.security.enabled=false" \ -v es-data:/usr/share/elasticsearch/data \ docker.elastic.co/elasticsearch/elasticsearch:8.13.4几个参数说明一下。discovery.type=single-node是告诉它这是单节点,跳过引导检查里关于集群发现的要求,否则容器起不来。ES_JAVA_OPTS覆盖堆内存,容器环境建议显式指定,不然它会用默认值在内存小的机器上出事。xpack.security.enabled=false是关掉认证,方便本地调试——这一条在能连公网的机器上千万别开,等于把服务裸奔在互联网上。数据卷es-data挂出来是为了容器删除后数据还在,命名卷比绑定挂载省事,Docker 自己管路径。
这里有个必须强调的点:Docker 里的 ES 依然受宿主机内核参数约束。vm.max_map_count是宿主机级别的,容器内改不了。所以即使你用了 Docker,第 2.1 节那个内核参数照样要在宿主机上配。很多人第一次用 Docker 跑 ES 就卡在这一步,容器反复重启,日志里还是那句max virtual memory areas vm.max_map_count [65530] is too low。
另外,docker desktop在 Windows 和 Mac 上是通过虚拟机跑的,实际的内核参数要在 Docker Desktop 的设置里或者它背后的虚拟机里调。Mac 上比较麻烦,一般用 Docker Desktop 自带的配置界面调资源限制,内核参数得进它的虚拟机里改。这也是为什么我前面说练手可以、生产别用容器。
4.3 从单机到三节点小集群
练手单节点够用,但只要你想验证副本分配、故障转移、跨节点查询这些行为,单节点是看不出问题的——因为单节点上的副本分片永远分配不出去,集群状态会一直是 yellow。这不是配置错了,是物理上没有第二台机器放副本。想看到 green,至少三节点。
三节点的最小配置,每个节点的elasticsearch.yml大致这样(以 node-1 为例):
cluster.name: dev-cluster node.name: node-1 node.roles: [master, data, ingest] path.data: /data/es/data path.logs: /data/es/logs network.host: 192.168.1.11 http.port: 9200 transport.port: 9300 discovery.seed_hosts: ["192.168.1.11:9300", "192.168.1.12:9300", "192.168.1.13:9300"] cluster.initial_master_nodes: ["node-1", "node-2", "node-3"] bootstrap.memory_lock: truenode.roles这个参数值得展开说。ES 7.9 之后引入了节点的角色分离,master角色负责集群状态管理,data负责存数据,ingest负责预处理管道。小集群里一般三个角色都留,但如果集群规模上去了,强烈建议把 master 角色单独拆出来做专属 master 节点,因为数据节点压力大的时候会影响集群状态更新的响应速度,进而让整个集群不稳定。
节点启动顺序上,我的经验是先把所有 master-eligible 节点同时启动,等集群形成后再启>curl -k -u elastic:密码 "https://192.168.1.11:9200/_cluster/health?pretty" 返回里的 服务起来了不等于可以交付了。我见过太多案例:ES 装完丢在内网,没有任何认证,半年后被人拿走数据。8.x 虽然默认开了安全,但很多人图省事在配置里给它关掉了,这个习惯非常危险。这一节讲两块:安全配置怎么配、系统层面的稳定性开关怎么开。 如果你装的是 8.x 且没关安全,那么默认就是开着的,证书和密码在首次启动时已经生成了。要做的事情是把这套证书和凭据管理起来,而不是每次启动重新生成。 关于证书,简单说清楚它的组成:ES 用一套 CA 签发的证书链, 密码这块,有几个内置用户要记住: 角色也要按需建,不要图省事给 如果你是 7.x,或者手动把 8.x 的安全关了,那就要手动开启: 然后用 注意: 这一节讲的是稳定性开关,配了之后 ES 在高负载下不容易雪崩。 交换分区这块,最彻底的做法是让 ES 完全不用 swap。前面配的 熔断器是 ES 的自我保护机制。它监控 JVM 堆内存的使用量,当某个操作(比如一个巨大的聚合查询)占用的内存超过阈值时,主动抛异常拒绝,避免整个节点 OOM。默认阈值是 95%,通常不用改,但如果你想更保守,可以在 磁盘水位也要配。ES 默认在磁盘使用超过 85% 时不再往该节点分配新分片,超过 90% 时尝试把分片挪走,超过 95% 时索引变成只读。对小容量磁盘来说这套默认值偏激进,可以调: 但调阈值只是缓解,不是解决。真正的解法是加盘或者清理旧索引,用 ILM(索引生命周期管理)策略自动滚动删除。见过有人把 装完、配完,最后一步是验收。验收不是打开浏览器看到页面就完事,而是要有几个明确的检查项,确认这个实例真的能扛事。我整理了一份自检清单和一张报错速查表,你照着走一遍,基本能覆盖 90% 的初期问题。 第一步,查集群健康。用 第二步,查节点信息。用 第三步,写入读取闭环测试。别只看健康状态,实际建个索引写几条数据再查出来: 走通这套,说明写链路和读链路都正常。测完记得把 第四步,压一下。不用专业压测工具,用 第五步,重启一次。这一条最容易被跳过,但价值最高。很多配置错误只有在重启后才会暴露,比如前面提到的 下面这张表是我这些年遇到频率最高的报错,按出现概率从高到低排。 这张表建议存下来,遇到报错先搜关键词对上,能省下大量搜索时间。 提示:遇到不认识的报错,最快的路径不是搜索引擎,而是先看日志里紧挨着报错的那几行 WARN。ES 的日志设计得很好,最终的 ERROR 往往只是结果,真正的原因藏在它前面几行的 WARN 里。比如分片分配失败,ERROR 只说失败,但前面会有一条 WARN 写清楚"因为磁盘水位超过阈值所以拒绝分配"。 前面讲的都是"应该怎么做",这一节讲我实际遇到的那些计划外的事,算是给这份安装教程打个补丁。 第一个坑跟时间有关。有次在三台机器上装集群,配置文件一模一样,但 node-3 死活加不进去,日志显示它不断重试加入但每次都被拒绝。排查了一个多小时才发现是那台机器的时间比另外两台慢了四分钟,导致集群选主时的任期判断出问题。集群对时间同步的要求比想象中高,现在我做任何集群部署,第一件事就是 第二个坑跟磁盘有关。有个环境用的是云主机,数据盘是网络存储,我给 第三个坑跟内存锁定有关。配了 第四个坑跟升级有关。用软链方式部署之后升级,新版本二进制替换了,但配置文件没注意对比,新版增加了一些新的必填项,启动时报 第五个坑跟 JVM 参数有关。有一次为了省内存,把堆调到 512m 跑一个日志场景,前面几个月都正常,数据量涨上去之后开始频繁 Full GC,服务每隔几小时就卡顿几十秒。查 最后分享一个小习惯。每次装完 ES,我都会在number_of_nodes应该是 3,status应该是green。如果还是yellow,用_cluster/allocation/explain接口查一下分片为什么没分配,通常会给出很具体的原因,比如磁盘水位超限、节点角色不匹配等。5. 装完不等于能用:安全配置与生产必做项
5.1 开启账号密码与传输加密
config/certs/下会生成ca.crt、ca.key、节点的http.crt/http.key、transport.crt/transport.key。ca.key是私钥,权限要收紧,绝对不能外传;ca.crt是公钥证书,客户端连接时需要它来做校验。生产环境里建议用公司统一的 CA 重新签发一套,方便证书轮换和集中管理。elastic是超级用户,权限最大也最危险,日常操作不要直接用它,而是建一个业务专用账号,授予最小必要权限。创建用户的接口是_security/user/,可以用 Kibana 的界面点,也可以直接调 API:curl -k -u elastic:密码 -X POST "https://localhost:9200/_security/user/app_user" \ -H 'Content-Type: application/json' -d ' { "password": "换个强密码", "roles": ["app_read_write"], "full_name": "业务写入账号" }'superuser。最小权限原则在 ES 里尤其重要,因为一个索引的写权限就足够覆盖掉全部数据了。xpack.security.enabled: true xpack.security.transport.ssl.enabled: true xpack.security.transport.ssl.verification_mode: certificate xpack.security.transport.ssl.keystore.path: certs/elastic-certificates.p12 xpack.security.http.ssl.enabled: true xpack.security.http.ssl.keystore.path: certs/http.p12bin/elasticsearch-certutil生成证书,用bin/elasticsearch-setup-passwords interactive交互式设置所有内置用户的密码。整个过程稍微繁琐,但比裸奔强一万倍。transport.ssl.verification_mode如果设成none会跳过证书校验,虽然能连通但等于放弃了加密的意义,生产环境必须用certificate或full。这个参数是很多"连不上集群"问题的元凶——排查时临时改成none能通、改回来不通,就说明证书配错了。5.2 内存锁定、交换分区与熔断器
bootstrap.memory_lock: true锁住了 JVM 堆,但堆外内存还是可能被换出去。更激进的做法是把宿主机的 swap 关掉,或者把vm.swappiness调到 1:echo "vm.swappiness=1" | sudo tee -a /etc/sysctl.conf sudo sysctl -pswappiness是 0~100 的值,越大越倾向于换出内存。设成 1 的意思是"除非万不得已,否则别换"。不要设成 0,因为在内存真正见底的时候,完全不换出可能导致 OOM Killer 直接杀掉进程,比慢一点更糟。elasticsearch.yml里调:indices.breaker.total.limit: 70% indices.breaker.fielddata.limit: 40% indices.breaker.request.limit: 40%cluster.routing.allocation.disk.watermark.low: 80% cluster.routing.allocation.disk.watermark.high: 90% cluster.routing.allocation.disk.watermark.flood_stage: 95%flood_stage调到 98%,结果磁盘还剩 2% 的时候 ES 疯狂报错,系统盘也满了,最后只能强制删数据救场。6. 上线前的验证清单与故障速查
6.1 五步健康自检
_cluster/health接口,重点看status是不是 green、number_of_nodes对不对、unassigned_shards是不是 0。yellow 在单节点上是正常的,多节点上出现 yellow 就要查原因。_nodes/stats看几个关键指标:jvm.mem.heap_used_percent是否长期高于 75%(高于说明堆偏小)、indices.fielddata.memory_size_in_bytes是不是很大(大说明有聚合在滥用 fielddata)、fs.total.available_in_bytes磁盘剩余。这些指标看一眼心里就有数了。curl -k -u elastic:密码 -X PUT "https://localhost:9200/test_idx" -H 'Content-Type: application/json' -d ' { "settings": { "number_of_shards": 1, "number_of_replicas": 0 } }' curl -k -u elastic:密码 -X POST "https://localhost:9200/test_idx/_doc/1" -H 'Content-Type: application/json' -d ' { "title": "hello es", "ts": "2024-01-01" }' curl -k -u elastic:密码 "https://localhost:9200/test_idx/_search?q=hello&pretty"test_idx删掉,别留在生产环境里。curl循环发几百个请求看响应时间也行。重点观察有没有明显抖动——如果响应时间忽快忽慢,大概率是 swap 没关干净,回去查_nodes/stats里的jvm.mem.pools和系统的free -h。cluster.initial_master_nodes没删、limits.conf没生效、挂载点没配好自动挂载。重启一遍全部走通,才算真的验收通过。6.2 常见报错速查表
报错信息关键词 根本原因 处理方式 can not run elasticsearch as root用 root 启动了 切换到专用用户,或用 --user方式启动max virtual memory areas vm.max_map_count [65530] is too low内核参数没配或没生效 sysctl -w vm.max_map_count=262144并写入/etc/sysctl.confmax file descriptors [4096] for elasticsearch process is too low句柄限制没生效 配 limits.conf,重新登录用户使配置生效the default discovery settings are unsuitable for production use改了 network.host但没配 discovery单节点加 discovery.type: single-node,集群配seed_hosts和initial_master_nodesmemory locking requested for elasticsearch process but memory is not locked开了 bootstrap.memory_lock但 memlock 限制没放开limits.conf加memlock unlimited,或 systemd 加LimitMEMLOCK=infinitynode is not in the initial master nodes list集群已成型后还留着 initial_master_nodes注释掉该参数再启动 java.lang.OutOfMemoryError: Java heap space堆内存给小了 调 jvm.options.d里的-Xms/-XmxAccessDeniedException: /data/es/data/nodes数据目录属主不对 chown -R esuser:esuser /data/esPort 9200 already in use端口被占用 `ss -lntp cluster status is RED有主分片未分配 _cluster/allocation/explain查具体原因,常见是磁盘水位或节点掉线index is read-only, disk watermark exceeded磁盘超过 flood_stage清理磁盘后调 _settings解除只读,长期靠 ILM 策略控制7. 我在实际安装中踩过的那些坑
chronyc sources确认时间源正常,比什么都管用。path.data指过去之后发现写入性能极差,索引速度只有本地盘的十分之一。原因是网络存储的 IOPS 和延迟跟本地 SSD 完全不是一个量级,而 ES 对磁盘延迟极其敏感。结论就是:ES 的数据盘必须用本地 SSD,网络盘只能用来放备份。这个教训我后来写进了所有部署文档的首页。bootstrap.memory_lock: true,limits.conf也改了,ulimit -a看max locked memory确实是 unlimited,但启动还是报内存锁定失败。最后发现是用的 systemd 启动服务,而 systemd 服务有自己独立的一套LimitXXX配置,它不走limits.conf,需要在 service 文件里单独加LimitMEMLOCK=infinity。这个坑很隐蔽,因为手动su启动是好的,用 systemd 就失败,容易让人以为是配置写错了。unknown setting。教训是升级前一定要把新旧版本的elasticsearch.yml拿 diff 工具过一遍,尤其是大版本升级,很多参数被废弃或者改名了,照搬旧配置会出问题。jvm.mem.heap_used_percent发现长期在 80% 以上。堆内存的配置要留出余量,按当前数据量的两到三倍估,别按刚好够用来算。后来把堆提到 4G,问题立刻消失。config/目录下放一个README.md,写上这次部署的关键信息:版本号、部署日期、数据目录路径、证书位置、管理员密码的存放位置(不写密码本身)、以及这份配置对应的是哪套环境。几个月后回头看,这份随手写的记录能帮你省下大量翻文档的时间。装 ES 这件事,命令本身不难,难的是把一堆看起来无关的参数串成一套能长期稳定运行的配置。