1. 为什么单机Nacos扛不住生产流量1.1 从一次线上事故说起去年帮一个朋友排查问题他们团队做了一套微服务系统注册中心用的是单机版Nacos跑了大半年一直挺稳。结果有天晚上机房网络抖了一下Nacos所在的那台机器磁盘IO突然飙高整个注册中心直接失联。连锁反应非常快——网关拿不到服务列表服务间调用全部超时整个系统在几分钟内彻底瘫痪。事后复盘发现单机Nacos的配置数据存在内嵌Derby数据库里磁盘一卡读写全堵死服务注册和发现全部停摆。这件事让我更加坚定一个判断注册中心是整个微服务体系的地基地基不能只有一根桩。Nacos作为注册中心和配置中心的双重角色一旦挂掉影响面是全局性的。所以生产环境必须做集群而且要做持久化。1.2 集群方案的核心思路Nacos集群的核心逻辑其实不复杂拆开来看就三件事多个Nacos节点组成集群通过Raft协议Nacos 2.x默认用JRaft做数据一致性保证配置和注册信息在节点间同步外部存储统一收口把数据从内嵌Derby迁移到MySQL所有节点共享同一份数据源前置负载均衡用Nginx或者云负载均衡把请求分发到各个Nacos节点对外暴露统一入口这三件事组合起来就实现了两个层面的高可用计算层高可用某个Nacos节点挂了其他节点继续服务和存储层高可用MySQL做主从或者用云数据库数据不丢。1.3 这套方案适合谁如果你正在经历以下场景这篇文章就是写给你的微服务数量超过20个注册中心单点风险已经不可接受配置管理散落在各个环境需要统一管理和动态推送团队开始做多活或者容灾注册中心必须支持跨机房部署之前用Eureka或者Consul想迁移到Nacos但不确定集群怎么搭整篇文章我会按照实际搭建的顺序来写从环境规划、MySQL初始化、集群配置、Nginx负载均衡到启动验证和常见问题排查每一步都会给出具体的命令和配置。你跟着走一遍基本能搭出一套可用的生产级集群。2. 搭建前的环境规划与关键决策2.1 节点数量与规格怎么定Nacos集群的节点数推荐3个或5个这是Raft协议的特性决定的。Raft要求集群中超过半数节点存活才能正常工作3个节点允许挂1个5个节点允许挂2个。2个节点反而比单机更脆弱因为挂1个就失去多数派了整个集群不可写。节点规格方面我一般建议规模节点数单节点配置适用场景小型32C4G服务数50以内配置项不多中型34C8G服务数50-200有较多配置管理需求大型58C16G服务数200以上多机房部署JVM堆内存不要给太大Nacos本身不重4G内存的机器给2G堆就够了剩下的留给操作系统和堆外内存。给太大反而容易导致GC停顿时间变长。2.2 MySQL版本与部署方式MySQL建议用5.7或8.0这两个版本都经过大量生产验证。Nacos的建表SQL在官方GitHub仓库的distribution/conf目录下文件名是mysql-schema.sql。MySQL的部署方式有两种选择自建主从成本低但需要自己维护主从同步和故障切换云数据库省心自带高可用和备份但成本高一些如果团队没有专职DBA我强烈建议用云数据库。Nacos对MySQL的依赖很重配置读写、服务注册信息都走数据库MySQL一旦出问题Nacos集群也跟着废。自建MySQL做主从的话故障切换这块很容易出问题我见过太多主从切换后数据不一致导致Nacos起不来的案例。2.3 网络与端口规划Nacos涉及好几个端口搭建前必须理清楚否则防火墙一拦就是各种连不上8848主服务端口HTTP接口和OpenAPI都走这个9848gRPC端口Nacos 2.x新增的用于客户端和服务端的长连接通信9849gRPC端口用于集群内部节点间的通信7848Raft通信端口集群选举和数据同步用注意Nacos 2.x之后客户端会同时使用8848和9848端口。如果只开了8848客户端能连上但会频繁断连日志里会报gRPC相关的错误。这个坑我踩过排查了大半天才发现是端口没开全。另外集群内部节点之间需要互相通信所以9849和7848端口要在节点间互通。如果是跨机房部署这些端口的网络延迟要控制在10ms以内否则Raft选举会频繁超时。3. MySQL持久化配置的完整实操3.1 数据库初始化先在MySQL上创建Nacos专用的数据库和用户。不要用root账号权限太大不安全CREATE DATABASE nacos_config DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER nacos% IDENTIFIED BY YourStrongPassword123!; GRANT ALL PRIVILEGES ON nacos_config.* TO nacos%; FLUSH PRIVILEGES;字符集一定要用utf8mb4因为配置内容里可能有emoji或者特殊字符用utf8会报错。这个细节很多人会忽略等到配置推不上去才回头改。然后导入建表SQL。把官方提供的mysql-schema.sql下载下来执行mysql -h your-mysql-host -u nacos -p nacos_config mysql-schema.sql导入完成后检查一下表是否都创建成功USE nacos_config; SHOW TABLES;正常情况下会看到config_info、config_info_beta、his_config_info、tenant_info等表。如果少了哪张表说明SQL执行过程中出错了需要重新导入。3.2 关键表结构解读理解这几张核心表的作用对后续排查问题很有帮助config_info存储配置信息的主表每条配置记录都在这里his_config_info配置历史表每次修改配置都会在这里留一条记录用于回滚tenant_info租户信息对应Nacos的命名空间users、roles、permissions权限相关表如果开启了鉴权会用到实操心得his_config_info表会随着配置修改次数不断增长如果配置变更频繁这张表可能变得很大。建议定期清理超过3个月的历史记录否则会影响查询性能。3.3 数据源配置每个Nacos节点的application.properties里都要配置MySQL数据源。关键配置项如下spring.datasource.platformmysql db.num1 db.url.0jdbc:mysql://your-mysql-host:3306/nacos_config?characterEncodingutf8connectTimeout1000socketTimeout3000autoReconnecttrueuseUnicodetrueuseSSLfalseserverTimezoneAsia/Shanghai db.user.0nacos db.password.0YourStrongPassword123!这里有几个参数值得展开说connectTimeout1000连接超时1秒不要设太大否则MySQL挂了Nacos会卡很久socketTimeout3000读写超时3秒同样不宜过大autoReconnecttrue自动重连MySQL重启后Nacos能自动恢复连接useSSLfalse内网通信可以关掉SSL减少开销serverTimezoneAsia/Shanghai时区必须设置否则时间字段会差8小时如果MySQL是主从架构可以配置多个数据源db.num2 db.url.0jdbc:mysql://master-host:3306/nacos_config?... db.url.1jdbc:mysql://slave-host:3306/nacos_config?... db.user.0nacos db.password.0password db.user.1nacos db.password.1passwordNacos会自动做读写分离写操作走第一个数据源读操作轮询所有数据源。4. 集群配置文件详解4.1 cluster.conf的配置在Nacos的conf目录下创建cluster.conf文件列出所有集群节点的IP和端口192.168.1.101:8848 192.168.1.102:8848 192.168.1.103:8848注意这里必须写IP地址不能写localhost或者127.0.0.1。我见过有人图省事写了localhost结果集群一直起不来日志里报cannot find peer之类的错误。因为Nacos集群内部通信需要真实的IP地址来定位节点。另外这个文件里不要包含注释行有些版本的Nacos解析cluster.conf时对注释处理有问题会直接把注释行当成节点地址。4.2 application.properties的集群相关配置除了数据源配置还有几个集群相关的关键配置# 集群模式必须设置为cluster nacos.core.member.lookup.typecluster # 节点IP不配置的话Nacos会自动获取但多网卡机器建议手动指定 nacos.inetutils.ip-address192.168.1.101 # Raft端口 nacos.core.protocol.raft.port7848 # 鉴权相关生产环境必须开启 nacos.core.auth.enabledtrue nacos.core.auth.server.identity.keyyourIdentityKey nacos.core.auth.server.identity.valueyourIdentityValue nacos.core.auth.plugin.nacos.token.secret.keyyourSecretKeyMustBeBase64EncodedAndAtLeast32Bytesnacos.core.auth.plugin.nacos.token.secret.key这个值必须是Base64编码的字符串且解码后至少32字节。生成方法echo -n your-32-byte-secret-key-here!! | base64实操心得多网卡机器上Nacos自动获取的IP可能不是你想要的。比如机器上有docker0网桥Nacos可能拿到172.17.0.1这个地址导致集群通信失败。所以生产环境建议手动指定nacos.inetutils.ip-address。4.3 JVM参数调优修改bin/startup.sh中的JVM参数JAVA_OPT${JAVA_OPT} -Xms2g -Xmx2g -Xmn1g JAVA_OPT${JAVA_OPT} -XX:MetaspaceSize128m -XX:MaxMetaspaceSize320m JAVA_OPT${JAVA_OPT} -XX:UseConcMarkSweepGC -XX:CMSParallelRemarkEnabled JAVA_OPT${JAVA_OPT} -XX:UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction5如果是JDK 11以上建议换成G1JAVA_OPT${JAVA_OPT} -Xms2g -Xmx2g JAVA_OPT${JAVA_OPT} -XX:UseG1GC -XX:MaxGCPauseMillis200 JAVA_OPT${JAVA_OPT} -XX:MetaspaceSize128m -XX:MaxMetaspaceSize320m堆内存设置有个经验公式堆内存不超过物理内存的50%且不超过32G。超过32G后对象指针压缩失效反而浪费内存。Nacos一般2-4G堆就够了。5. Nginx负载均衡层的搭建5.1 为什么需要NginxNacos集群本身不提供统一的对外入口客户端需要知道所有节点地址才能连接。但让客户端配置所有节点地址有两个问题一是节点变更时客户端要改配置二是客户端需要自己实现负载均衡和故障转移。用Nginx做一层反向代理对外暴露一个统一地址客户端只需要配置这个地址就行。Nginx会自动把请求分发到各个Nacos节点某个节点挂了Nginx会自动摘除。5.2 Nginx配置详解upstream nacos_cluster { server 192.168.1.101:8848 weight1 max_fails2 fail_timeout10s; server 192.168.1.102:8848 weight1 max_fails2 fail_timeout10s; server 192.168.1.103:8848 weight1 max_fails2 fail_timeout10s; } server { listen 80; server_name nacos.yourdomain.com; 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_connect_timeout 5s; proxy_read_timeout 30s; proxy_send_timeout 30s; } }关键参数说明max_fails2 fail_timeout10s10秒内失败2次就摘除节点10秒后重新探测proxy_connect_timeout 5s连接超时5秒不要设太长proxy_read_timeout 30s读超时30秒Nacos的长轮询请求可能需要较长时间注意Nacos 2.x的gRPC通信9848端口不能通过普通的HTTP反向代理转发。如果客户端用2.x版本需要额外配置Nginx的stream模块来代理gRPC流量或者客户端直接连接Nacos节点。这是2.x版本相比1.x最大的变化很多老教程没提到这点导致升级后各种连接问题。5.3 gRPC流量的处理如果要用Nginx代理gRPC需要配置stream块stream { upstream nacos_grpc { server 192.168.1.101:9848; server 192.168.1.102:9848; server 192.168.1.103:9848; } server { listen 9848; proxy_pass nacos_grpc; proxy_connect_timeout 5s; proxy_timeout 300s; } }但stream模块是四层代理不支持HTTP的路径路由。而且gRPC的长连接特性会导致负载不均衡所以更推荐的做法是客户端直接配置Nacos节点地址让Nacos客户端自己做负载均衡。Nacos客户端本身支持配置多个服务端地址会自动做故障转移。6. 集群启动与验证6.1 启动顺序三个节点依次启动不要同时启动。同时启动容易导致Raft选举冲突集群起不来。建议间隔10-20秒# 节点1 sh bin/startup.sh -m cluster # 等待15秒 # 节点2 sh bin/startup.sh -m cluster # 等待15秒 # 节点3 sh bin/startup.sh -m cluster启动后检查日志logs/start.out看到Nacos started successfully in cluster mode就说明启动成功了。6.2 集群状态验证访问任意节点的集群状态接口curl http://192.168.1.101:8848/nacos/v1/ns/operator/servers返回的JSON里会列出所有节点及其状态state为UP表示节点正常。如果某个节点状态是DOWN检查该节点的日志和网络连通性。还可以通过Nacos控制台查看集群状态。登录控制台后在集群管理-节点列表里能看到所有节点的状态和元数据。6.3 持久化验证验证数据是否真的写到了MySQL在Nacos控制台创建一个配置登录MySQL执行SELECT * FROM config_info;如果能看到刚才创建的配置说明持久化配置生效了再验证一下集群同步在节点1创建一个配置然后访问节点2和节点3的控制台看是否能查到同样的配置。如果能查到说明集群间数据同步正常。7. 常见问题与排查技巧实录7.1 集群启动失败排查表现象可能原因排查方法启动后日志报cannot find peercluster.conf配置错误检查IP和端口是否正确不要用localhost节点状态一直是DOWN网络不通或端口未开telnet测试7848和9849端口启动报数据库连接失败数据源配置错误检查URL、用户名、密码用mysql客户端测试连接集群选举频繁超时网络延迟大或时钟不同步检查NTP时间同步网络延迟应小于10ms控制台能访问但客户端连不上gRPC端口未开检查9848端口是否开放7.2 几个我踩过的坑坑一cluster.conf里写了注释。有次我在cluster.conf里加了一行# 这是集群节点结果Nacos启动时报错说找不到名为#的节点。后来发现Nacos解析这个文件时不会跳过注释行直接按行读取。所以这个文件里只能写IP:端口不能有任何其他内容。坑二MySQL时区问题。数据源URL里没加serverTimezone参数结果配置的创建时间比实际时间少了8小时。虽然不影响功能但排查问题时看时间戳会很困惑。加上serverTimezoneAsia/Shanghai就好了。坑三JVM堆内存给太大。有次给Nacos配了8G堆结果Full GC一次要好几秒期间服务注册全部超时。后来降到2GGC停顿控制在200ms以内问题就消失了。Nacos本身不重堆内存不是越大越好。坑四Nginx只代理了8848。客户端用Nacos 2.x只配置了Nginx的80端口结果客户端频繁断连。日志里报grpc connection failed。后来在客户端配置里直接写了Nacos节点地址绕过Nginx问题解决。所以2.x版本要么客户端直连节点要么Nginx同时代理8848和9848。7.3 性能调优建议连接池调优Nacos的数据库连接池默认配置偏保守高并发场景下可以适当调大db.pool.config.maximumPoolSize一般设置为CPU核数的2倍Tomcat线程数server.tomcat.max-threads默认200服务数多的时候可以调到500长轮询超时nacos.config.long-poll.timeout默认30秒如果客户端网络不稳定可以适当调大定期清理历史配置his_config_info表定期清理避免影响查询性能8. 生产环境的一些经验补充8.1 监控告警配置集群搭好只是第一步后续的监控才是保证稳定运行的关键。建议监控以下指标节点存活状态通过/nacos/v1/ns/operator/servers接口定期探测JVM指标堆内存使用率、GC次数和耗时数据库连接池活跃连接数、等待连接数接口响应时间配置读取和注册接口的P99延迟告警阈值建议节点DOWN立即告警堆内存使用率超过80%告警接口P99超过500ms告警。8.2 备份与恢复策略MySQL定期备份至少每天一次全量备份binlog保留7天配置导出Nacos控制台支持导出配置建议每周导出一次作为额外备份恢复演练定期做恢复演练确保备份可用8.3 版本升级注意事项Nacos版本升级要谨慎尤其是1.x升2.x变化很大。升级前先在测试环境验证确认客户端兼容性。升级时采用滚动升级先停一个节点升级验证没问题后再升级其他节点。升级前务必备份数据库。我个人在实际操作中的体会是Nacos集群搭建本身技术难度不大难点在于细节。端口有没有开全、cluster.conf格式对不对、MySQL连接参数有没有配好、Nginx有没有正确代理gRPC流量这些细节任何一个出问题都会导致集群不可用。所以搭建完成后一定要做完整的验证包括节点故障模拟、数据库故障模拟确保高可用真正生效而不是纸面上看起来高可用。
阅读完成 · 觉得有帮助?