在这里插入图片描述

👋 大家好,欢迎来到我的技术博客!
💻 作为一名热爱 Java 与软件开发的程序员,我始终相信:清晰的逻辑 + 持续的积累 = 稳健的成长
📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。
🎯 本文将围绕ElasticSearch这个话题展开,希望能为你带来一些启发或实用的参考。
🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!


Elasticsearch - Elasticsearch 集群搭建:3 节点基础配置 🌐

在现代分布式系统中,Elasticsearch 已成为日志分析、全文搜索、实时监控等场景的首选引擎。然而,单节点部署仅适用于开发或测试环境,生产环境中必须使用集群架构以保障高可用性、容错能力和横向扩展能力。

本文将手把手带你从零开始,搭建一个 3 节点的 Elasticsearch 集群,涵盖网络配置、角色划分、安全设置、健康检查及 Java 客户端连接示例。无论你是 DevOps 工程师、后端开发者,还是刚接触 Elasticsearch 的新手,都能通过本文快速掌握集群部署的核心技能。

💡 为什么是 3 节点?

  • 奇数节点可避免脑裂(Split-Brain);
  • 最小高可用单元(容忍 1 节点故障);
  • 资源开销适中,适合中小型企业起步。

一、准备工作:环境与依赖 🛠️

1. 硬件要求(最低建议)

组件 推荐配置
CPU 每节点 ≥ 2 核
内存 每节点 ≥ 4 GB(建议 8 GB+)
存储 每节点 ≥ 20 GB SSD(用于测试)
网络 节点间互通,延迟 < 1ms

🔗 官方硬件指南:Elasticsearch Hardware Recommendations

2. 软件依赖

  • 操作系统:Linux(Ubuntu 22.04 / CentOS 7+)推荐,Windows 仅限测试;
  • Java:OpenJDK 17(Elasticsearch 8.x+ 要求 JDK 17);
  • Elasticsearch 版本:本文以 8.12.0 为例(截至 2025 年主流稳定版)。

3. 服务器规划

假设我们有三台虚拟机(或云主机):

主机名 IP 地址 角色
es-node-1 192.168.1.101 master + data
es-node-2 192.168.1.102 master + data
es-node-3 192.168.1.103 master + data

✅ 小集群中,通常让所有节点兼具 masterdata 角色,简化架构。


二、安装 Elasticsearch 📦

以下操作需在 每台节点 上执行。

1. 安装 OpenJDK 17

# Ubuntu
sudo apt update
sudo apt install openjdk-17-jdk -y

# CentOS
sudo yum install java-17-openjdk-devel -y

验证:

java -version
# 应输出 openjdk version "17.x.x"

2. 下载并安装 Elasticsearch

# 添加 Elastic 官方 GPG 密钥
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elastic-keyring.gpg

# 添加 APT 源(Ubuntu)
echo "deb [signed-by=/usr/share/keyrings/elastic-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list

# 安装
sudo apt update
sudo apt install elasticsearch -y

🔗 安装文档:Install Elasticsearch

3. 启动服务(暂不启动)

sudo systemctl daemon-reload
sudo systemctl enable elasticsearch
# 先不要 start,需先配置

三、核心配置:elasticsearch.yml 🧩

Elasticsearch 的集群行为主要由 elasticsearch.yml 控制。该文件位于 /etc/elasticsearch/elasticsearch.yml

⚠️ 注意:每台节点的配置略有不同,尤其是 node.namenetwork.host

通用配置项说明

