Nacos 集群部署方案

Nacos 集群部署方案


一、集群标准部署架构

1.1 架构图

yaml 复制代码
                              ┌─────────────────┐
                              │    Nginx / SLB   │
                              │   (VIP: 10.x.x.x)│
                              │   Port: 8848     │
                              └────────┬─────────┘
                                       │
              ┌────────────────────────┼────────────────────────┐
              │                        │                        │
    ┌─────────▼─────────┐   ┌─────────▼─────────┐   ┌─────────▼─────────┐
    │   Nacos Node 1    │   │   Nacos Node 2    │   │   Nacos Node 3    │
    │   IP: 10.1.1.11   │   │   IP: 10.1.1.12   │   │   IP: 10.1.1.13   │
    │   Port: 8848      │   │   Port: 8848      │   │   Port: 8848      │
    │   gRPC: 9848      │   │   gRPC: 9848      │   │   gRPC: 9848      │
    │   gRPC srv: 9849  │   │   gRPC srv: 9849  │   │   gRPC srv: 9849  │
    └────────┬──────────┘   └────────┬──────────┘   └────────┬──────────┘
             │                       │                        │
             └───────────────────────┼────────────────────────┘
                                     │
                        ┌────────────▼────────────┐
                        │          MySQL          │
                        │  (主从 / MGR 集群)       │
                        │  IP: 10.1.1.20:3306     │
                        │  DB: nacos_config       │
                        └─────────────────────────┘

1.2 架构说明

组件 说明
Nacos Node 3 节点集群,无中心化设计,任意节点可提供完整服务
负载均衡 Nginx / SLB 统一入口,将请求分发到后端各 Nacos 节点
MySQL 集中式元数据存储,所有 Nacos 节点共享同一数据库
协议端口 8848(HTTP)、9848(gRPC客户端)、9849(gRPC服务端,用于Raft)

1.3 关键端口说明

端口 用途 偏移公式
8848 HTTP 管理端 / 客户端 API 主端口
9848 gRPC 客户端通信 主端口 + 1000
9849 gRPC Raft 节点间通信 主端口 + 1001

注意 :Nacos 2.x 起,节点间 Raft 通信默认使用 (server.port + 1001) 端口,集群间必须互通。


二、集群完整配置

2.1 环境要求

项目 要求
JDK 1.8+ (推荐 JDK 17)
内存 JVM 堆内存 ≥ 2G (生产建议 4G)
磁盘 ≥ 10G 可用空间
MySQL 5.7+ / 8.0

2.2 Nacos 下载与目录

bash 复制代码
# 下载
wget https://github.com/alibaba/nacos/releases/download/2.4.3/nacos-server-2.4.3.tar.gz

# 解压
tar -zxvf nacos-server-2.4.3.tar.gz -C /usr/local/
cd /usr/local/nacos

2.3 MySQL 初始化

sql 复制代码
-- 创建数据库
CREATE DATABASE IF NOT EXISTS nacos_config DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 授权
GRANT ALL PRIVILEGES ON nacos_config.* TO 'nacos'@'%' IDENTIFIED BY 'Nacos@123456';
FLUSH PRIVILEGES;

执行 Nacos 自带 SQL 脚本(在 conf/mysql-schema.sql):

bash 复制代码
mysql -h 10.1.1.20 -u nacos -p nacos_config < /usr/local/nacos/conf/mysql-schema.sql

2.4 conf/application.properties(三节点通用配置)

properties 复制代码
# ============ 集群模式 ============
spring.sql.init.platform=mysql

# ============ 节点数量(用于选举多数派)============
nacos.naming.election.majority=true
nacos.naming.quorum.majority=2

# ============ MySQL 数据源 ============
db.num=1
db.url.0=jdbc:mysql://10.1.1.20:3306/nacos_config?characterEncoding=utf8&connectTimeout=3000&socketTimeout=6000&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
db.user.0=nacos
db.password.0=Nacos@123456
db.pool.config.driver-class-name=com.mysql.cj.jdbc.Driver

# ============ 连接池 ============
db.pool.config.connectionTimeout=5000
db.pool.config.maximumPoolSize=20
db.pool.config.minimumIdle=5

2.5 conf/cluster.conf(集群节点列表)

每台节点使用相同的 cluster.conf,内容为各节点 IP:PORT:

makefile 复制代码
10.1.1.11:8848
10.1.1.12:8848
10.1.1.13:8848

