Elasticsearch(ES)是基于Lucene实现的分布式实时检索与分析引擎,其所有高可用、高容错、横向扩展能力,全部依托分布式集群机制实现。很多开发者仅会简单搭建集群,却不理解选主算法、分片分配、故障自愈的底层原理,导致生产环境频繁出现脑裂、集群红、分片丢失、节点无法上线等问题。
本文严格按照先原理、后实战的结构撰写:前置完整拆解ES集群架构原理、分布式一致性算法、集群选主核心算法、故障底层机制,最后统一落地集群从零搭建实战,彻底实现「懂原理、会搭建、能排障」。
Elasticsearch 集群核心原理
ES集群分布式整体架构原理
ES集群本质是一个去中心化的分布式对等集群,集群内所有节点地位对等,通过内部TCP协议自动发现、状态同步、数据协同,对外统一提供服务,客户端无需感知集群内部节点细节。
分布式集群的核心设计目标:解决单节点容量上限、性能上限、单点故障问题,实现数据冗余、请求负载均衡、故障自动转移、集群横向扩容。
集群选主核心算法与选举原理(重点)
很多资料只讲选主规则,不讲底层算法。ES 7.x/8.x 彻底废弃老旧Zen机制,统一使用基于Raft一致性算法改良的分布式选举机制 ,官方名称为ES Coordination Algorithm(ES协调算法)。
选主底层依赖:改良版Raft算法
原生Raft算法分为三个角色:领导者、跟随者、候选人,通过任期制、日志复制、多数投票实现一致性。
ES在原生Raft基础上做了轻量化改良,适配集群运维场景:
-
只针对集群元数据选举,不做强日志复制,提升集群响应速度;
-
引入固定投票配置集,避免随机节点参与选举,防止脑裂;
-
简化任期逻辑,优先保证集群快速收敛、稳定,而非极致强一致性。
算法核心结论 :ES集群选主 = 改良版Raft多数投票机制 + 法定人数Quorum约束。
法定人数 Quorum 原理(防脑裂核心)
Raft算法的安全底线:任何决策必须获得多数节点确认。ES基于此定义Quorum法定票数:
Quorum = 主候选节点总数 / 2 + 1(向上取整)
举例:3个主候选节点,Quorum=2,必须获得至少2票才能当选主节点。
该机制从算法层面杜绝脑裂:网络分区后,任何子集群只要不满足多数票数,就无法选举主节点,集群不会出现双主冲突。
完整选举触发时机与算法流程
选举触发时机:集群初始化、主节点心跳超时离线、网络分区恢复、投票配置变更。
改良Raft选主完整流程:
-
心跳探测:所有Master候选节点互相1s一次心跳,超时则判定对方离线;
-
切换候选状态:无主节点时,所有存活候选节点切换为候选人状态,发起选举;
-
广播投票请求:候选人向所有存活候选节点发送投票申请;
-
多数票校验:统计投票数,满足Quorum法定票数则竞选成功;
-
领导者生效:获胜节点成为Master主节点,接管集群元数据管理权限;
-
状态同步收敛:新主节点将最新集群状态同步至所有节点,集群恢复稳定。
为什么生产必须奇数主节点?
基于Raft+Quorum算法特性:
-
偶数节点:4个主节点,Quorum=3,若分裂为2+2两个子集群,均不满足法定票数,集群无主、整体瘫痪;
-
奇数节点:3个主节点,分裂为2+1,只有2节点集群满足Quorum,可正常选主,1节点集群无法选举,彻底规避双主脑裂。
集群脑裂故障底层原理
脑裂定义 :集群因网络抖动、分区、心跳超时,分裂为两个独立子集群,且两个子集群均满足Quorum多数投票条件,各自选出主节点。
底层危害:双主节点同时管理集群,分别执行索引创建、分片分配、数据写入,导致集群元数据分裂、分片错乱、数据覆盖、永久数据丢失,是ES最致命的分布式一致性故障。
根因总结:不满足Raft多数投票约束、主节点数量不合理、心跳超时参数不合理、非法节点参与选举。
ES集群生产搭建实战
单节点集群非安全组建:
修改JVM配置:最高不超过32G,小编这里设置为1GB

修改elasticsearch 配置,当前是想配置一个非安全的集群,所以这里设置一下
关闭X-Pack核心安全认证 xpack.security.enabled: false
之后什么都不用了,直接运行es就可以。
但是我们上述只是做了一下简单的配置,上面的配置下,我们的es只是配置到了本机可以访问,外网是访问不到的。