配置项 说明
cluster.name 集群名称,所有节点必须一致
node.name 当前节点名称,需唯一
network.host 绑定 IP,设为内网 IP 或 0.0.0.0(生产慎用)
discovery.seed_hosts 初始主节点发现列表
cluster.initial_master_nodes 首次启动时的主节点候选列表(仅首次需要)
node.roles 节点角色(如 [master, data]

节点 1 配置(192.168.1.101)

# /etc/elasticsearch/elasticsearch.yml

cluster.name: my-es-cluster

node.name: es-node-1
node.roles: [ master, data ]

network.host: 192.168.1.101
http.port: 9200

discovery.seed_hosts: ["192.168.1.101", "192.168.1.102", "192.168.1.103"]
cluster.initial_master_nodes: ["es-node-1", "es-node-2", "es-node-3"]

# 安全设置(8.x 默认开启)
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true

节点 2 配置(192.168.1.102)

cluster.name: my-es-cluster

node.name: es-node-2
node.roles: [ master, data ]

network.host: 192.168.1.102
http.port: 9200

discovery.seed_hosts: ["192.168.1.101", "192.168.1.102", "192.168.1.103"]
cluster.initial_master_nodes: ["es-node-1", "es-node-2", "es-node-3"]

xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true

节点 3 配置(192.168.1.103)

cluster.name: my-es-cluster

node.name: es-node-3
node.roles: [ master, data ]

network.host: 192.168.1.103
http.port: 9200

discovery.seed_hosts: ["192.168.1.101", "192.168.1.102", "192.168.1.103"]
cluster.initial_master_nodes: ["es-node-1", "es-node-2", "es-node-3"]

xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true

✅ 关键点:

  • cluster.name 必须相同;
  • node.name 必须唯一;
  • discovery.seed_hosts 包含所有 master 候选节点 IP;
  • cluster.initial_master_nodes 仅在首次启动集群时需要,后续重启可注释或删除。

四、启动集群并初始化安全 🔐

1. 启动所有节点

在每台机器上执行:

sudo systemctl start elasticsearch

查看状态:

sudo systemctl status elasticsearch
# 确保 active (running)

2. 初始化内置用户密码(仅在一台节点执行)

Elasticsearch 8.x 默认启用安全功能,需为内置用户(如 elastic)设置密码。

sudo /usr/share/elasticsearch/bin/elasticsearch-setup-passwords auto

输出示例:

Changed password for user apm_system
PASSWORD apm_system = Hh8nK2pQxL...

Changed password for user elastic
PASSWORD elastic = s3cr3tP@ssw0rd!
...

📌 记下 elastic 用户的密码,后续 Java 客户端连接需要。

🔗 安全配置指南:Secure a cluster


五、验证集群状态 ✅

1. 检查节点是否加入集群

在任意节点执行:

curl -u elastic:s3cr3tP@ssw0rd! http://192.168.1.101:9200/_cat/nodes?v

预期输出:

ip            heap.percent ram.percent cpu load_1m load_5m load_15m node.role   master name
192.168.1.101           20          80   2    0.10    0.05     0.01 mdi         *      es-node-1
192.168.1.102           18          78   1    0.08    0.04     0.00 mdi         -      es-node-2
192.168.1.103           19          79   2    0.09    0.06     0.01 mdi         -      es-node-3
  • mdi 表示 master + data + ingest;
  • * 表示当前主节点。

2. 检查集群健康状态

curl -u elastic:s3cr3tP@ssw0rd! http://192.168.1.101:9200/_cluster/health?pretty

理想输出:

{
  "cluster_name" : "my-es-cluster",
  "status" : "green",
  "timed_out" : false,
  "number_of_nodes" : 3,
  "number_of_data_nodes" : 3,
  "active_primary_shards" : 0,
  "active_shards" : 0,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 0
}
  • status: green 表示一切正常;
  • 若为 yellow,通常因副本未分配(单节点常见,3 节点应为 green)。

六、集群架构图解 📊

下面用 Mermaid 展示 3 节点集群的逻辑结构:

graph TD
    Client[Java Client] -->|HTTPS| LB[Load Balancer<br/>(可选)]
    LB -->|9200| Node1[es-node-1<br/>192.168.1.101<br/>master + data]
    LB -->|9200| Node2[es-node-2<br/>192.168.1.102<br/>master + data]
    LB -->|9200| Node3[es-node-3<br/>192.168.1.103<br/>master + data]
    
    Node1 <-->|Transport Port 9300| Node2
    Node2 <-->|Transport Port 9300| Node3
    Node3 <-->|Transport Port 9300| Node1
    
    style Node1 fill:#e6f7ff,stroke:#1890ff
    style Node2 fill:#e6f7ff,stroke:#1890ff
    style Node3 fill:#e6f7ff,stroke:#1890ff
    style LB fill:#f6ffed,stroke:#52c41a

💡 说明:

  • 客户端可通过任一节点访问集群;
  • 节点间通过 9300 端口(transport)通信;
  • 生产环境建议前置负载均衡器(如 Nginx、HAProxy)。

七、Java 客户端连接示例 💻

Elasticsearch 8.x 推荐使用 官方 Java API Client(基于 HTTP,非 Transport Client)。

1. Maven 依赖

<dependency>
    <groupId>co.elastic.clients</groupId>
    <artifactId>elasticsearch-java</artifactId>
    <version>8.12.0</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.3</version>
</dependency>

2. 创建安全客户端

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;

public class ESClientBuilder {

    public static ElasticsearchClient createSecureClient(String host, int port, String username, String password) {
        // 设置认证
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(
            AuthScope.ANY,
            new UsernamePasswordCredentials(username, password)
        );

        // 创建 RestClient
        RestClient restClient = RestClient.builder(new HttpHost(host, port))
            .setHttpClientConfigCallback(httpClientBuilder ->
                httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
            )
            .build();

        // 创建传输层
        ElasticsearchTransport transport = new RestClientTransport(
            restClient,
            new JacksonJsonpMapper()
        );

        return new ElasticsearchClient(transport);
    }
}

3. 测试集群连接

import co.elastic.clients.elasticsearch.core.InfoResponse;

public class ClusterHealthCheck {
    public static void main(String[] args) throws Exception {
        // 连接任意节点
        ElasticsearchClient client = ESClientBuilder.createSecureClient(
            "192.168.1.101", 9200, "elastic", "s3cr3tP@ssw0rd!"
        );

        // 获取集群信息
        InfoResponse info = client.info();
        System.out.println("Cluster Name: " + info.clusterName());
        System.out.println("Version: " + info.version().number());

        // 检查健康状态
        var health = client.cluster().health();
        System.out.println("Status: " + health.status());
        System.out.println("Nodes: " + health.numberOfNodes());

        client._transport().close();
    }
}

输出示例:

Cluster Name: my-es-cluster
Version: 8.12.0
Status: GREEN
Nodes: 3

4. 写入与查询数据

import co.elastic.clients.elasticsearch.core.IndexRequest;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.search.Hit;

import java.time.Instant;
import java.util.Map;

public class DataOperations {
    public static void main(String[] args) throws Exception {
        ElasticsearchClient client = ESClientBuilder.createSecureClient(
            "192.168.1.101", 9200, "elastic", "s3cr3tP@ssw0rd!"
        );

        // 写入文档
        Map<String, Object> doc = Map.of(
            "message", "Hello from Java!",
            "@timestamp", Instant.now(),
            "user_id", 123
        );

        IndexRequest indexReq = IndexRequest.of(i -> i
            .index("test-index")
            .document(doc)
        );
        var indexResp = client.index(indexReq);
        System.out.println("Indexed ID: " + indexResp.id());

        // 查询文档
        SearchRequest searchReq = SearchRequest.of(s -> s
            .index("test-index")
            .query(q -> q.matchAll(m -> m))
            .size(5)
        );

        var searchResp = client.search(searchReq, Object.class);
        for (Hit<Object> hit : searchResp.hits().hits()) {
            System.out.println("Source: " + hit.source());
        }

        client._transport().close();
    }
}

🔗 Java Client 官方文档:Elasticsearch Java API Client


八、常见问题排查 🛠️

问题 1:节点无法加入集群

现象_cat/nodes 只显示部分节点。

排查步骤

  1. 检查防火墙:确保 9200(HTTP)和 9300(Transport) 端口开放;
    sudo ufw allow 9200/tcp
    sudo ufw allow 9300/tcp
    
  2. 检查 elasticsearch.ymlnetwork.host 是否绑定正确 IP;
  3. 查看日志:sudo journalctl -u elasticsearch -f

问题 2:集群状态为 RED

原因:主分片丢失。

解决

  • 检查磁盘空间:df -h
  • 检查索引是否被误删;
  • 若为新集群,可能因未创建索引,属正常(状态为 green)。

问题 3:SSL/TLS 错误(Java 客户端)

错误javax.net.ssl.SSLHandshakeException

解决:Elasticsearch 8.x 默认使用自签名证书。开发环境可禁用证书验证(仅限测试!):

// 不推荐生产使用!
RestClient restClient = RestClient.builder(new HttpHost(host, port))
    .setHttpClientConfigCallback(httpClientBuilder -> {
        try {
            SSLContext sslContext = SSLContextBuilder
                .create()
                .loadTrustMaterial(null, (chain, authType) -> true)
                .build();
            return httpClientBuilder
                .setSSLContext(sslContext)
                .setSSLHostnameVerifier((hostname, session) -> true);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    })
    .build();

✅ 生产环境应配置 CA 证书,参考:Configure TLS


九、生产环境增强建议 🚀

1. 角色分离(大规模集群)

当节点数 > 5 时,建议分离角色:

节点类型 数量 角色
Master 节点 3 [master]
Data 节点 N [data]
Ingest 节点 2 [ingest]

避免 master 节点承担数据压力。

2. 配置专用主节点

# master-only 节点
node.roles: [ master ]

3. 调整 JVM 堆内存

编辑 /etc/elasticsearch/jvm.options

-Xms4g
-Xmx4g

⚠️ 堆内存 ≤ 32GB,且不超过物理内存 50%。

4. 启用监控

集成 Kibana + Metricbeat,监控集群性能。

🔗 监控方案:Elastic Stack Monitoring


十、自动化脚本示例 🤖

为简化部署,可编写 Ansible 或 Shell 脚本。

批量配置脚本(install-es.sh)

#!/bin/bash
# 在每台节点运行,传入节点名和IP
NODE_NAME=$1
IP_ADDR=$2

# 安装 JDK & ES(略)

# 生成 elasticsearch.yml
cat > /etc/elasticsearch/elasticsearch.yml <<EOF
cluster.name: my-es-cluster
node.name: $NODE_NAME
node.roles: [ master, data ]
network.host: $IP_ADDR
discovery.seed_hosts: ["192.168.1.101", "192.168.1.102", "192.168.1.103"]
cluster.initial_master_nodes: ["es-node-1", "es-node-2", "es-node-3"]
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
EOF

systemctl restart elasticsearch

调用:

# 在 192.168.1.101
./install-es.sh es-node-1 192.168.1.101

外部资源推荐 🔗

✅ 所有链接均经测试可正常访问(截至 2025 年 11 月)。


结语 🌟

搭建一个 3 节点的 Elasticsearch 集群,是迈向高可用搜索与分析系统的第一步。通过合理的配置、安全加固和客户端集成,你可以构建一个稳定、高效、可扩展的基础平台。

记住:集群不是搭完就结束,而是运维的开始。持续监控、定期备份、容量规划,才是保障长期稳定的关键。

现在,打开你的终端,开始部署吧!🚀

💬 提示:遇到问题?查看日志永远是第一选择:journalctl -u elasticsearch -n 100

Happy clustering! 😊


🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