Spring Cloud Alibaba微服务学习一:服务发现Nacos

772 阅读6分钟

这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战

为什么出现Spring Cloud Alibaba?

Spring Cloud的官网中:

在以往的Spring Cloud中官方也是推荐使用Netflix的组件,但是随着Netflix的多个组件进入维护状态,可以说Netflix的组件已经不能使用了,因为可能出现潜在风险。对于微服务来说,最重要的几个组件:服务发现、断路器、网关、负载均衡。然而这些组件都进入了维护状态。所以随之Ailibaba的组件就成为了我们的首选。

Spring Cloud Alibaba的主要组件

  • Sentinel:把流量作为切入点,从流量控制、熔断降级、系统负载保护等都各维度保护服务的稳定性。
  • Nacos:一个更易于构建云原生应用的动态服务发现配置管理服务管理平台
  • RabbitMQ:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时、高可靠的消息发布与订阅服务。
  • Dubbo:高性能的Java RPC框架。
  • Seata:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
  • Alibaba Cloud ACM:一款在分布式结构环境中对应用配置进行集中式管理和推送的应用配置中心产品。
  • Alibaba Cloud SchedulerX:分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时任务调度服务。
  • Alibaba Cloud SMS:覆盖全球的短信服务,友好、高效、只能的互联网通讯能力
  • Alibaba Cloud OSS:对象存储服务。

像OSS SMS、SchedulerX、ACM这些是阿里云的收费产品,这些也不是构建微服务的必需品,我们可以不用。

什么是Nacos?

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

Kubernetes Service

gRPC & Dubbo RPC Service

Spring Cloud RESTful Service

使用Nacos Server并注册应用

1.下载Nacos。下载地址:github.com/alibaba/nac…

2.解压Nacos的压缩包。

3.启动Nacos。

windows下启动

cmd startup.cmd或者双击startup.cmd

linux/Unix/Mac启动

sh startup.sh -m standalone

4.启动完成

nacos有一个完整的web界面,在上面有很多完善的功能。在浏览器打开http://localhost:8848/nacos。默认的用户名为nacos,密码为nacos

nacos的web界面

5.编写应用,注册到Nacos中

创建项目:

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.msr</groupId>
    <artifactId>cloud-v2</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>cloud-user-center-nacos-7003</module>
        <module>cloud-user-center-nacos-7005</module>
    </modules>
    <packaging>pom</packaging>

    <!-- 统一管理jar包版本 -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.16.18</lombok.version>
        <mysql.version>8.0.18</mysql.version>
        <druid.version>1.1.16</druid.version>
        <druid.spring.boot.starter.version>1.1.10</druid.spring.boot.starter.version>
        <spring.boot.version>2.2.2.RELEASE</spring.boot.version>
        <spring.cloud.version>Hoxton.SR1</spring.cloud.version>
        <spring.cloud.alibaba.version>2.1.0.RELEASE</spring.cloud.alibaba.version>
        <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
        <mybatis-spring-boot-starter.version>2.1.1</mybatis-spring-boot-starter.version>
        <hutool-all.version>5.1.0</hutool-all.version>
    </properties>

    <!-- 子模块继承之后,提供作用:锁定版本 + 子module不用谢groupId和version -->
    <dependencyManagement>
        <dependencies>
            <!--spring boot 2.2.2-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.2.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud Hoxton.SR1-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--Spring cloud alibaba 2.1.0.RELEASE-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${druid.spring.boot.starter.version}</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis-spring-boot-starter.version}</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
        </plugins>
    </build>


</project>

创建模块(cloud-user-center-nacos-7003)

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>cloud-v2</artifactId>
        <groupId>com.msr</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-user-center-nacos-7003</artifactId>

    <dependencies>
        <!-- SpringCloud ailibaba nacos-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
    </dependencies>
</project>

**启动类:**UserCenter7003Application

package com.msr.cloudv2.nacos;

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

@EnableDiscoveryClient
@SpringBootApplication
public class UserCenter7003Application {

    public static void main(String[] args) {
        SpringApplication.run(UserCenter7003Application.class, args);
    }
}

配置文件:

server:
  port: 7003
spring:
  application:
    name: cloud-user-center-provider-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
management:
  endpoints:
    web:
      exposure:
        include: '*'

创建模块(cloud-user-center-nacos-7005)

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>cloud-v2</artifactId>
        <groupId>com.msr</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-user-center-nacos-7005</artifactId>

    <dependencies>
        <!-- SpringCloud ailibaba nacos-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
</project>

启动类:

package com.msr.cloudv2.nacos;

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

@EnableDiscoveryClient
@SpringBootApplication
public class Nacos7005Application {