注意 :IP 必须配置本机实际网络 IP,不要写 127.0.0.1localhost

2.6 JVM 参数优化 conf/nacos-jvm.env(或 bin/startup.sh 中调整)

bash 复制代码
# 生产环境建议
JAVA_OPT="${JAVA_OPT} -server -Xms4g -Xmx4g -Xmn2g"
JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
JAVA_OPT="${JAVA_OPT} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/nacos/logs/heapdump.hprof"
JAVA_OPT="${JAVA_OPT} -Dnacos.home=/usr/local/nacos"
JAVA_OPT="${JAVA_OPT} -Dcom.sun.management.jmxremote"
JAVA_OPT="${JAVA_OPT} -Dcom.sun.management.jmxremote.port=9999"
JAVA_OPT="${JAVA_OPT} -Dcom.sun.management.jmxremote.authenticate=false"
JAVA_OPT="${JAVA_OPT} -Dcom.sun.management.jmxremote.ssl=false"

2.7 Nginx 负载均衡配置

nginx 复制代码
upstream nacos_cluster {
    server 10.1.1.11:8848 weight=1 max_fails=2 fail_timeout=10s;
    server 10.1.1.12:8848 weight=1 max_fails=2 fail_timeout=10s;
    server 10.1.1.13:8848 weight=1 max_fails=2 fail_timeout=10s;
}

# HTTP 长连接配置(gRPC 必须)
upstream nacos_grpc {
    server 10.1.1.11:9848 weight=1;
    server 10.1.1.12:9848 weight=1;
    server 10.1.1.13:9848 weight=1;
}

server {
    listen 8848;
    server_name nacos.example.com;

    # 日志
    access_log /var/log/nginx/nacos_access.log;
    error_log  /var/log/nginx/nacos_error.log;

    # 代理 HTTP API
    location / {
        proxy_pass http://nacos_cluster;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

# gRPC 端口(四层代理)
stream {
    upstream nacos_grpc_stream {
        server 10.1.1.11:9848;
        server 10.1.1.12:9848;
        server 10.1.1.13:9848;
    }
    server {
        listen 9848;
        proxy_pass nacos_grpc_stream;
        proxy_timeout 60s;
    }
}

三、启停脚本

3.1 Nacos 启动脚本 start_nacos.sh

bash 复制代码
#!/bin/bash
# ============================================
# Nacos 集群启动脚本
# ============================================

NACOS_HOME=/usr/local/nacos
NACOS_USER=nacos
JAVA_HOME=/usr/local/jdk17
LOG_DIR=${NACOS_HOME}/logs
STARTUP_LOG=${LOG_DIR}/startup.log

# 环境检查
check_env() {
    if [ ! -d "${JAVA_HOME}" ]; then
        echo "[ERROR] JAVA_HOME ${JAVA_HOME} not found"
        exit 1
    fi
    if [ ! -f "${NACOS_HOME}/bin/startup.sh" ]; then
        echo "[ERROR] startup.sh not found in ${NACOS_HOME}/bin/"
        exit 1
    fi
    if [ ! -f "${NACOS_HOME}/conf/cluster.conf" ]; then
        echo "[ERROR] cluster.conf not found"
        exit 1
    fi
}

# 检查是否已运行
check_running() {
    PIDS=$(ps -ef | grep "nacos.nacos" | grep -v grep | awk '{print $2}')
    if [ -n "${PIDS}" ]; then
        echo "[WARN] Nacos is already running. PIDS: ${PIDS}"
        return 1
    fi
    return 0
}

# 启动
start_nacos() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] Starting Nacos ..."
    cd ${NACOS_HOME}/bin
    # 单机模式: startup.sh -m standalone
    # 集群模式: startup.sh (默认)
    bash startup.sh >> ${STARTUP_LOG} 2>&1 &

    # 等待启动完成
    echo "Waiting for Nacos to start ..."
    for i in {1..60}; do
        sleep 2
        if curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8848/nacos/v1/console/health/readiness | grep -q "200"; then
            echo "[$(date '+%Y-%m-%d %H:%M:%S')] Nacos started successfully!"
            return 0
        fi
        echo -n "."
    done
    echo ""
    echo "[ERROR] Nacos start timeout, please check log: ${STARTUP_LOG}"
    return 1
}

# 主流程
main() {
    check_env
    if check_running; then
        start_nacos
    fi
}

main

