CentOS 7.2下Nacos 1.4.2集群部署

5,841 阅读4分钟

「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。

Nacos官网已经提供了集群部署说明文档,但官方文档较为简单,对新手不太友好,容易踩坑。因此,这里将所实践的Nacos集群部署过程详细记录下来。

1 环境说明

  • 操作系统:CentOS 7.2
  • Nacos版本:1.4.2
  • Nacos集群规划:3节点分别部署在3台虚拟机上
  • 数据库:MySQL 5.7(单点)

2 集群部署步骤

2.1 下载安装包并解压

Nacos 1.4.2下载地址:github.com/alibaba/nac…

将安装包上传至3台服务器后,执行解压:

tar -zxvf nacos-server-1.4.2.tar.gz

2.2 数据库初始化

这里选择MySQL作为Nacos的支撑数据库,MySQL的详细安装过程可参考:《CentOS/RedHat下RPM方式安装MySQL 5.7》

2.2.1 创建nacos数据库

登录MySQL的root用户:

mysql -uroot -p

创建nacos数据库:

create database nacos character set utf8 collate utf8_bin;

2.2.2 创建nacos用户

create user 'nacos'@'%' identified by '密码';

2.2.3 用户授权

给nacos用户授权并刷新权限配置:

grant all privileges on nacos.* to 'nacos'@'%';
flush privileges;

2.2.4 执行初始化脚本文件

进入到安装包解压后的conf目录下,执行初始化数据库的脚本文件:

cd nacos/conf
mysql -unacos -p密码 nacos < nacos-mysql.sql

2.3 application.properties

conf/application.properties文件中,修改数据库相关的配置:

#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
spring.datasource.platform=mysql

### Count of DB:
db.num=1

### Connect URL of DB:
db.url.0=jdbc:mysql://xxx.xxx.xxx.xxx:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=nacos
db.password.0=xxxx

另,nacos服务端口默认为8848,也在此文件中:

server.port=8848

2.4 集群配置

conf文件夹下,将cluster.conf.example文件重命名为cluster.conf

mv cluster.conf.example cluster.conf

删除文件中原有的示例ip、port,维护实际的ip、port:

xxx.xxx.xxx.xxx1:8848
xxx.xxx.xxx.xxx2:8848
xxx.xxx.xxx.xxx3:8848

2.5 端口开放

Nacos从 1.4.0 版本开始,除了主端口 8848 以外,还需要额外对外暴露 7848 端口,该端口是raft集群协议的通讯端口,用于集群的节点选举、检测等。

firewall-cmd --zone=public --add-port=8848/tcp --permanent
firewall-cmd --zone=public --add-port=7848/tcp --permanent
service firewalld restart

2.6 集群启动

分别启动三个Nacos节点:

cd nacos/bin
sh startup.sh && tail -f ../logs/start.out

2.7 集群验证

集群启动完成后,通过任意一个ip地址,均可访问Nacos控制台(默认的用户名/密码都是nacos):http://xxx.xxx.xxx.xxx1:8848/nacos/#/login

登录后,通过【集群管理】 - 【节点状态】页面,首先能够看到当前集群下有三个节点,且状态均为“UP”:

然后还需要点击“节点元数据”,来确认集群中已选举出了leader节点,以此证明集群正常运行:

2.8 通过Nginx实现负载均衡

我们可以通过Nginx为Nacos做一个简单的负载均衡,Nginx配置如下:

upstream nacos_server {
server xxx.xxx.xxx.xxx1:8848;
server xxx.xxx.xxx.xxx2:8848;
server xxx.xxx.xxx.xxx3:8848;
}

server {
    listen       18848;
    proxy_set_header Host $http_host;
    server_name localhost;
    
    location / {
        proxy_pass http://nacos_server;
        index index.html;
    }		 
}

Nginx配置完成后,来验证一下Nacos的负载地址是否可用。

先通过Nginx负载地址来访问Nacos控制台,【集群管理】 - 【节点状态】页面中仍能够看到三个Nacos服务节点。

再将程序中的Nacos地址修改为Nginx的负载地址,启动程序。在【服务管理】 - 【服务列表】中可以看到注册上来的应用程序:

3 踩坑回顾

3.1 坑从何来?

7848 端口是从 1.4.0 版本开始才需要的。

1.4.0-BETA的版本日志 中有提到:
At the same time, jraft is used to replace the old self-implemented raft protocol to improve the performance and accuracy of raft semantics.