接下来我们可以设置IP+主节点的配置:
配置集群名称:
单节点下,这个也是可以选择配置或者是不配置的
配置节点名称:
这个是大家任意可以选择的。
配置es监听地址:
规定谁可以访问当前的es集群。
,下面问大家展示了集中配置的区别
| 配置值 | 含义 |
|---|---|
network.host: 127.0.0.1 |
只能本机访问,别的电脑连不上(最安全,但别人用不了) |
network.host: 192.168.1.100 |
只允许这个 IP 的机器访问 |
network.host: 0.0.0.0 |
所有 IP 都能访问(你现在要的效果) |
cluster.initial_master_nodes
- 作用:集群首次启动指定候选主节点,用于集群选举
- 取值:和
node.name节点名保持一致 - 适用:首次启动生效,后续失效
- 单节点简化写法:
cluster.initial_master_nodes: ["node-1"]
上述讲解后配置文件总体为
python
# 集群名称(同一个集群的节点名称必须一致)
cluster.name: es85X
# 当前节点的名称(唯一标识)
node.name: node-1
# 监听所有IP地址,允许外部设备访问
network.host: 0.0.0.0
# HTTP 访问端口(curl、浏览器、程序连接用)
http.port: 9200
# 节点间内部通信端口(集群同步数据用)
transport.port: 9300
# 集群第一次启动时,初始化主节点的候选列表
cluster.initial_master_nodes: ["node-1"]
# 关闭安全认证(学习环境用,生产环境不要关)
xpack.security.enabled: false
单节点集群安全组建:
和上述配置一样,只是最终不可以关闭xpack.
python
# 集群名称(同一个集群的节点名称必须一致)
cluster.name: es85X
# 当前节点的名称(唯一标识)
node.name: node-1
# 监听所有IP地址,允许外部设备访问
network.host: 0.0.0.0
# HTTP 访问端口(curl、浏览器、程序连接用)
http.port: 9200
# 节点间内部通信端口(集群同步数据用)
transport.port: 9300
# 集群第一次启动时,初始化主节点的候选列表
cluster.initial_master_nodes: ["node-1"]
多节点集群非安全组建:
节点一配置
python
# 集群名称(同一个集群的节点名称必须一致)
cluster.name: es85X
# 当前节点的名称(唯一标识)
node.name: node-1
# 监听所有IP地址,允许外部设备访问
network.host: 0.0.0.0
# HTTP 访问端口(curl、浏览器、程序连接用)
http.port: 9200
# 节点间内部通信端口(集群同步数据用)
transport.port: 9300
# 集群节点发现列表(告诉ES去哪些IP:端口找同伴节点)
discovery.seed_hosts: ["192.0.168.189:9300", "192.0.168.189:9301"]
# 集群第一次启动时,初始化主节点的候选列表
cluster.initial_master_nodes: ["node-1"]
# 关闭安全认证(学习环境用,生产环境不要关)
xpack.security.enabled: false
节点二配置
python
# 集群名称(同一个集群的节点名称必须一致)
cluster.name: es85X
# 当前节点的名称(唯一标识)
node.name: node-2
# 监听所有IP地址,允许外部设备访问
network.host: 0.0.0.0
# HTTP 访问端口(curl、浏览器、程序连接用)
http.port: 9201
# 节点间内部通信端口(集群同步数据用)
transport.port: 9301
# 集群节点发现列表(告诉ES去哪些IP:端口找同伴节点)
discovery.seed_hosts: ["192.0.168.189:9300", "192.0.168.189:9301"]
# 集群第一次启动时,初始化主节点的候选列表
cluster.initial_master_nodes: ["node-1"]
# 关闭安全认证(学习环境用,生产环境不要关)
xpack.security.enabled: false
非安全模式下直接启动就可以成功了。
安全模式所节点集群搭建
es在8.x版本下默认就是使用非安全的方式启动集群的。下文中问大家展示一下搭建安全模式下的集群
在安全模式下,配置的时候,参照如下的配置:
节点一:
python
# 集群名称(同一个集群的节点名称必须一致)
cluster.name: es85X
# 当前节点的名称(唯一标识)
node.name: node-1
# 监听所有IP地址,允许外部设备访问
network.host: 0.0.0.0
# HTTP 访问端口(curl、浏览器、程序连接用)
http.port: 9200
# 节点间内部通信端口(集群同步数据用)
transport.port: 9300
cluster.initial_master_nodes: ["node-1"]
节点二:
python
# 集群名称(同一个集群的节点名称必须一致)
cluster.name: es85X
# 当前节点的名称(唯一标识)
node.name: node-2
# 监听所有IP地址,允许外部设备访问
network.host: 0.0.0.0
# HTTP 访问端口(curl、浏览器、程序连接用)
http.port: 9201
# 节点间内部通信端口(集群同步数据用)
transport.port: 9301
节点三:
python
# 集群名称(同一个集群的节点名称必须一致)
cluster.name: es85X
# 当前节点的名称(唯一标识)
node.name: node-3
# 监听所有IP地址,允许外部设备访问
network.host: 0.0.0.0
# HTTP 访问端口(curl、浏览器、程序连接用)
http.port: 9202
# 节点间内部通信端口(集群同步数据用)
transport.port: 9302
使用安全模式的时候,启动的方式是一个一个服务器进行启动,之后通过下面的命令进行添加:
之后使用正在运行的节点执行命令:
./elasticsearch-create-enrollment-token -s node
之后需要加入的节点执行命令:./bin/elasticsearch --enrollment-token <粘贴你的Token>。
之后如果在重启集群的时候直接启动就可以了。
配置kibnana:
非安全模式配置:

下面的这个在集群模式下,推荐多配置几个,这样的话在一个节点挂了 → Kibana 自动切换另一个

安全模式配置:

在安全模式线只是需要配置这个一个就可以,但是需要注意的是,我们需要配置一下token.
如果是第一次执行的话。kibana会弹出一个页面,在页面中配置就行了,但是如果我们的token第一次打印的过期了,或者是没有保存下来的话,使用命令:
在任何正在运行的es服务器执行命令都可以获取token。
./elasticsearch-create-enrollment-token -s kibana
之后使用如下命令在kibana启动时带着参数就行了
./kibana-setup -t 《token》
其实这个文章在我在之前已经谢过了,但是那个只是快速搭建一个es的运行环境,但是当前的文章更加的具体和详细,大家都可以对照学习:第四章:动手搭建专业的ES运行环境_linux es启动无报错 但是状态仍然为 dead-CSDN博客,这这篇文章中写了集群配置时我们的操作系统如何配置,这里不再赘述,大家参考一下就可以了。