nacos集群版本为2.0.1
集群架构
Nacos集群的部署过程
注:至少3台服务器部署节点集群
安装3个以上Nacos
我们可以复制之前已经解压好的nacos文件夹,分别命名为nacos,nacos1,nacos2
第一步设置集群
nacos中bin目录下打开startup.cmd设置集群
第二步配置集群配置文件
由于是单机演示,需要更改nacos/conf目录下application.peoperties中server.port,防止端口冲突
设置端口分别8848、8849、8850
如果服务器有多个ip也要指定具体的ip地址,如:nacos.inetutils.ip-address=127.0.0.1
例如:
server.port=8850
nacos.inetutils.ip-address=127.0.0.1
在所有nacos目录下conf目录下,有文件cluster.conf.exqmple,将其命名为cluster.conf,并将每行配置成为ip:port.(请配置3个或者3个以上节点)
一个nacos在conf新增cluster.conf
#it is ip
#example
127.0.0.1:8848
127.0.0.1:8849
127.0.0.1:8850
或者试试
127.0.0.1:8845
127.0.0.1.8846
127.0.0.1.8847
初始化 nacos数据库
解压下载的安装包nacos-server-2.0.3.tar.gz至/usr/local目录,找到/nacos/conf下的nacos-mysql.sql脚本
在MySQL实例创建 nacos库并执行sql脚本
修改修改 Nacos 配置文件,指向MySQL实例,替换其内嵌数据库
在application.properties中找到如下配置,该配置默认为注释掉的,取消注释即可,修改数据库信息为实际的数据库信息后保存。其他nacos服务实例也需要做同样的修改
为了达到高可用,通常会有多个MySQL数据库实例,nacos的配置文件也需要指定每一个MySQL实例的信息,例如:
集群模式部署启动
分别执行nacos目录下的startup
startup -m cluster
启动失败原因
由于nacos配置文件application.properties中默认的数据库连接超时时间设置较短,如下图,因为网络延时等原因,MySQL可能会连接超时导致nacos启动报错,因此只需要将超时时间适当设置长一些即可
虚拟机内存不足,由于在vmvare创建虚拟机时,只给每个虚拟分配了1G的内存,从nacos的启动脚本startup.sh中可知,nacos以集群模式启动时,默认分配的java堆内存空间为2G,因此可判断是由于虚拟机内存不足导致nacos启动报错,修改虚拟机内存为2G后可以正常启动。
Nginx 配置
修改 Nginx 配置文件 nginx.conf如下:
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
#nacos集群负载均衡
upstream nacos-cluster {
server 192.168.230.129:8848;
server 192.168.230.130:8848;
server 192.168.230.131:8848;
}
server {
listen 80;
server_name 192.168.230.1;
location / {
#root html;
#index index.html index.htm;
proxy_pass http://nacos-cluster;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
微服务集成Nacos
依赖组件版本选型
由于Spring Cloud Alibaba与Spring Boot 及Spring Cloud版本的兼容性要求非常严格,如果依赖选错版本,很可能会导致服务启动报错从而导致启动失败。不过alibaba官方已经给我们整理出了推荐的版本依赖关系:
由于我们使用的nacos是最新的2.0.3版本,从以上表格可以查询到依赖的Spring Cloud Alibaba的版本为2.2.7.RELEASE。继续根据Spring Cloud Alibaba的版本查询毕业版本依赖关系表,如下图,可以找到依赖的Spring Cloud版本为Hoxton.SR12,依赖的Spring Boot版本为2.3.12.RELEASE
因此,通过上述查询,最终确定微服务依赖版本选型如下:
Spring Cloud Version |
Spring Cloud Alibaba Version |
Spring Boot Version |
Nacos Version |
Hoxton.SR12 |
2.2.7.RELEASE |
2.3.12.RELEASE |
2.0.3 |
注册中心
首先新建demo-project-parent父工程,根据4.1 依赖组件版本选型选型确定的版本,在父pom文件统一定义好依赖的组件以及版本,如下:
1.8
2.3.12.RELEASE
Hoxton.SR12
2.2.7.RELEASE
org.springframework.boot
spring-boot-dependencies
${spring-boot.version}
pom
import
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
com.alibaba.cloud
spring-cloud-alibaba-dependencies
${spring-cloud-alibaba.version}
pom
import
在父工程下新建服务提供者子模块micro-service-provider,并在pom文件引入依赖:
org.springframework.boot
spring-boot-starter-web
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
修改provider配置文件application.yml:
server:
port: 8081
spring:
application:
name: service-provider
cloud:
nacos:
discovery:
#nacos集群配置(Nginx)
server-addr: 192.168.230.1:80
provider启动类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
Provider测试Controller类:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ProviderController {
@Value("${server.port}")
String port;
@GetMapping("/hi")
public String hi(@RequestParam(value = "name", defaultValue = "zmx",required = false) String name) {
return "hello " + name + ", i'm provider, my port:" + port;
}
}
在父工程下新建服务消费者子模块micro-service-consumer,并在pom文件引入以下依赖:
org.springframework.boot
spring-boot-starter-web
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud
spring-cloud-starter-openfeign
org.springframework.cloud
spring-cloud-starter-loadbalancer
修改consumer配置文件:
server:
port: 8082
spring:
application:
name: service-consumer
cloud:
nacos:
discovery:
#nacos集群配置(Nginx)
server-addr: 192.168.230.1:80
在工程的启动类加上@EnableFeignClient注解,以开启FeignClient的功能:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
写一个feign客户端FeignClient,去调用provider服务的接口:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
//此处的value值对应于provider服务application配置文件中的spring.application.name
@FeignClient(value = "service-provider" )
public interface ProviderClient {
@GetMapping("/hi")
String hi(@RequestParam(value = "name", defaultValue = "zmx", required = false) String name);
}
写一个测试接口,让consumer去调用provider服务的接口:
import net.myibc.client.ProviderClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConsumerController {
@Autowired
ProviderClient providerClient;
@GetMapping("/hi-feign")
public String hiFeign(){
return providerClient.hi("feign");
}
}
启动provider和consumer两个工程,在nacos的【服务管理】-【服务列表】页面查看,可见2个服务都已经注册成功:
注意:这里启动所有服务后,可能在控制台只能查看到某一个服务,或者查不到注册的服务,查看nacos.log日志,发现报如下异常:
出现该异常的原因:当nacos客户端升级为2.x版本后,新增了gRPC的通信方式,新增了两个端口。这两个端口在nacos原先的端口上(默认8848),进行一定偏移量自动生成。
端口与主端口的偏移量描述:
9848:客户端gRPC请求服务端端口,用于客户端向服务端发起连接和请求
9849:服务端gRPC请求服务端端口,用于服务间同步等
7848:Nacos 集群通信端口,用于Nacos 集群间进行选举,检测等
因此,不难猜出,出现该问题的原因是由于nacos2.x版本新增的这两个端口没有在宿主机开启防火墙白名单,导致nacos实例之间无法进行服务间数据同步,因而在控制台无法查看到所有的服务注册实例信息。只需要在nacos宿主机执行以下命令即可:
[root@localhost bin]# firewall-cmd --add-port=9848/tcp --permanent
success
[root@localhost bin]# firewall-cmd --add-port=9849/tcp --permanent
success
[root@localhost bin]# firewall-cmd --add-port=7848/tcp --permanent
success
[root@localhost bin]# firewall-cmd --reload
Success
注意:如果是采用VIP/nginx代理集群的话,需要在nginx配置9848和9849这两个端口的TCP请求转发,否则客户端服务在启动时因为无法连接到服务端这两个端口,从而导致启动失败。如果不使用任何代理,在宿主机执行以上开启端口白名单命令后,只需要在客户端服务application配置文件里配置naocs集群的节点的ip和端口即可,配置如下:
Nginx配置nacos TCP转发配置:
#配置nacos TCP转发
stream {
upstream nacos1 {
server 192.168.230.129:9848;
server 192.168.230.130:9848;
server 192.168.230.131:9848;
}
server {
listen 9848;
proxy_pass nacos1;
}
upstream nacos2 {
server 192.168.230.129:9849;
server 192.168.230.130:9849;
server 192.168.230.131:9849;
}
server {
listen 9849;
proxy_pass nacos2;
}
}
在浏览器上输入http://127.0.0.1:8082/hi-feign,浏览器返回响应:
hello feign, i'm provider ,my port:8081
可见浏览器的请求成功调用了consumer服务的接口,consumer服务也成功地通过feign成功的调用了provider服务的接口。
Feign使用了Spring Cloud Loadbanlancer作为负载均衡器。可以通过修改provider的端口,再在本地启动一个新的provider服务,那么本地有2个provider 服务,端口分别为8081 和8083。在浏览器上多次调用http://127.0.0.1:8082/hi-feign,浏览器会交替显示:
hello feign, i'm provider ,my port:8081
hello feign, i'm provider ,my port:8083
此时控制台provider的实例数会变为2:
在父工程下新建nacos配置客户端子模块nacos-config-client,并在pom文件引入以下依赖:
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
在bootstrap.yml(一定是bootstrap.yml文件,不是application.yml文件)文件配置以下内容:
spring:
application:
name: nacos-config-client
cloud:
nacos:
config:
server-addr: 192.168.230.1:80
file-extension: yaml
prefix: nacos-config-client
profiles:
active: dev
在上面的配置中,配置了nacos config server的地址,配置的扩展名是ymal(目前仅支持ymal和properties)。注意是没有配置server.port的,sever.port的属性在nacos中配置。上面的配置是和Nacos中的dataId 的格式是对应的,nacos的完整格式如下:
${prefix}-${spring.profile.active}.${file-extension}
prefix 默认为 spring.application.name 的值,也可以通过配置项 spring.cloud.nacos.config.prefix来配置。
spring.profile.active 即为当前环境对应的 profile,详情可以参考 Spring Boot文档。 注意:当 spring.profile.active 为空时,对应的连接符 - 也将不存在,dataId 的拼接格式变成 ${prefix}.${file-extension}
file-exetension 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置。目前只支持 properties 和 yaml 类型。
启动nacos,登陆控制台http://192.168.230.1/nacos,创建一个Data ID ,完整的配置如图所示:
写一个RestController,在Controller上添加@RefreshScope注解实现配置的热加载。该注解只有加载需要动态更新配置的类上才会生效,如果将该注解加在启动类上,其他类中的动态更新是不会生效的,代码如下:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RefreshScope
public class ConfigController {
@Value("${username:lily}")
private String username;
@RequestMapping("/username")
public String get() {
return username;
}
}
启动工程nacos-provider,在浏览器上访问http://127.0.0.1:8084/username,可以返回在nacos控制台上配置的username的值zhangsan3。在nacos 控制台上更改username的配置为lisi,在不重启nacos-provider工程的情况下,重新访问http://127.0.0.1:8084/username,返回的是修改后的值lisi,可见nacos作为配置中心实现了热加载功能。
修改nacos中username配置前返回:
将nacos中username的值修改为lisi后重新请求返回:
注意:使用某些高版本的SpringCloud组件时,在启动nacos配置客户端服务的时候,可能会找不到bootstrap.yml配置文件,会报如下错误,只需要在系统环境变量中配置一下环境变量即可:spring.cloud.bootstrap.enabled=true
通常情况下,为了安全起见,客户端服务在访问nacos的时候都需要通过用户名和密码认证,nacos默认是没有开启认证的,如果需要开启认证,首先需要编辑/nacos/conf/application.properties配置文件,找到nacos.core.auth.enabled=false配置项,如下图,默认是false,表示权限认证是关闭的,修改为true即可开启认证。修改完成后需要重启所有nacos实例。
在application配置文件中配置nacos的用户名和密码,如下图,首先将服务用户名和密码配置为一个不存在的用户,启动服务验证权限配置是否生效:
启动服务,发现报了以下异常,code=403和unknown user,说明权限验证失败:
将用户名和密码修改为正确的之后,再次启动服务,可发现服务启动正常:
至此,说明nacos的权限认证配置已生效。