图源:laiketui.com
Nacos 是 Alibaba 研发的用于 Spring Cloud Alibaba 的服务注册中心组件,符合 Spring Cloud 官方标准,同样被 Spring Cloud 官方接纳,所以我们可以在 Spring Cloud 中用 Nacos 替换 Eureka 作为服务注册中心。
本文将演示如何用 Nacos 作为注册中心。
本文的示例项目基于上篇文章。
Nacos 服务端的安装和启动可以参考这篇文章。
本篇文章使用的 Nacos 版本是1.4.1。
在根项目中添加 Spring Cloud Alibaba 相关依赖:
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>2.2.5.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
在子模块中删除 Eureka 相关依赖,并添加 Nacos 客户端相关依赖:
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
在子模块的配置文件中添加 Nacos 服务端地址:
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
因为这里使用了一个低版本的 Nacos,其负载均衡使用的是 Ribbon 而非上文介绍的 LoadBalancer,它们定制负载均衡策略的方式略有不同,所以这里可能还需要删除
@LoadBalancerClient
注解,否则会导致应用启动失败。
启动2个子模块(Eureka 除外)的3个实例,此时在 Nacos 控制面板就能看到注册的服务信息:
对接口 localhost:8080/order/101 进行请求,就能观察到两个 shopping-user 服务实例轮流接受请求并返回数据,所以 Ribbon 同样默认使用轮询策略。
在 Nacos 中,服务按照集群来进行组织,这可以用以下的图进行表示:
如果服务没有特别设置,默认会分配到 DEFAULT 集群:
下面我们看如何设置服务所在的集群。
在子模块 shopping-user 和 shopping-order 配置文件中添加以下内容:
spring:
cloud:
nacos:
discovery:
cluster-name: HZ # 集群名称
这样产生的3个实例都会被分配到 HZ 这个集群。
集群名称可以随意填写,这里用 HZ 代表杭州,BJ代表北京,表示两个异地机房。
重启3个服务实例,再次进入 Nacos 控制面板的服务详情,就能看到这3个服务实例都归属于 HZ 这个集群。
为了进行对比,这里再添加一个 shopping-user 实例,并分配到 BJ 集群。
Nacos 控制面板中应该会出现一个新的实例,并属于 BJ 集群。
集群是为了能够按地域和网络划分服务实例,以便服务实例能够“就近”访问接口,比如理想情况下 HZ的 shopping-order 就应该访问 HZ的 shopping-user 的接口,只有在集群内的服务都挂掉的情况下才会跨集群访问。
但默认的情况下并非如此,实际访问 localhost:8080/order/101 就能发现,依然会有几率出现 HZ 集群的 shopping-order 访问 BJ 集群的 shopping-user 实例的情况出现,这是因为此时我们使用的依然是 Ribbon 默认的轮询策略。
要实现我们希望的“优先访问本集群内的服务”这个效果,需要让 Ribbon 使用 Nacos 策略。
修改子模块 shopping-order 的配置文件,添加以下配置:
shopping-user: #服务名称
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则
这个配置可以让子模块 shopping-order 的负载均衡策略变成NacosRule
。
重启子模块 shopping-order。
现在再访问 localhost:8080/order/101 就不会再出现跨集群访问的情况。
如果我们关闭 HZ 集群的两个 shopping-user 实例,再次访问就能看到进行了跨集群调用,并且 shopping-order 实例的控制台输出以下警告信息:
07-16 15:54:20:987 WARN 32960 --- [nio-8080-exec-4] c.alibaba.cloud.nacos.ribbon.NacosRule : A cross-cluster call occurs,name = shopping-user, clusterName = HZ, instance = [Instance{instanceId='192.168.0.46#8083#BJ#DEFAULT_GROUP@@shopping-user', ip='192.168.0.46', port=8083, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='BJ', serviceName='DEFAULT_GROUP@@shopping-user', metadata={preserved.register.source=SPRING_CLOUD}}]
这里的 A cross-cluster call occurs 说明了一次跨集群调用已经发生,言下之意是我们需要检查同集群下的服务是否挂掉了,可能需要重启服务。
实际上 Nacos 策略的具体内容是:优先在本集群内用乱序策略访问服务,本集群内服务都不可用时,跨集群访问。
可以用权重控制同一个集群下的同一个服务的不同实例的访问优先级。
默认情况下服务实例的权重都是 1:
权重的可选值是0~1之间。可以通过编辑修改权重:
这里将 8081 端口的实例权重修改为 0.1,为 8082 端口权重的 1/10,现在对接口 localhost:8080/order/101 进行多次访问,可以看到即使访问了20多次,8081 端口的实例也只会发生2次接口调用,概率大约是后者的1/10。
特别的是,如果将权重修改为0,那么服务将不再会被访问。
Nacos提供了namespace来实现环境隔离功能。
默认情况下,Nacos 会存在一个 public 命名空间:
服务默认都在 public 命名空间中:
可以添加新的命名空间:
命名空间 ID 需要在 Nacos 中唯一,新建的时候可以不填,Nacos 会生成一个 UUID 作为 ID:
在子模块 shopping-order 配置中添加:
spring:
cloud:
nacos:
discovery:
namespace: fbb59711-b6c7-4cd0-b796-c497f0608c77
重启服务后就能在 Nacos 控制面板中看到 shopping-order 这个服务已经归属到 dev 这个命名空间下了。
现在访问接口 localhost:8080/order/101 就会报错:
No instances available for shopping-user
因为此时 shopping-order 和 shopping-user 分属不同命名空间,是不可见的,不能互相访问。
可以利用这点对不同开发环境的接口进行隔离。
Nacos 的服务实例分为临时实例与非临时实例,默认是临时实例。
它们的区别是:
此外,临时实例仅通过30秒一次的心跳检测向 Nacos 上报状况,而非临时实例则由 Nacos 主动发起请求进行检测状态,健康状态监测的时效性要更好,但同样也更消耗 Nacos 服务器的资源。
可以通过以下配置将服务实例修改为非临时实例:
spring:
cloud:
nacos:
discovery:
ephemeral: false # 设置为非临时实例
Nacos 和服务消费者、提供者的关系可以用下图表示:
Nacos与eureka的共同点
Nacos与Eureka的区别
The End,谢谢阅读。
本文的完整实例可以从这里获取。