3.2 Nacos 停止脚本 stop_nacos.sh

bash 复制代码
#!/bin/bash
# ============================================
# Nacos 集群停止脚本
# ============================================

NACOS_HOME=/usr/local/nacos
SHUTDOWN_API="http://127.0.0.1:8848/nacos/v1/console/server/shutdown"
TIMEOUT=30

# 优雅下线
graceful_shutdown() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] Graceful shutdown via API ..."
    curl -X POST "${SHUTDOWN_API}" 2>/dev/null
    return $?
}

# 强制停止
force_kill() {
    echo "[WARN] Force killing Nacos ..."
    PIDS=$(ps -ef | grep "nacos.nacos" | grep -v grep | awk '{print $2}')
    for pid in ${PIDS}; do
        echo "Killing PID: ${pid}"
        kill -9 ${pid}
    done
}

# 主流程
main() {
    # 先尝试优雅下线
    if ! graceful_shutdown; then
        force_kill
        exit 0
    fi

    # 等待进程退出
    echo "Waiting for Nacos to stop ..."
    for i in $(seq 1 ${TIMEOUT}); do
        sleep 1
        PCOUNT=$(ps -ef | grep "nacos.nacos" | grep -v grep | wc -l)
        if [ ${PCOUNT} -eq 0 ]; then
            echo "[$(date '+%Y-%m-%d %H:%M:%S')] Nacos stopped gracefully."
            exit 0
        fi
    done

    # 超时则强制停止
    force_kill
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] Nacos stopped."
}

main

3.3 Nacos 重启脚本 restart_nacos.sh

bash 复制代码
#!/bin/bash
# ============================================
# Nacos 集群重启脚本
# ============================================

NACOS_HOME=/usr/local/nacos
SCRIPT_DIR=$(cd $(dirname $0) && pwd)

echo "=========================================="
echo "  Nacos Cluster Restart"
echo "  Time: $(date '+%Y-%m-%d %H:%M:%S')"
echo "=========================================="

echo "[STEP 1/2] Stopping Nacos ..."
bash ${SCRIPT_DIR}/stop_nacos.sh

# 确保完全停止
sleep 5
PIDS=$(ps -ef | grep "nacos.nacos" | grep -v grep | awk '{print $2}')
if [ -n "${PIDS}" ]; then
    echo "[ERROR] Failed to stop Nacos completely. PIDs: ${PIDS}"
    exit 1
fi

echo "[STEP 2/2] Starting Nacos ..."
bash ${SCRIPT_DIR}/start_nacos.sh

if [ $? -eq 0 ]; then
    echo "=========================================="
    echo "  Nacos restarted successfully!"
    echo "=========================================="
else
    echo "[ERROR] Nacos start failed after restart!"
    exit 1
fi

3.4 集群滚动重启脚本 rolling_restart.sh

bash 复制代码
#!/bin/bash
# ============================================
# 集群滚动重启(逐台重启,保证服务不中断)
# ============================================

NODES=("10.1.1.11" "10.1.1.12" "10.1.1.13")
SSH_USER="root"
REMOTE_SCRIPT_DIR="/usr/local/nacos/scripts"

for node in "${NODES[@]}"; do
    echo "=========================================="
    echo "  Restarting Nacos on ${node} ..."
    echo "=========================================="

    ssh ${SSH_USER}@${node} "bash ${REMOTE_SCRIPT_DIR}/stop_nacos.sh"
    sleep 10

    # 确认停止
    if ssh ${SSH_USER}@${node} "ps -ef | grep nacos.nacos | grep -v grep | wc -l"; then
        echo "[WARN] ${node} may still be running, force kill ..."
        ssh ${SSH_USER}@${node} "pkill -9 -f nacos.nacos"
        sleep 3
    fi

    ssh ${SSH_USER}@${node} "bash ${REMOTE_SCRIPT_DIR}/start_nacos.sh"

    # 等待节点就绪
    echo "Waiting for ${node} to be ready ..."
    for i in {1..30}; do
        sleep 2
        if curl -s -o /dev/null -w "%{http_code}" http://${node}:8848/nacos/v1/console/health/readiness | grep -q "200"; then
            echo "${node} is ready!"
            break
        fi
        echo -n "."
    done
    echo ""

    # 等待集群重新同步
    echo "Waiting for cluster sync (30s) ..."
    sleep 30
done

echo "=========================================="
echo "  Rolling restart completed!"
echo "=========================================="