    public static void main(String[] args) {
        SpringApplication.run(Nacos7005Application.class, args);
    }
}

配置文件:

server:
  port: 7003
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&characterEncoding=utf8
  application:
    name: cloud-user-center-provider-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
management:
  endpoints:
    web:
      exposure:
        include: '*'

运行启动类启动,可以看到程序成功注册到Nacos注册中心。

登录Nacos的Web界面查看:已经有两个实列数成功注册进去。

服务之间的相互感知

很明显user-center两个实列已经注册成功,对于一个注册中心来说,里面的服务时可以相互感知的。代码如下:

在7003端口的服务中创建一个UserCenterController,然后两个服务都启动。在浏览器访问http://localhost:7003/nacos/getServiceInfo

package com.msr.cloudv2.nacos.conttoller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("nacos")
public class UserCenterController {

    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("getServiceInfo")
    public Object testNacos() {
        List<String> services = discoveryClient.getServices();
        List<Object> list = new ArrayList<>();
        services.stream().distinct().forEach(e -> list.add(discoveryClient.getInstances(e)));
        return list;
    }
    
    @GetMapping("toCall7005")
    public Object call() {
        List<ServiceInstance> instances = discoveryClient.getInstances("cloud-user-center-provider-service");
        List<ServiceInstance> serviceInstances = instances.stream().filter(e -> e.getPort() == 7005).collect(Collectors.toList());
        ServiceInstance serviceInstance = serviceInstances.get(0);
        URI uri = serviceInstance.getUri();
        return restTemplate.getForObject(uri.toString()+"nacos/test", String.class);
    }

    @Bean
    public RestTemplate restTemplate() {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setReadTimeout(5000);
        requestFactory.setConnectTimeout(5000);
        return new RestTemplate();
    }
}

显然,可以通过DiscoveryClient来获取注册在Nacos上的服务信息。接下来可以使用RestTemplate来调用7005端口的服务。

首先在7005端口的服务也创建一个UserCenterController

package com.msr.cloudv2.nacos.controller;

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

@RestController
@RequestMapping("nacos")
public class UserCenterController {


    @GetMapping("test")
    public String testNacos() {
        return "welcome to use nacos port :"+7005;
    }
}

在浏览器访问http://localhost:7003/nacos/toCall7005

综上所述,注册中Nacos中的服务时可以相互感知,并可以通过一些Http的客户端进行相互之间的调用。

Nacos服务发现的领域模型

  • NameSpace:命名空间,Nacso默认的NameSpace是public。比如在开发中,可以创建一个开发环境和测试环境的NameSpace。这样可以通过指定服务的NameSpace做到环境隔离。
  • Group:分组。在Nacos用作配置中心时使用。
  • **Service:**微服务
  • Cluster:对指定微服务的一个虚拟划分,默认是DEFAULT。
  • **Instance:**微服务实例。
  • Metadata: 只要用于版本控制。比如,我们在开发中可能是多个版本共存的。

配置使用

在Nacos下创建一个名为dev的NameSpace,然后再该NameSpace下创建一个

cloud-user-center-nacos-7003

只需要在配置文件中配置namespace和cluster-name这两项。

server:
  port: 7003
spring:
  application:
    name: cloud-user-center-provider-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        # 开发NameSpace,值为UUID
        namespace: 
        # 列如:广州集群
        cluster-name: GZ
management:
  endpoints:
    web:
      exposure:
        include: '*'

cloud-user-center-nacos-7005

配置文件

server:
  port: 7005
spring:
  application:
    name: cloud-user-center-provider-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
          # 开发NameSpace,值为UUID
        namespace: fa47d71f-9bc5-45ae-96c1-a6b9f7c55700
          # 北京集群
        cluster-name: BJ
management:
  endpoints:
    web:
      exposure:
        include: '*'

运行结果

注册中心:服务列表

点击”详情“,可以看到GZ和BJ两个集群

Nacos的元信息

Nacos数据(如配置和服务)描述信息,如服务版本、权重、容灾策略、负载均衡策略、鉴权配置、各种自定义标签 (label),从作用范围来看,分为服务级别的元信息、集群的元信息及实例的元信息。

设置方式:1.在Nacos的web界面的控制台设置。2.在配置文件设置

在配置文件设置

server:
  port: 7003
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&characterEncoding=utf8
  application:
    name: cloud-user-center-provider-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        # 开发NameSpace,值为UUID
        namespace: fa47d71f-9bc5-45ae-96c1-a6b9f7c55700
        # 广州集群
        cluster-name: GZ
        metadata:
          version: v1
          info: user-center
management:
  endpoints:
    web:
      exposure:
        include: '*'

结语

不积跬步无以至千里,不积小流无以成江海