介绍

使用 Nacos Discovery 进行服务注册/发现

简介

服务注册与发现是微服务架构体系中最关键的组件之一。如果尝试着用手动的方式来给每一个客户端来配置所有服务提供者的服务列表是一件非常困难的事,而且也不利于服务的动态扩缩容。Nacos Discovery 可以帮助您将服务自动注册到 Nacos 服务端并且能够动态感知和刷新某个服务实例的服务列表。除此之外,Nacos Discovery 也将服务实例自身的一些元数据信息-例如 host,port, 健康检查URL,主页等内容注册到 Nacos。Nacos 的获取和启动方式可以参考Nacos 官网

学习目标

  • 掌握 Nacos Discovery 实现 Spring Cloud 服务注册和发现
  • 掌握 Nacos Discovery 整合 Spring Cloud 负载均衡和服务调用
  • 理解 Nacos Discovery 高级特性:命名空间、安全控制、元数据、Nacos Watch 等

详细内容

  • 快速上手:指导读者从使用 Nacos Discovery 进行服务注册/发现
  • 服务调用整合:实战 Nacos Discovery 整合 @LoadBalanced RestTemplate 以及 Open Feign
  • 运维特性:演示 Nacos Discovery 高级外部化配置以及 Endpoint 内部细节

使用 Nacos Discovery 进行服务注册/发现

使用 Nacos Discovery 进行服务注册/发现与传统 Spring Cloud 的方式并没有本质区别,仅需添加相关外部化配置即可工作。换言之,Nacos Discovery 不会侵入应用代码,方便应用整合和迁移,这归功于 Spring Cloud 的高度抽象。
如果读者熟悉 Spring Cloud 服务注册和发现的话,通常需要将注册中心预先部署,Nacos Discovery 也不例外。

查看 Nacos Discovery 注册中心

使用单机模式,启动本地nacos

 .\startup.cmd -m standalone

访问http://124.0.0.1/nacos 访问nacos,默认账号密码是nacos

启动服务提供者(Provider)

由于初始工程已经包含所有主要代码,我们要做的修改非常少:打开服务端的 application.properties,修改服务端口到50000

server.port=50000

修改注册中心地址到本地

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

启动项目后在nacos端可以看到注册的服务

激活 Nacos Discovery 服务注册与发现

Aliyun Java Initializr 默认不会自动激活 Nacos Discovery 服务注册与发现,需要在引导类(main 方法所在类。或者是@Configuration标注类)标注 Spring Cloud 服务注册与发现标准注解@EnableDiscoveryClient,代码如下所示: NacosDiscoveryConfiguration 文件

/**
 * @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
 */
@EnableDiscoveryClient
@Configuration
public class NacosDiscoveryConfiguration {
}

如果不想使用 Nacos 作为您的服务注册与发现,可以将spring.cloud.nacos.discovery设置为false。

Nacos Discovery 整合 Spring Cloud 服务调用

从应用架构上,Spring Cloud 服务调用通常需要两个应用,一个为服务提供者(Provider),一个为服务消费者(Consumer)。从技术上,传统的 Spring Cloud 服务通讯方式是基于 REST 实现的,包好两种内建实现方法,分别是 @LoadBalanced RestTemplate 以及 Open Feign,两者均作用于服务消费者,而服务提供者仅为 WebMVC 或者 WebFlux 应用(需注册到注册中心)。同时,还允许整合 Spring Cloud 负载均衡 API,实现自定义 REST 服务调用。至于,Spring Cloud Alibaba 引入 Dubbo 服务通讯方式,会在后续内容中单独讨论。

获取客户端代码

综上所述,我们现在需要获取一套客户端代码

前文的准备工作已经完成了客户端代码的下载工作,所以这里无需做任何操作;

如果需要在本地获取代码,可以参考下面链接

增加 Nacos Discovery 外部化配置

与应用 nacos-discovery-provider-sample 配置类似,增加 Nacos Discovery 外部化配置,为了避免与应用 nacos-discovery-provider-sample 端口冲突 ,完整配置如下:

打开客户端配置文件 application.properties

修改服务端口到51000

server.port=51000

修改注册中心地址到本地

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

服务消费者激活 Nacos Discovery 服务注册与发现

与应用 nacos-discovery-provider-sample 实现一样,在引导类上标注@EnableDiscoveryClient,参考代码 NacosDiscoveryConfiguration.java 文件

/**
 * @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
 */
@EnableDiscoveryClient
@Configuration
public class NacosDiscoveryConfiguration {
}

服务消费者使用 @LoadBalanced RestTemplate 实现服务调用

前文提到 @LoadBalanced RestTemplate 是 Spring Cloud 内建的服务调用方式,因此需要在应用 nacos-discovery-consumer-sample 增加执行代码,消费应用 nacos-discovery-provider-sample REST 服务/echo/{message},请参考 RestTemplateController.java ,核心代码如下:

@RestController
class EchoController {

	@GetMapping("/")
	public ResponseEntity index() {
		return new ResponseEntity("index error", HttpStatus.INTERNAL_SERVER_ERROR);
	}

	@GetMapping("/test")
	public ResponseEntity test() {
		return new ResponseEntity("error", HttpStatus.INTERNAL_SERVER_ERROR);
	}

	@GetMapping("/sleep")
	public String sleep() {
		try {
			Thread.sleep(1000L);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return "ok";
	}

	@GetMapping("/echo/{string}")
	public String echo(@PathVariable String string) {
		return "hello Nacos Discovery " + string;
	}

	@GetMapping("/divide")
	public String divide(@RequestParam Integer a, @RequestParam Integer b) {
		return String.valueOf(a / b);
	}

}

文档示例中没有客户端的代码,自己新建包路径如下

package com.alibaba.cloud.nacosdiscoveryprovidersample.demos.nacosdiscoveryprovider;

在启动完成以后,测试运行结果:

http://127.0.0.1:51000/call/echo/Hello,World

返回

hello Nacos Discovery Hello,World

结果符合期望,说明 Nacos Discovery 整合 @LoadBalanced RestTemplate 的实现与标准 Spring Cloud 实现的差异仅体现在 Maven 依赖 starter 以及外部化配置上。接下来,应用 nacos-discovery-consumer-sample 将继续与 Spring Cloud OpenFeign 整合。

Nacos Discovery 整合 Spring Cloud OpenFeign

Spring Cloud OpenFeign 是 Spring Cloud 基于 REST 客户端框架 OpenFeign 而构建,使得服务发现和负载均衡透明,开发人员只需关注服务消费者接口契约。同时,Spring Cloud OpenFeign 可以与 @LoadBalanced RestTemplate 共存,因此,可在原有应用 nacos-discovery-consumer-sample 的基础上,增加 Maven 依赖和代码实现整合。

关于 Spring Cloud OpenFeign 的技术细节,可参考官方文档: https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/

服务消费者增加 Spring Cloud OpenFeign Maven 依赖

在 nacos-discovery-consumer-sample 项目 pom.xml 中追加 Spring
Cloud OpenFeign Maven 依赖:

  <!-- Spring Cloud OpenFeign -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-openfeign</artifactId>
	<version>2.2.2.RELEASE</version>
</dependency>

本地测试采用的是gradle项目,添加依赖如下:

dependencies {
    implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
}

服务消费者增加 Spring Cloud OpenFeign 服务声明接口

由于需要消费应用 nacos-discovery-provider-sample 提供的 REST 服务/echo/{message},根据 Spring Cloud OpenFeign 的要求,需要在消费者应用增加 REST 服务声明接口,参考 EchoService.java,核心代码如下(此处代码结构和官方demo中的略有不同):

package com.alibaba.cloud.nacosdiscoveryconsumersample.demos.nacosdiscoveryconsumer;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient("nacos-discovery-provider-sample") // 指向服务提供者应用
public interface EchoService {

	@GetMapping("/echo/{message}")
	String echo(@PathVariable("message") String message);
}

不难发现,echo(String) 方法在 Spring MVC 请求映射的方式与 nacos-discovery-provider-sample 中的ServiceController基本相同,唯一区别在于 @PathVariable 注解指定了 value 属性 "message",这是因为默认情况,Java 编译器不会讲接口方法参数名添加到 Java 字节码中。

服务消费者激活 Spring Cloud OpenFeign 服务声明接口

激活 Spring Cloud OpenFeign 服务声明接口的方法非常简单,仅需在引导类标注@EnableFeignClients,请参考 NacosDiscoveryConsumerConfiguration.java,其中核心代码如(这里由于没有把配置和feign的接口放在同一个包下,所以使用basePackages属性进行配置)下:

package com.alibaba.cloud.nacosdiscoveryconsumersample.nacosdiscovery;

import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Configuration;

/**
 * @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
 */
@EnableDiscoveryClient
@Configuration
@EnableFeignClients(basePackages="com.alibaba.cloud.nacosdiscoveryconsumersample.demos.nacosdiscoveryconsumer") // 激活 @FeignClient
public class NacosDiscoveryConfiguration {
}

服务消费者使用 Spring Cloud OpenFeign 服务声明接口实现服务调用


@RestController
public class OpenFeignController {

	@Autowired
	private EchoService echoService;