3.5 集群状态检查脚本 check_cluster.sh

bash 复制代码
#!/bin/bash
# ============================================
# Nacos 集群状态检查
# ============================================

NODES=("10.1.1.11" "10.1.1.12" "10.1.1.13")
ALERT_THRESHOLD=2   # 少于 N 个存活节点时告警

alive_count=0

echo "=========================================="
echo "  Nacos Cluster Health Check"
echo "  Time: $(date '+%Y-%m-%d %H:%M:%S')"
echo "=========================================="

for node in "${NODES[@]}"; do
    status_code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 http://${node}:8848/nacos/v1/console/health/readiness 2>/dev/null)

    if [ "${status_code}" = "200" ]; then
        echo "[OK]  ${node}:8848 - UP"
        alive_count=$((alive_count + 1))
    else
        echo "[DOWN] ${node}:8848 - DOWN (HTTP ${status_code})"
    fi
done

echo ""
echo "Alive nodes: ${alive_count}/${#NODES[@]}"

if [ ${alive_count} -lt ${ALERT_THRESHOLD} ]; then
    echo "[ALERT] Cluster is degraded! Only ${alive_count} nodes alive."
    exit 1
else
    echo "[OK] Cluster is healthy."
    exit 0
fi

四、运维注意事项

4.1 日常维护要点

检查项 频率 说明
集群节点健康检查 每天 运行 check_cluster.sh 确认 3 节点均在线
MySQL 连接检查 每天 确认 Nacos 到 MySQL 的连接数正常(<50)
磁盘空间 每周 日志目录 /usr/local/nacos/logs 清理,防止写满
配置备份 每周 导出 Nacos 配置做异地备份
证书有效期 每月 如启用了 TLS,检查证书到期时间
JVM 堆内存监控 持续 接入 Prometheus/Grafana 监控 JVM 指标

4.2 日志管理

bash 复制代码
# Nacos 日志目录结构
/usr/local/nacos/logs/
├── nacos.log           # 主日志
├── naming-server.log   # 命名服务日志
├── config-server.log   # 配置服务日志
├── raft.log            # Raft 协议日志
├── jraft.log           # JRaft 日志
├── access_log.log      # 访问日志
├── alipay-jraft.log    # JRaft 详细日志
└── startup.log         # 启动日志

日志清理策略

bash 复制代码
# 保留最近 7 天日志
find /usr/local/nacos/logs/ -name "*.log" -mtime +7 -exec rm -f {} \;

# 或配置 logback 滚动策略:conf/nacos-logback.xml 中调整 maxHistory

4.3 配置备份与恢复

bash 复制代码
# 备份(通过 API 导出)
curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs/export" -o nacos_backup_$(date +%Y%m%d).zip

# 恢复(通过 API 导入)
curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs/import" \
  -F "file=@nacos_backup_20250101.zip" \
  -F "policy=OVERWRITE"

4.4 故障排查

4.4.1 节点启动失败
bash 复制代码
# 1. 检查启动日志
tail -200 /usr/local/nacos/logs/startup.log

# 2. 常见原因排查
# - 端口占用
netstat -tlnp | grep -E "8848|9848|9849"

# - MySQL 连接不通
telnet 10.1.1.20 3306
mysql -h 10.1.1.20 -u nacos -p -e "SELECT 1"

# - cluster.conf 中 IP 配置错误
cat /usr/local/nacos/conf/cluster.conf

# - JVM 内存不足
free -h
4.4.2 集群脑裂
症状 处理方式
部分节点间互相不可见 检查网络连通性和防火墙规则(端口 9848/9849)
多节点自认为 Leader 先全部停止 → 确认 MySQL 正常 → 逐个启动
4.4.3 配置无法生效
bash 复制代码
# 检查配置推送是否成功(查 Nacos 日志)
grep "config change" /usr/local/nacos/logs/nacos.log

# 确认客户端长轮询连接正常
curl http://node:8848/nacos/v1/cs/configs/listener
4.4.4 常见问题速查
问题 原因 解决
Connect refused Nacos 未启动 执行 start_nacos.sh
Service Unavailable 集群节点不足多数派 恢复至少 2 个节点
DB connection pool full 数据库连接数不够 调大 maximumPoolSize
日志刷满磁盘 未配置日志滚动 配置 logback maxHistory

4.5 高可用要点

