「这是我参与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.