	@GetMapping("/feign/echo/{message}")
	public String feignEcho(@PathVariable String message) {
		System.out.println(message);
		return echoService.echo(message);
	}
}

启动服务并访问测试:

http://127.0.0.1:51000/feign/echo/Hello,World

返回结果:

hello Nacos Discovery Hello,World

结果符合期望,说明 Nacos Discovery 整合 Spring Cloud OpenFeign 与传统方式也是相同的。
综上所述,Nacos Discovery 在 Spring Cloud 服务调用是无侵入的。

Nacos Discovery 更多配置项信息

更多关于 Nacos Discovery Starter 的配置项如下所示:

配置项 Key 默认值 说明
服务端地址 spring.cloud.nacos.discovery.server-addr Nacos Server 启动监听的ip地址和端口
服务名 spring.cloud.nacos.discovery.service $ 注册的服务名
权重 spring.cloud.nacos.discovery.weight 1 取值范围 1 到 100,数值越大,权重越大
网卡名 spring.cloud.nacos.discovery.network-interface 当IP未配置时,注册的IP为此网卡所对应的IP地址,如果此项也未配置,则默认取第一块网卡的地址
注册的IP地址 spring.cloud.nacos.discovery.ip 优先级最高
注册的端口 spring.cloud.nacos.discovery.port -1 默认情况下不用配置,会自动探测
命名空间 spring.cloud.nacos.discovery.namespace 常用场景之一是不同环境的注册的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等
AccessKey spring.cloud.nacos.discovery.access-key 当要上阿里云时,阿里云上面的一个云账号名
SecretKey spring.cloud.nacos.discovery.secret-key 当要上阿里云时,阿里云上面的一个云账号密码
Metadata spring.cloud.nacos.discovery.metadata 使用Map格式配置,用户可以根据自己的需要自定义一些和服务相关的元数据信息
日志文件名 spring.cloud.nacos.discovery.log-name
集群 spring.cloud.nacos.discovery.cluster-name DEFAULT Nacos集群名称
接入点 spring.cloud.nacos.discovery.endpoint 地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址
是否集成Ribbon ribbon.nacos.enabled true 一般都设置成true即可
是否开启Nacos Watch spring.cloud.nacos.discovery.watch.enabled

Nacos Discovery Actuator Endpoint

Nacos Discovery 内部提供了一个 Endpoint, 对应的 endpoint id 为nacos-discovery,其 Actuator Web Endpoint URI 为/actuator/nacos-discovery(需要先添加依赖)

注:使用 Nacos Config Spring Cloud 1.x 版本的话,其 URI 地址则为/nacos-discovery )

 implementation 'org.springframework.boot:spring-boot-starter-actuator'

Endpoint 暴露的 json 中包含了两种属性:

  • subscribe: 显示了当前服务有哪些服务订阅者
  • NacosDiscoveryProperties: 当前应用 Nacos 的基础配置信息
    由于 Aliyun Java Initializr 所生成的应用工程默认激活 Spring Boot Actuator Endpoints(JMX 和 Web),具体配置存放在application.properties 文件中,同时,Actuator Web 端口设置为 8081(这里修改为52000),内容如下:
management.endpoints.jmx.exposure.include=*
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always

# Actuator Web 访问端口
management.server.port=52000

直接访问:http://127.0.0.1:52000/actuator/nacos-discovery ,服务响应的内容如下:

/ 20210206154001
// http://127.0.0.1:52000/actuator/nacos-discovery

{
  "subscribe": [
    {
      "name": "nacos-discovery-provider-sample",
      "groupName": "DEFAULT_GROUP",
      "clusters": "DEFAULT",
      "cacheMillis": 1000,
      "hosts": [
        
      ],
      "lastRefTime": 0,
      "checksum": "",
      "allIPs": false,
      "valid": true
    }
  ],
  "NacosDiscoveryProperties": {
    "serverAddr": "127.0.0.1:8848",
    "username": "nacos",
    "password": "nacos",
    "endpoint": "",
    "namespace": "public",
    "watchDelay": 30000,
    "logName": "",
    "service": "nacos-discovery-provider-sample",
    "weight": 1.0,
    "clusterName": "DEFAULT",
    "group": "DEFAULT_GROUP",
    "namingLoadCacheAtStart": "false",
    "metadata": {
      "management.port": "52000",
      "preserved.register.source": "SPRING_CLOUD"
    },
    "registerEnabled": true,
    "ip": "169.254.232.209",
    "networkInterface": "",
    "port": 50000,
    "secure": false,
    "accessKey": "",
    "secretKey": "",
    "heartBeatInterval": null,
    "heartBeatTimeout": null,
    "ipDeleteTimeout": null,
    "instanceEnabled": true,
    "ephemeral": true,
    "nacosProperties": {
      "secretKey": "",
      "namespace": "public",
      "username": "nacos",
      "namingLoadCacheAtStart": "false",
      "enabled": "true",
      "serverAddr": "127.0.0.1:8848",
      "com.alibaba.nacos.naming.log.filename": "",
      "clusterName": "DEFAULT",
      "password": "nacos",
      "accessKey": "",
      "endpoint": ""
    }
  }
}
posted on 2021-02-06 16:44  学业未成  阅读(171)  评论(0编辑  收藏  举报