scss 复制代码
┌─────────────────────────────────────────────────────────────────┐
│                     高可用设计核心原则                              │
├─────────────────────────────────────────────────────────────────┤
│  1. 集群节点数 = 2n+1 (奇数),生产环境至少 3 节点                     │
│  2. 多数派 (quorum) = n+1,即 3 节点集群至少需 2 节点存活              │
│  3. MySQL 使用主从 / MGR / Galera 保证数据库高可用                    │
│  4. 负载均衡层(Nginx/SLB)自身也需要主备 HA                           │
│  5. 节点分布在不同的物理机 / 机架 / 可用区                              │
│  6. 客户端必须配置所有节点地址,不能只配 VIP                            │
└─────────────────────────────────────────────────────────────────┘
客户端连接最佳实践
java 复制代码
// Spring Cloud 应用 - bootstrap.yml
spring:
  cloud:
    nacos:
      discovery:
        server-addr: nacos.example.com:8848   # VIP / 域名
      config:
        server-addr: nacos.example.com:8848

# 客户端也应配置节点列表用于直连兜底
# 通过 JVM 参数: -Dnacos.server-addr=10.1.1.11:8848,10.1.1.12:8848,10.1.1.13:8848
防火墙规则
bash 复制代码
# 集群内部互通 (所有节点之间)
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.1.1.0/24" port port="8848" protocol="tcp" accept'
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.1.1.0/24" port port="9848" protocol="tcp" accept'
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.1.1.0/24" port port="9849" protocol="tcp" accept'
firewall-cmd --reload

4.6 升级操作流程

makefile 复制代码
升级前:
  1. 备份数据库  → mysqldump nacos_config > backup.sql
  2. 导出配置    → curl 导出配置 zip
  3. 通知业务方  → 发布升级公告

升级步骤:
  1. 从 Nacos 负载均衡摘除目标节点
  2. 停止 Nacos → 替换 jar 包 / 解压新版本
  3. 启动 Nacos → 验证节点恢复正常
  4. 观察 10 分钟 → 确认无异常
  5. 依次滚动升级其他节点
  6. 升级完成后整体验证

回滚方案:
  1. 恢复旧版本 jar 包
  2. 恢复数据库备份(如有 schema 变更)
  3. 按相同滚动方式回滚

4.7 监控指标建议

指标类别 具体指标 告警阈值
可用性 节点存活数 < 3 告警
可用性 健康检查失败 连续 3 次告警
性能 HTTP 请求延迟 p99 > 500ms
性能 gRPC 连接数 突降 > 30%
JVM 堆内存使用率 > 80%
JVM Full GC 频率 > 5 次/小时
数据库 连接池活跃数 > 80%
数据库 慢查询数 > 10/min

附录:快速部署 Checklist

  • 3 台 Linux 服务器(JDK 17 已安装)
  • MySQL 实例已创建并初始化 nacos_config
  • application.properties 已配置 MySQL 连接
  • cluster.conf 已填写 3 节点 IP:8848
  • Nginx / SLB 已配置 8848 和 9848 代理
  • 防火墙已开放 8848、9848、9849 端口
  • 各节点 start_nacos.sh 启动成功
  • check_cluster.sh 确认 3 节点健康
  • Nacos 控制台 http://{VIP}:8848/nacos 可正常访问
相关推荐
PILIPALAPENG3 小时前
第4周 Day 4:Agent 工作流模式——编排复杂流程
前端·人工智能·python
KaMeidebaby3 小时前
卡梅德生物技术快报|蛋白的过表达质粒构建与生信分析实验全流程复盘
前端·数据库·其他·百度·新浪微博
ricardo19733 小时前
代码分割 + 路由懒加载 + 字体子集化:前端瘦身三板斧
前端·面试
dsyyyyy11013 小时前
CSS 2D 效果、3D 效果 与 Animation 总结
前端·css·3d
jerrywus3 小时前
Vibe Coding 实战:三天,一个人,一个 Claude Session Viewer——给三家 AI CLI 当统一会话浏览器
前端·claude·gemini
lichenyang4533 小时前
HarmonyOS AI 聊天模块架构复盘:从 UI、状态、Controller 到 Provider、SSE 与业务卡片
前端
wanger614 小时前
AI Agent
前端·javascript·人工智能
徐小夕4 小时前
面试官:AI生成到90%突然断了,你的解决方案是什么?(万字长文深度剖析)
前端·vue.js·算法