上周刚在Windows Server 2019上搭完一套Elasticsearch 7.6.2集群,三台服务器、三个节点,从单节点验证到多节点握手成功,整个过程中最折磨人的不是ES本身,而是网上集群教程绝大多数基于Linux,Windows下好几个隐藏坑只能自己一个一个踩。其中最典型的包括:防火墙默认挡了9300节点通信端口、记事本改YAML出现编码问题、cluster.initial_master_nodes没配导致节点启动后直接报master not discovered yet退出。
这篇就把从零开始做Windows下Elasticsearch 7.6.2多服务器多节点配置的完整过程复盘一遍,覆盖环境准备、节点角色划分、elasticsearch.yml关键字段解析、三节点配置模板、启动顺序、跨服务器联调报错排查,以及最后怎么把ES注册成Windows服务长期跑。适合第一次在Windows环境搭ES集群的开发或运维,也适合从Linux环境切到Windows的同学参考。
1. 为什么选7.6.2:版本背景和Windows部署前要解决的三个前置问题
1.1 7.6.2在版本序列里的“江湖地位”
Elasticsearch 7.6.2不是最新版本,但它在国内项目里的存在感极强。因为很多业务系统、数据同步工具、中文分词插件、日志采集组件,都是围绕7.6.2这个版本完成适配的。后续7.7、7.8等版本属于小步迭代,但老项目如果已经用7.6.2的API开发完,贸然跨小版本升级意味着要重新验证插件兼容性、接口变化和集群迁移,成本不小。
所以很多人和我一样,新部署也会选择7.6.2,倒不是说它比新版强,而是它的资料最全、周边生态最成熟。遇到问题搜索时,几乎每个报错都能找到对应场景,这在生产排障里是实打实的优势。
1.2 Windows Server部署的特殊性
很多企业内网系统跑在Windows Server上,ES集群不可能都迁到Linux。实际部署下来,ES官方对Windows的支持并不弱,解压zip包就能跑,单机安装甚至比Linux还省事。但多服务器集群和单机是两个难度等级,Windows下的特殊点集中在三个方面:
第一,防火墙。节点间走9300端口做transport通信,Windows防火墙默认可能拦截,不提前放行,节点就互相发现不了。
第二,配置文件的编辑方式。用记事本改elasticsearch.yml容易引入编码和格式问题,这在Linux下不太会遇到。
第三,长期运行方式。手动开命令行窗口跑ES,窗口一关节点就下线,必须注册成Windows服务才能稳定运行。
把这三个问题先解决掉,Windows下搭ES集群的体验会顺畅很多。
1.3 安装前的环境检查清单
动手改集群配置之前,我建议先在每台服务器上做一轮环境检查。重点看这五样:
- 安装目录:解压到无空格路径,比如
C:\elasticsearch-7.6.2。不要放进Program Files,否则后续权限控制和路径引用都麻烦。 - JDK:ES 7.6.2安装包自带JDK,在安装目录的
jdk文件夹里,直接能用。但生产环境建议统一设置JAVA_HOME指向JDK 11,避免不同节点JVM版本不一致。 - 端口:9200是HTTP端口,9300是节点间通信端口,启动前确认没被占用。
- 内存:单节点建议最少4G可用内存,堆内存按物理内存一半以内设置,稍后讲。
- 磁盘:数据目录、日志目录单独规划,别放在C盘系统盘,我习惯用
D:\es-data和D:\es-logs。
环境检查到位后再开始配置,能避免一半以上的“集群起不来”问题。
2. 多服务器多节点的拓扑规划:角色职责、脑裂预防与推荐布局
2.1 节点角色到底怎么分
ES的每个节点启动时,都可以通过elasticsearch.yml里的配置决定自己承担什么职责。最核心的三个开关是:
node.master: true:该节点有资格参与master选举,负责维护集群状态。node.data: true:该节点存储数据,执行读写和聚合。node.ingest: true:该节点可以对写入数据做预处理。
三个开关默认都是true,也就是每个节点既是数据节点又是master候选节点。对于3节点的小集群,我建议就保持默认,不要拆角色。
很多人会想:一台做纯master,两台做纯data,分工不是更清晰吗?听起来合理,但实际会引入风险。比如纯data节点挂了,索引副本可能无处分配;纯master节点不存数据,集群里能放副本的机器变少,一旦数据节点分布不均,很容易出现索引health为yellow。小规模集群要的是冗余和简单,不是精细分工。等到节点数量到10个以上,再考虑把master候选节点独立出来。
2.2 为什么最少要三台服务器
ES集群设计里有个绕不开的点:脑裂。简单说,如果集群只有两个master候选节点,网络发生分区时,两边各有一台节点,彼此联系不上,都认为自己这边该成为master,很容易出现两套集群状态。
ES 7.x开始,discovery.zen.minimum_master_nodes这个参数已经交给集群自动管理,但底层“多数派选举”的原则没有变。master候选节点最好是奇数,3个或5个。这样任何一台宕机,剩余节点仍然能凑够多数派,继续选主,不会出现双主脑裂。
如果你手里只有两台物理服务器,临时方案是在其中一台服务器上启动两个ES实例,凑够三个节点。但要注意,这台物理机一旦挂掉,等于同时丢了两个节点,集群还是可能不可用。所以从生产角度讲,想跑高可用集群,最少三台独立服务器才是正解。
2.3 推荐的三节点布局
假设三台服务器都在同一内网网段,IP分别如下,每台各跑一个ES节点:
| 节点名 | IP地址 | 角色 |
|---|---|---|
| node-1 | 192.168.10.11 | master + data + ingest |
| node-2 | 192.168.10.12 | master + data + ingest |
| node-3 | 192.168.10.13 | master + data + ingest |
这个布局没有单点瓶颈,任何一台宕机,另外两台仍然能组成多数派,集群继续对外服务。后面新增节点时,把新节点的node.master设为false、node.data设为true即可,不必让所有新节点都参与master选举。
3. 手动配置elasticsearch.yml:七个关键字段逐个拆
3.1 cluster.name:集群的唯一身份
cluster.name是所有节点能否走到一起的第一道门槛。三台服务器的这个值必须完全一致,差一个字母,节点启动后只会把彼此当成不同集群,日志里不会有明显报错,但永远发现不了对方。
命名建议用小写、简短、带环境含义的名字,比如es-cluster-prod。这个值会写进数据和日志目录,后期改起来很麻烦,想清楚再定。
3.2 node.name:节点命名的纪律
node.name在同一集群内必须唯一,不允许出现两个同名节点。命名最好和服务器主机名或IP有对应关系,比如node-1、node-2、node-3,这样看到堆栈日志时能立刻判断是哪个节点出了问题。
3.3 network.host:该写0.0.0.0还是具体IP
默认情况下network.host是127.0.0.1,只监听本机回环地址,其他服务器访问不到,集群根本不可能建立。
有两种改法:
- 写
0.0.0.0,让ES绑定本机所有网卡。优点是配置简单,缺点是如果服务器有多块网卡,9200和9300端口会全部暴露,在内网环境问题不大,在边界机器上就有安全隐患。 - 写具体内网IP,比如
192.168.10.11。更可控,我推荐这种方式,每台服务器填各自的IP。
另外注意http.port默认是9200,不需要改。想让每台节点独立提供HTTP访问,就保持9200。
3.4 discovery.seed_hosts:告诉节点去哪里找朋友
这个字段就是节点启动后用来发现其他节点的地址列表。格式是一个数组,元素是IP:9300,如果节点都在同一内网,建议每个节点都写上三台机器的完整列表。
discovery.seed_hosts: - "192.168.10.11:9300" - "192.168.10.12:9300" - "192.168.10.13:9300"不要只在node-1上写完整列表,另外两台只写自己,那样当node-1故障时,新加入的节点可能找不到可用目标。保持三台配置一致,是最稳妥的。
3.5 cluster.initial_master_nodes:只在第一次启动时至关重要
这是7.x版本新引导机制最容易踩坑的字段。含义是:集群第一次启动时,允许作为初始master引导的节点名单。注意它填的是node.name,不是IP。
cluster.initial_master_nodes: ["node-1", "node-2", "node-3"]第一次启动集群时,这个字段必须包含参与引导的节点名。如果没配,7.6.2启动会直接报master not discovered yet并退出,我在第5节会细说。集群引导完成后,新加入的节点就不需要再配置这个字段了,它们只要通过discovery.seed_hosts找到已有节点,就能同步集群状态并加入。
3.6 path.data和path.logs:Windows路径的三个坑
path.data和path.logs不配置的话,数据默认放在安装目录下的data和logs文件夹。这有两个坏处:一是安装目录在C盘,数据增长会拖累系统盘;二是以后卸载重装或升级时,可能不小心把数据删了。
我习惯在每台服务器上单独建两个目录:
path.data: D:/es-data path.logs: D:/es-logs这里有个Windows专属的坑:YAML里写反斜杠路径,比如D:\es-data,反斜杠是YAML的转义字符,经常解析出错。要么写两个反斜杠D:\\es-data,要么直接像我一样用正斜杠D:/es-data,ES在Windows下能正确识别,而且省心。
提示:同一个
path.data目录只能被一个ES节点使用。如果你在一台机器上跑多个ES实例,必须给每个实例指定各自独立的数据目录,否则第二个节点启动时会因无法获得目录锁而失败。
4. 三台机器的配置模板与启动验证
4.1 完整配置示例
下面给出node-1的完整elasticsearch.yml配置,node-2和node-3只需要改动三处:node.name、network.host,其余保持一致。
node-1的配置:
cluster.name: es-cluster-prod node.name: node-1 node.master: true node.data: true node.ingest: true network.host: 192.168.10.11 http.port: 9200 transport.port: 9300 discovery.seed_hosts: - "192.168.10.11:9300" - "192.168.10.12:9300" - "192.168.10.13:9300" cluster.initial_master_nodes: ["node-1", "node-2", "node-3"] path.data: D:/es-data path.logs: D:/es-logsnode-2把node.name改成node-2,network.host改成192.168.10.12,其他不变。node-3同理。discovery.seed_hosts和cluster.initial_master_nodes三台机器保持一致。
4.2 启动顺序与理由
配置好之后,启动顺序有讲究。我习惯的流程是:先启动node-1,等待它成为master;再启动node-2,观察它是否加入集群;最后启动node-3。
这样做的好处是日志清晰。node-1启动后,如果它在没有其他节点的情况下成功选主,日志里会出现elected as master字样。此时再启动node-2,它会通过discovery.seed_hosts里的地址找到node-1并同步状态,整个过程容易判断问题出在哪一环。
如果三台机器同时启动,ES内部也能通过选举机制自行解决,但日志交错在一起,排障难度会大不少。手动部署阶段,一台一台来更稳妥。
启动方式很简单,在每台服务器的安装目录下执行:
cd C:\elasticsearch-7.6.2\bin elasticsearch.bat前台启动窗口不要关,关了就相当于把节点杀了。临时验证用这种方式可以,长期运行后面会做成Windows服务。
4.3 验证是否成功形成集群
集群全部启动后,在任意一台服务器上执行状态查询。Windows Server 2019自带curl,直接用:
curl -X GET "http://192.168.10.11:9200/_cluster/health?pretty"重点关注返回结果里的三个字段:
status:为green说明所有索引主分片和副本分片都已分配;yellow说明有副本分片未分配;red说明有主分片丢失。number_of_nodes:应该等于3。number_of_data_nodes:应该等于3。
再执行:
curl -X GET "http://192.168.10.11:9200/_cat/nodes?v"能看到三行节点列表,包含IP、node.role、master列。node.role为dim表示master、data、ingest三重角色都承担,master列显示*的那个节点是当前集群master。看到三行输出,multinode集群就算正式通了。
5. 从日志到API:跨服务器联调中最常见的报错排查
5.1 master not discovered yet:引导配置丢失
这是7.6.2集群第一次启动时最经典的报错。节点日志里会出现类似这样的内容:
master not discovered yet, this node has not previously joined a bootstrapped (v7+) cluster意思是节点还没有加入过任何集群,也没有在初始化引导阶段被指定为潜在master,所以它不知道去哪找一个可用的master。
排查链路按顺序走:
- 检查三台服务器
cluster.name是否完全一致,一个字符都不能差。 - 检查
cluster.initial_master_nodes里的node.name是否和实际配置完全一致,注意大小写。 - 检查
discovery.seed_hosts里的端口是否写的9300,以及IP是否能互通。 - 如果之前已经启动过又失败,数据目录里可能残留旧状态,必要时在明确无数据的情况下清空
path.data目录后重试。
提示:报这个错时,不要急着反复重启任意节点。先确认三台服务器的配置都到位,再按顺序重启node-1、node-2、node-3,很多“起不来”其实是没按顺序启动导致的。
5.2 防火墙导致节点间握不上手
三台机器配置都正确,但节点日志里不断出现connect timeout、NoNodeAvailableException,大概率是9300端口被防火墙拦了。
在Windows上可以先测试端口连通性:
Test-NetConnection 192.168.10.12 -Port 9300如果输出里TcpTestSucceeded显示False,说明两台机器之间的9300端口不通,基本就是防火墙问题。开放端口用以下命令,以管理员身份打开PowerShell:
netsh advfirewall firewall add rule name="ES 9200" dir=in action=allow protocol=TCP localport=9200 netsh advfirewall firewall add rule name="ES 9300" dir=in action=allow protocol=TCP localport=93009200是HTTP API端口,外部程序访问ES数据要放行;9300是节点间transport通信端口,节点寻址要用。两个都放行,三台服务器都要执行。
如果对安全要求高,可以给规则限定来源网段:
netsh advfirewall firewall add rule name="ES 9300 internal" dir=in action=allow protocol=TCP localport=9300 remoteip=192.168.10.0/24只允许内网网段访问,端口不暴露给外部。
5.3 yellow状态和未分配分片
集群节点数已经是3,但_cluster/health返回的status是yellow,查看分片状态:
curl -X GET "http://192.168.10.11:9200/_cat/shards?v"会看到部分副本分片的state是UNASSIGNED。原因是索引默认副本数配置为1,而索引可能是集群只有单节点时创建的。单节点时代,副本分片无法分配到其他节点,所以处于未分配状态;集群变成多节点后,ES会尝试自动分配,但有时不会立刻完成。
先看具体原因:
curl -X GET "http://192.168.10.11:9200/_cluster/allocation/explain?pretty"返回结果里会指明为什么分片分配不了。常见原因是磁盘水位线、节点数量不足、或某索引被手动关闭分配。
如果只是历史遗留的未分配,可以手动触发一次重新分配:
curl -X POST "http://192.168.10.11:9200/_cluster/reroute?retry_failed=true"之后重新看_cluster/health,大多数情况下会从yellow变green。如果仍然未分配,再把explain的输出和节点磁盘使用情况放一起看,基本能定位。
5.4 几个Windows特有的小毛病
failed to bind to 9300:说明本机9300端口已经被占用。检查同一台机器是否起了第二个ES实例,或者别的程序占了端口。处理方式是把第二个实例的transport.port改成9301。
failed to obtain node locks:同一台机器上两个节点共用了同一个path.data目录。这个问题我在3.6节提过,两个节点必须各自独立数据目录。
YAML解析失败、冒号后面没空格、中文标点混入:Windows记事本编辑YAML时容易出现,尤其是从网页复制的配置。建议用VS Code编辑,保存时编码选UTF-8,不要选带BOM的UTF-8。ES对配置文件的编码敏感,BOM头会导致解析异常。
控制台日志乱码:Windows控制台默认编码是GBK,ES输出的是UTF-8,个别版本会显示乱码。这不影响节点运行,等注册成Windows服务后,日志写入path.logs目录,用专用工具查看即可,不用纠结控制台显示。
6. 生产化落地:Windows服务注册、内存调整与日常维护经验
6.1 把ES注册成Windows服务
手动开命令行窗口跑ES只适合验证,生产环境必须注册成Windows服务,开机自启、崩溃自动重启都靠它。
ES自带服务脚本,在安装目录的bin下。以管理员身份打开PowerShell,执行:
cd C:\elasticsearch-7.6.2\bin .\elasticsearch-service.bat install默认服务名是elasticsearch-service-x64。可以用服务管理器查看:
services.msc找到对应服务,启动方式设为自动。需要调整服务运行参数时,用:
.\elasticsearch-service.bat manager会弹出图形化管理界面,可以设置启动方式、服务名、JVM参数等。
如果同一台机器要跑多个ES实例,注册服务时指定不同服务名:
.\elasticsearch-service.bat install es-node-2这样两个实例能作为不同服务独立管理。
卸载服务:
.\elasticsearch-service.bat remove6.2 JVM堆内存调整
ES默认堆内存是1G,生产环境肯定不够。修改安装目录下的config\jvm.options:
-Xms4g -Xmx4gXms和Xmx必须保持一致,避免运行期动态扩容带来性能抖动。堆内存上限不要超过物理内存的50%,也不要超过30G。下面是常见配置参考:
| 服务器物理内存 | 建议堆内存 |
|---|---|
| 8G | 4G |
| 16G | 8G |
| 32G | 16G |
堆内存设太大反而会拖累GC,给操作系统留足缓存空间更重要。
6.3 日常维护的几个习惯
集群搭好不是终点,后续维护有几个习惯我从实践中总结出来。每周看一次_cluster/health,确认长时间平稳;用_cat/indices?v看索引分片分布,数一数是否存在单节点集中了大量分片的情况。path.logs增长很快,Windows磁盘空间规划时给日志目录留够余量。
需要重启节点时,优先用Windows服务管理器重启,不要直接kill进程。ES节点从服务停止到完全下线需要一点时间,强制结束进程可能导致分片恢复时间变长。多节点集群滚动重启时,一次只重启一台,等节点状态重新变green再动下一台。
6.4 最后分享两个小技巧
第一个技巧:所有节点的配置维护好之后,把每台服务器的node.name、IP地址、cluster.name这组映射关系写成txt,贴到每台服务器桌面上。排障时经常遇到一个问题:人站在node-2前面,却记不清node-2的IP是什么。有这个记录表,一下就能定位。
第二个技巧:排查任何集群问题时,优先看path.logs下以cluster.name命名的日志文件,而不是盯着控制台窗口。Windows控制台在ES日志高输出时会漏消息,日志文件里才是完整链路。遇到报错先翻日志结尾的Caused by,再往回找根因,比从头读日志高效得多。
这套流程跑通之后,Windows下的ES集群其实比想象中稳。只要把防火墙、配置编码、服务化这几个Windows专属坑处理干净,剩下的问题大概率都出在引导配置和网络互通上,按本文第5节的排查链路走一遍,基本都能解决。