手把手教你搭建高可用 Elasticsearch 多节点集群:从零部署到生产级调优
你是不是也遇到过这种情况——项目上线在即,日志量猛增,单机版 Elasticsearch 刚跑两天就卡得不行?主节点宕机后整个搜索服务直接“躺平”?分片分配失败、节点连不上、堆内存溢出……各种报错满屏飞?
别急。这些坑我都踩过。
今天我就以一个实战派工程师的身份,带你完整走一遍多节点 ES 集群的搭建全过程。不是照搬文档,而是把那些官方不会明说但实际必踩的“暗坑”,全都摊开讲清楚。
我们不谈虚的,只讲能落地的:怎么装、怎么配、怎么调、怎么查问题。目标只有一个:让你亲手搭出一个稳定、可扩展、真正能扛住生产压力的 ES 集群。
为什么不能只用单节点?
先泼一盆冷水:单节点 ES 根本不适合任何严肃场景。
它就像一辆没有备胎的车——一旦爆胎,寸步难行。
Elasticsearch 的核心价值在于“分布式”。它的数据是按分片(shard)分布的,每个主分片可以有多个副本。当某个节点挂了,副本能自动顶上,继续提供服务。这个能力,只有在多节点集群中才能体现出来。
而且,主节点(master node)负责管理集群状态、调度分片、处理元数据变更。如果这个角色和数据存储混在一起,写入压力一大,主节点一卡,整个集群都会陷入“假死”。
所以,哪怕你现在只是做测试环境,也建议至少上三节点。这不是过度设计,而是为未来留活路。
我们要建一个什么样的集群?
假设我们现在有三台服务器:
| 节点 | IP 地址 | 角色规划 |
|---|---|---|
| es01 | 192.168.1.10 | master + data + ingest |
| es02 | 192.168.1.11 | master + data |
| es03 | 192.168.1.12 | data + ingest |
注:生产环境中建议将master 节点与 data 节点物理分离,避免资源争抢。这里为了简化演示,允许部分节点兼任。
我们的目标是让这三个节点组成一个名为prod-cluster的高可用集群,支持自动发现、故障转移,并具备基本的安全防护能力。
第一步:环境准备 —— 别跳过这一步,90%的问题都出在这儿
1. 系统要求确认
- 操作系统:Linux(CentOS 7+/Ubuntu 20.04+)
- Java 版本:JDK 17(ES 8.x 强制要求,别再用 JDK 8!)
- 内存:每台机器 ≥16GB(建议 32GB)
- 文件句柄数:≥65536
- 虚拟内存映射数:
vm.max_map_count ≥ 262144
⚠️ 特别提醒:最后一个参数很多人忽略,结果启动时报错
max virtual memory areas vm.max_map_count [65530] is too low,然后一脸懵。
解决办法:
# 修改系统配置 echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf sudo sysctl -p # 设置文件描述符限制 echo 'elasticsearch soft nofile 65536' | sudo tee -a /etc/security/limits.conf echo 'elasticsearch hard nofile 65536' | sudo tee -a /etc/security/limits.conf echo 'elasticsearch soft nproc 4096' | sudo tee -a /etc/security/limits.conf记得重启会话或重新登录生效。
2. 关闭 swap
ES 明确建议关闭交换分区。因为 JVM 已经做了内存管理,一旦触发 swap,性能暴跌不说,还可能导致 GC 停顿飙升。
sudo swapoff -a # 并注释掉 /etc/fstab 中的 swap 行3. 创建专用用户运行服务
不要用 root 启动 ES!
sudo useradd elasticsearch -m -s /bin/bash sudo passwd elasticsearch后续所有操作尽量切换到该用户执行。
第二步:安装 Elasticsearch(以 tar.gz 方式为例)
去官网下载对应版本的包(推荐 LTS 版本如 8.11):
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.11.0-linux-x86_64.tar.gz tar -xzf elasticsearch-8.11.0-linux-x86_64.tar.gz mv elasticsearch-8.11.0 /opt/es chown -R elasticsearch:elasticsearch /opt/es目录结构如下:
/opt/es/ ├── bin/ ├── config/ ├── data/ ├── logs/ └── jdk/第三步:核心配置详解 —— 这些参数决定成败
进入/opt/es/config/elasticsearch.yml,这是最关键的一步。
节点 es01 配置示例(192.168.1.10)
# ================ 基础信息 ================ cluster.name: prod-cluster node.name: es01 # 绑定内网 IP,对外提供服务 network.host: 192.168.1.10 http.port: 9200 transport.port: 9300 # ================ 节点角色 ================ node.roles: [ master, data, ingest ] # ================ 发现与选举机制 ================ # 所有可能的初始联络点(所有候选主节点的地址) discovery.seed_hosts: ["192.168.1.10", "192.168.1.11", "192.168.1.12"] # 【仅首次启动时需要】指定哪些节点参与初选 cluster.initial_master_nodes: ["es01", "es02"] # ================ 安全设置(基础) ================ xpack.security.enabled: true xpack.security.transport.ssl.enabled: true其他节点类似配置
- es02:
node.name: es02,network.host: 192.168.1.11 - es03:
node.name: es03,network.host: 192.168.1.12,node.roles: [data, ingest]
🔥 关键提示:
-discovery.seed_hosts是所有节点都要一致的。
-cluster.initial_master_nodes只在第一次启动集群时设置一次,成功后就可以注释掉了,否则下次重启可能出问题。
- 如果你用了主机名而非 IP,请确保 DNS 或/etc/hosts解析正确。
第四步:JVM 调优 —— 让 GC 不再成为噩梦
编辑/opt/es/config/jvm.options:
# 堆内存建议设为物理内存的一半,最大不超过 31g -Xms16g -Xmx16g # 使用 G1GC 回收器(默认已启用) -XX:+UseG1GC # 目标最大暂停时间 500ms -XX:MaxGCPauseMillis=500 # 可选:启用大页(需系统支持) #-XX:+UseLargePages💡 小知识:为什么堆不能超过 32GB?
因为超过之后,JVM 无法使用指针压缩(Compressed OOPs),导致内存占用反而更高,性能下降。这不是玄学,是 HotSpot VM 的底层机制。
第五步:启动顺序很重要!别乱来
很多“节点连不上”的问题,其实是启动顺序错了。
正确的做法是:
- 先启动拥有
cluster.initial_master_nodes的节点(即 es01 和 es02) - 等它们互相发现并形成集群
- 再启动其他节点(如 es03)
启动命令(切换到 elasticsearch 用户):
cd /opt/es nohup bin/elasticsearch > logs/start.log 2>&1 &或者以后台服务方式运行(推荐使用 systemd):
# /etc/systemd/system/es.service [Unit] Description=Elasticsearch After=network.target [Service] Type=simple User=elasticsearch Group=elasticsearch ExecStart=/opt/es/bin/elasticsearch Restart=always LimitNOFILE=65536 [Install] WantedBy=multi-user.target然后:
sudo systemctl daemon-reload sudo systemctl start es sudo systemctl enable es第六步:验证集群是否正常
等所有节点启动后,访问任意节点的健康接口:
curl -X GET "http://192.168.1.10:9200/_cluster/health?pretty"期望输出:
{ "cluster_name" : "prod-cluster", "status" : "green", "number_of_nodes" : 3, "number_of_data_nodes" : 3, "active_primary_shards" : 5, "active_shards" : 10 }看到status: green就说明一切正常。
还可以查看节点列表:
curl -X GET "http://192.168.1.10:9200/_cat/nodes?v"你应该能看到三个节点都在线,并标注了各自的角色(m,d,i 等)。
常见问题排查指南(实战经验总结)
❌ 问题1:节点起不来,日志报failed to send join request
可能原因:
- 防火墙没开 9300 端口(transport 通信端口)
-discovery.seed_hosts写错了 IP 或端口
-cluster.name不一致
检查方法:
telnet 192.168.1.11 9300通不通一试便知。不通就看防火墙:
sudo firewall-cmd --add-port=9300/tcp --permanent sudo firewall-cmd --reload❌ 问题2:集群状态 yellow 或 red
- yellow:副本分片未分配(常见于节点数少于副本数)
- red:主分片缺失(严重!意味着数据不可读)
比如你只有一个节点,却设置了"number_of_replicas": 2,那必然 yellow。
解决方案:
# 调整索引副本数 curl -X PUT "localhost:9200/_all/_settings" -H 'Content-Type: application/json' -d' { "index.number_of_replicas": 1 }'或者增加节点数量。
❌ 问题3:启动报max file descriptors too low
前面已经说过,这是系统限制没改。
临时解决:
ulimit -n 65536永久解决:修改/etc/security/limits.conf并重新登录。
❌ 问题4:忘记密码怎么办?
ES 8.x 默认开启安全功能,首次启动会生成密码。
如果你错过了,可以用以下命令重置:
bin/elasticsearch-reset-password -u elastic或者重新初始化:
bin/elasticsearch-setup-passwords auto提示:记得保存好生成的密码,尤其是
kibana_internal和elastic用户。
生产级最佳实践建议
✅ 角色分离
- 专用 master 节点:
node.roles: [ master ] - 专用 data 节点:
node.roles: [ data ] - 协调节点(coordinating node):
node.roles: [ ],专门接请求做路由
这样可以避免主节点被查询压垮。
✅ 开启 TLS 加密
虽然商业功能,但在公网或跨机房部署时强烈建议开启节点间 SSL 通信:
xpack.security.transport.ssl.enabled: true xpack.security.http.ssl.enabled: true可以通过自签名证书实现免费加密。
✅ 快照备份不能少
配置共享存储仓库定期快照:
PUT _snapshot/my_backup { "type": "fs", "settings": { "location": "/mnt/backups", "compress": true } }然后定时创建快照:
PUT _snapshot/my_backup/snapshot_20250405灾难恢复时一键还原。
✅ 接入监控体系
暴露指标给 Prometheus:
GET /_nodes/stats配合 Grafana 展示 CPU、堆内存、GC 时间、线程池队列等关键指标,提前预警。
最后一点思考:你的集群真的“高可用”了吗?
搭建完成只是开始。
真正的挑战在于运维:如何应对磁盘写满?如何优雅扩容?如何滚动升级而不中断服务?
这些问题的答案,往往藏在一次次故障复盘中。
但我可以告诉你一个底线原则:
只要你的集群有至少三个 master-eligible 节点,且 data 节点有副本,你就拥有了最基本的容灾能力。
剩下的,交给时间和经验去打磨。
如果你正在构建 ELK 日志平台、实时分析系统,或是需要全文检索的产品功能,那么这套集群就是你最坚实的地基。
现在,打开终端,动手试试吧。
有问题欢迎留言讨论,我们一起踩坑、填坑、成长。