Spring Cloud Alibaba:Nacos服务注册与发现

动态服务发现对以服务为中心的(例如微服务和云原生)应用架构方式非常关键。​​Nacos​​​支持​​DNS-Based​​​和​​RPC-Based​​​(​​Dubbo​​​、​​gRPC​​​)模式的服务发现。​​Nacos​​也提供实时健康检查,以防止将请求发往不健康的服务实例。

服务(​​Service​​​)是​​Nacos​​​世界的一等公民。​​Nacos​​支持几乎所有主流类型的服务的发现、配置和管理:

  • ​Kubernetes Service​
  • ​gRPC & Dubbo RPC Service​
  • ​Spring Cloud RESTful Service​

​Nacos​​​的配置特性将在下一篇博客中进行介绍,并且先以​​Spring Cloud RESTful Service​​​为例子,​​Kubernetes Service​​​和​​gRPC & Dubbo RPC Service​​​在以后介绍​​Kubernetes​​​和​​Dubbo​​时再进行补充。

​Eureka​​也有服务注册与发现的功能,博主在下面这几篇博客中进行了介绍:

  • ​​Spring Cloud 之Eureka初使用​​
  • ​​Spring Cloud 之Eureka高可用​​
  • ​​Spring Cloud 之使用RestTemplate实现微服务之间相互请求的三种方式​​
  • ​​Spring Cloud 之Feign实现微服务之间相互请求​​

但由于​​Eureka2.0​​​闭源,以及​​Nacos​​​本身的优势(服务在线管理、配置动态刷新等),并且​​Nacos​​久经双十一的考验。

功能

Nacos

Eureka

说明

注册中心



服务治理基本功能,负责服务中心化注册

配置中心



​Eureka​​​需要​​Config​​的配合来实现配置中心,且不提供管理界面

配置动态刷新



​Eureka​​​需要​​Config​​​、​​MQ​​​以及​​Webhook​​​的配合来实现配置动态刷新,而​​Nacos​​​采用​​Netty​​​保持​​TCP​​长连接实时推送

可用区AZ



对服务集群划分不同区域,实现区域隔离,并提供容灾自动切换

分组



​Nacos​​可以根据业务和环境进行分组管理

元数据



提供服务标签数据,例如环境或服务标识

权重



​Nacos​​默认提供权重设置功能,调整承载流量压力

健康检查



​Nacos​​​支持由客户端或服务端发起的健康检查,​​Eureka​​是由客户端发起心跳

负载均衡



均提供负责均衡策略,​​Eureka​​​采用​​Ribbon​

管理界面



​Nacos​​​支持对服务在线管理,​​Eureka​​只是预览服务状态

​Spring Cloud Alibaba​​版本关系:

下载与运行Nacos

Windows下载

直接下载​​zip​​​后缀的​​nacos-server​​压缩包。

Spring Cloud Alibaba:Nacos服务注册与发现_spring cloud_03


解压后的目录如下图所示:

Spring Cloud Alibaba:Nacos服务注册与发现_spring_04


运行​​Nacos​​:

startup.cmd -m standalone

Spring Cloud Alibaba:Nacos服务注册与发现_spring cloud_05


可以访问管理界面(要加​​/nacos​​​路径,因为有默认配置​​server.servlet.cnotallow=/nacos​​)。

Spring Cloud Alibaba:Nacos服务注册与发现_java_06

Linux下载

复制链接地址,用于使用​​wget​​命令进行下载。

Spring Cloud Alibaba:Nacos服务注册与发现_spring_07

wget https://github.com/alibaba/nacos/releases/download/1.4.2/nacos-server-1.4.2.tar.gz

Spring Cloud Alibaba:Nacos服务注册与发现_spring cloud_08


解压:

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

Spring Cloud Alibaba:Nacos服务注册与发现_spring cloud_09


解压后的目录如下图所示:

Spring Cloud Alibaba:Nacos服务注册与发现_java_10


运行​​Nacos​​:

./startup.sh -m standalone

Spring Cloud Alibaba:Nacos服务注册与发现_spring_11


用户名和密码都是​​nacos​​。

Spring Cloud Alibaba:Nacos服务注册与发现_spring_12

Spring Cloud Alibaba:Nacos服务注册与发现_maven_13

创建服务

创建​​AlibabaBlog maven​​​工程作为父​​module​​​,再创建​​nacos​​​和​​consumer​​​两个子​​module​​。

Spring Cloud Alibaba:Nacos服务注册与发现_maven_14


​​AlibabaBlog module

​pom.xml​​:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.kaven</groupId>
<artifactId>AlibabaBlog</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>

<description>Spring Cloud Alibaba</description>
<modules>
<module>nacos</module>
<module>consumer</module>
</modules>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
</parent>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<spring-cloud-alibaba-version>2.2.6.RELEASE</spring-cloud-alibaba-version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>

nacos module

结构如下图所示:

Spring Cloud Alibaba:Nacos服务注册与发现_微服务_15


​pom.xml​​:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>AlibabaBlog</artifactId>
<groupId>com.kaven</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>nacos</artifactId>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
</project>

​application.yml​​:

server:
port: 8080

spring:
application:
name: nacos
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848

​NacosController​​接口类:

package com.kaven.alibaba.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* @Author: ITKaven
* @Date: 2021/11/08 17:00
* @Blog: https://kaven.blog.csdn.net
* @Leetcode: https://leetcode-cn.com/u/kavenit
* @Notes:
*/

@RestController
public class NacosController {

@GetMapping("/nacos")
public String getMessage() {
System.out.println("被请求了!");
return "spring cloud alibaba nacos";
}
}

​NacosApplication​​启动类:

package com.kaven.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
* @Author: ITKaven
* @Date: 2021/11/08 16:39
* @Blog: https://kaven.blog.csdn.net
* @Leetcode: https://leetcode-cn.com/u/kavenit
* @Notes:
*/

@SpringBootApplication
@EnableDiscoveryClient
public class NacosApplication {
public static void main(String[] args) {
SpringApplication.run(NacosApplication.class);
}
}

​@EnableDiscoveryClient​​注解要加上。

consumer module

结构如下图所示:

Spring Cloud Alibaba:Nacos服务注册与发现_spring cloud_16

​pom.xml​​:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>AlibabaBlog</artifactId>
<groupId>com.kaven</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>consumer</artifactId>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
</project>

​application.yml​​:

server:
port: 8090

spring:
application:
name: consumer
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848

​ConsumerController​​接口类:

package com.kaven.alibaba.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

/**
* @Author: ITKaven
* @Date: 2021/11/08 17:10
* @Blog: https://kaven.blog.csdn.net
* @Leetcode: https://leetcode-cn.com/u/kavenit
* @Notes:
*/

@RestController
public class ConsumerController {

@Resource
private RestTemplate restTemplate;

@GetMapping("/nacos")
public String getNacos() {
return restTemplate.getForObject("http://nacos/nacos", String.class);
}
}

​ConsumerApplication​​启动类:

package com.kaven.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

/**
* @Author: ITKaven
* @Date: 2021/11/08 17:07
* @Blog: https://kaven.blog.csdn.net
* @Leetcode: https://leetcode-cn.com/u/kavenit
* @Notes:
*/

@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class);
}

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

​@EnableDiscoveryClient​​注解要加上。

启动两个子​​module​​。

Spring Cloud Alibaba:Nacos服务注册与发现_java_17


服务注册成功了。

Spring Cloud Alibaba:Nacos服务注册与发现_微服务_18


​consumer​​​使用​​RestTemplate​​​成功调用注册在​​Nacos​​上的服务。

Spring Cloud Alibaba:Nacos服务注册与发现_spring cloud_19


Spring Cloud Alibaba:Nacos服务注册与发现_java_20

多服务负载均衡

启动​​3​​​个​​nacos​​​服务,首先要修改​​NacosApplication​​的运行配置,操作如下所示:

Spring Cloud Alibaba:Nacos服务注册与发现_spring_21


Spring Cloud Alibaba:Nacos服务注册与发现_maven_22


依次修改端口启动服务(修改一次端口,启动一次服务)。

Spring Cloud Alibaba:Nacos服务注册与发现_java_23


​3​​​个​​nacos​​服务启动成功。

Spring Cloud Alibaba:Nacos服务注册与发现_spring cloud_24


Spring Cloud Alibaba:Nacos服务注册与发现_微服务_25

多次请求​​http://localhost:8090/nacos/​​:

Spring Cloud Alibaba:Nacos服务注册与发现_spring cloud_26


Spring Cloud Alibaba:Nacos服务注册与发现_微服务_27


Spring Cloud Alibaba:Nacos服务注册与发现_java_28


Spring Cloud Alibaba:Nacos服务注册与发现_spring_29


这里很显然是轮询的负载均衡策略,而​​Nacos​​​的负载均衡策略默认是轮询。但这里并没有使用到​​Nacos​​​的负载均衡策略,而是使用了​​Spring Cloud​​​中的负载均衡策略,因为在控制台上修改服务的权重是无效的,仍然是轮询;要想使用自定义的负载均衡策略,就需要实现自定义的​​IRule​​实现类,这在下面这篇博客中有介绍:

  • ​​Spring Cloud 之Ribbon负载均衡​​

而​​Nacos​​​已经实现了自定义的​​IRule​​​实现类​​NacosRule​​​,有兴趣可以去探索一下​​NacosRule​​​类的源码。因此需要将​​NacosRule​​​实例变成​​bean​​​,便于​​Spring​​​容器管理,修改​​ConsumerApplication​​类如下:

package com.kaven.alibaba;

import com.alibaba.cloud.nacos.ribbon.NacosRule;
import com.netflix.loadbalancer.IRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.web.client.RestTemplate;

/**
* @Author: ITKaven
* @Date: 2021/11/08 17:07
* @Blog: https://kaven.blog.csdn.net
* @Leetcode: https://leetcode-cn.com/u/kavenit
* @Notes:
*/

@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class);
}

@Bean
@Scope(value = "prototype")
public IRule loadBalanceRule() {
return new NacosRule();
}

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

重复上面的请求操作,结果是一样的,大家可以去测试一下,因为​​Nacos​​的负载均衡策略默认也是轮询。

服务在线管理

修改第一个​​nacos​​​服务的权重为​​100​​​(默认为​​1​​)。

Spring Cloud Alibaba:Nacos服务注册与发现_微服务_30


修改服务权重成功。

Spring Cloud Alibaba:Nacos服务注册与发现_spring cloud_31

使用​​Postman​​​来批量调用​​consumer​​服务的接口。

Spring Cloud Alibaba:Nacos服务注册与发现_java_32


Spring Cloud Alibaba:Nacos服务注册与发现_微服务_33

第一个​​nacos​​​服务被调用了​​98​​次。

Spring Cloud Alibaba:Nacos服务注册与发现_spring_34


另外两个​​nacos​​​服务都是被调用了​​1​​次。

Spring Cloud Alibaba:Nacos服务注册与发现_maven_35


Spring Cloud Alibaba:Nacos服务注册与发现_maven_36

​Nacos​​​的源码分析博主以后再进行介绍,博主目前还在看​​Spring​​​的源码,等有时间再分享其他框架的源码分析。​​Nacos​​​服务注册与发现就介绍到这里,之后会介绍​​Nacos​​的其他特性以及高可用。

如果博主有说错的地方或者大家有不同的见解,欢迎大家评论补充。