翻译如下:
同时,使用jraft取代了旧有的自实现式的raft协议,用以提高性能和raft语义的准确性。

这个 7848 端口就是jraft使用的。

巨坑!!! 在官网的部署文档中,并没有 7848 端口的相关说明,因此对于第一次使用 1.4.x 版本的人来说,并不知道需要开放 7848 端口,尤其是对于原来使用过老版本的人来说,升级到 1.4.x 后,Nacos集群部署因未开放 7848 端口而出现错误时,凭以往低版本Nacos的使用经验去排查错误,很难第一时间定位问题所在。

3.2 错误现象

SpringBoot工程连接Nacos,日志中出现以下错误信息:

com.alibaba.nacos.api.exception.NacosException: failed to req API:xxx.xxx.xxx.xxx:8848/nacos/v1/ns/instance. code:500 msg: java.net.SocketTimeoutException: Read timed out

java.lang.IllegalStateException: failed to req API:/nacos/v1/ns/instance after all servers([xxx.xxx.xxx.xxx:8848]) tried: failed to req API:xxx.xxx.xxx.xxx:8848/nacos/v1/ns/instance. code:500 msg: java.net.SocketTimeoutException: Read timed out

com.alibaba.nacos.api.exception.NacosException: failed to req API:xxx.xxx.xxx.xxx:8848/nacos/v1/ns/instance/beat. code:500 msg: 

java.net.ConnectException: no available server, currentServerAddr : http://xxx.xxx.xxx.xxx:8848

具有迷惑性的是,logs/start.out启动日志显示集群启动成功,且控制台观察节点状态均为“UP”:

展开节点的元数据信息,会发现有的节点信息项较少(没有raftMetaData),有的节点leader显示为null

此处的截图来自 1.4.2 版本,其节点元数据在 7848 端口不通的情况下所展示出的信息已经比较丰富了,能够体现出 7848 作为raft端口,容易引导问题定位。而笔者踩坑的时候安装的是 1.4.1 版本,印象中 7848 端口不通的情况下所展示的三个节点的原数据信息都十分简单,且体现不出 7848 端口,因此没有通过节点元数据定位到问题所在。

3.3 Nacos日志排查

nacos/logs目录下,有着二十余个不同的日志文件:

上面已经提到了,启动日志start.out一切正常。

接着排查nacos.log,发现存在如下错误信息(对于问题的定位没有太多帮助):

java.lang.IllegalStateException: old raft protocol already stop

com.alibaba.nacos.api.exception.NacosException: com.alibaba.nacos.consistency.exception.ConsistencyException: The conformance protocol is temporarily unavailable for reading, No leader at term 0.

然后看nacos-cluster.log

2022-01-01 14:54:57,690 ERROR failed to report new info to target node : xxx.xxx.xxx.xxx:8848, error : caused: Connection refused;

2022-01-01 14:56:28,663 WARN [serverlist] updated to : [Member{ip='xxx.xxx.xxx.xxx', port=8848, state=UP, extendInfo={raftPort=7848}}, Member{ip='xxx.xxx.xxx.xxx', port=8848, state=UP, extendInfo={raftPort=7848}}, Member{ip='xxx.xxx.xxx.xxx', port=8848, state=UP, extendInfo={raftPort=7848}}]

此处“ERROR”报错信息比较坑,说的是 8848 端口拒绝连接,但实际上能够确定 8848 端口是开放的,通过 8848 端口在浏览器中可以顺利访问Nacos控制台。反而是“WARN”警告信息,让笔者第一次发现了 7848 端口的存在,这时笔者还完全不懂“raftPort”是个什么东西,抱着试试看的心理,在防火墙上打通了 7848 端口,然后就像奇迹降临一样,解决了已经困惑了5个小时的问题。

问题解决后,又将Nacos的其他日志也看了看,在alipay-jraft.log中其实是有更加清晰、明确的 7848 端口无法连接的错误信息的:

2022-01-01 14:58:56,243 WARN Node <naming_persistent_service/xxx.xxx.xxx.xxx:7848> channel init failed, address=xxx.xxx.xxx.xxx:7848.

2022-01-01 14:58:59,567 ERROR Fail to connect xxx.xxx.xxx.xxx:7848, remoting exception: java.util.concurrent.ExecutionException: io.grpc.StatusRuntimeException: UNAVAILABLE: io exception.