Nacos注册中心简介

背景分析

在微服务中,首先需要面对的问题就是如何查找服务(软件即服务),其次,就是如何在不同的服务之间进行通信?如何更好更方便的管理应用中的每一个服务,如何建立各个服务之间联系的纽带,由此注册中心诞生(例如淘宝网卖家提供服务,买家调用服务)。
市面上常用注册中心有Zookeeper(雅虎Apache),Eureka(Netfix),Nacos(Alibaba),Consul(Google),那他们分别都有什么特点,我们如何进行选型呢?我们主要从社区活跃度,稳定性,功能,性能等方面进行考虑即可.本次微服务的学习,我们选择Nacos,它很好的支持了阿里的双11活动,不仅可以做注册中心,还可以作为配置中心,稳定性和性能都很好.

Nacos概述

Nacos(DynamicNaming and Configuration Service)是一个应用于服务注册与发现、配置管理的平台。它孵化于阿里巴巴,成长于十年双十一的洪峰考验,沉淀了简单易用、稳定可靠、性能卓越的核心竞争力。其官网地址如下:

https://nacos.io/zh-cn/docs/quick-start.html

构建Nacos服务

下载与安装

第一步:Nacos下载,可在浏览器直接输入如下地址:

https://github.com/alibaba/nacos/releases

第二步:选择对应版本,直接下载,如图所示:


第三步:解压Nacos(最好不要解压到中文目录下),其目录结构如下:


初始化配置

第一步:

找到/conf/nacos-mysql.sql文件里的sql脚本,然后登陆mysql,然后基于脚本文件中的描述创建数据库(名字nacos_config,编码方式utf8mb4),并执行脚本文件(也可以直接使用老师上课发的nacos-mysql.sql),脚本执行成功会创建一些表,如图所示:


说明:在执行此文件时,要求mysql的版本大于5.7版本(MariaDB最好10.5.11),否则会出现如下错误:

nacos中注册的地址是docker容器地址_ci

第二步:

打开/conf/application.properties里打开默认配置,并基于你当前环境配置要连接的数据库,连接数据库时使用的用户名和密码(假如前面有"#"要将其去掉):

### If use MySQL as datasource:
spring.datasource.platform=mysql

### Count of DB:
db.num=1

### Connect URL of DB:
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=root

服务启动与访问

第一步:启动Nacos服务。

Linux/Unix/Mac启动命令(standalone代表着单机模式运行,非集群模式):

./startup.sh -m standalone

Windows启动命令(standalone代表着单机模式运行,非集群模式):

startup.cmd -m standalone

说明:

  1. 执行执行令时要么配置环境变量,要么直接在nacos/bin目录下去执行.
  2. nacos启动时需要本地环境变量中配置了JAVA_HOME(对应jdk的安装目录),

第二步:访问Nacos服务。

打开浏览器,输入http://localhost:8848/nacos地址,出现如下登陆页面:

nacos中注册的地址是docker容器地址_ide_02


其中,默认账号密码为nacos/nacos.

服务注册与调用入门(重点)

业务描述

创建两个项目Module分别为服务提供者和服务消费者,两者都要注册到NacosServer中(这个server本质上就是一个web服务,端口默认为8848),然后服务提供者可以为服务消费者提供远端调用服务(例如支付服务为服务提供方,订单服务为服务消费方),如图所示:

nacos中注册的地址是docker容器地址_spring_03

创建Maven父工程

创建maven module工程01-sca,此工程为我们后续项目模块的父工程,这个工程的作用就是来管理子模块中所需要的共性依赖,如图所示:

nacos中注册的地址是docker容器地址_spring_04


通过此工程管理其核心依赖,其pom文件内容如下:

<?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>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.cy</groupId>
    <artifactId>01-sca </artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring.cloud-version>Hoxton.SR8</spring.cloud-version>
        <spring.cloud.alibaba-version>2.2.5.RELEASE</spring.cloud.alibaba-version>
   </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <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>

其中的版本可参考如下网址(涉及到一个兼容性问题,不能随意指定其版本):

https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E

说明:父工程资源初始化完成以后,将src目录删除,因为父工程只负责依赖管理.

生产者服务创建及注册

第一步:创建服务提供者继承parent工程(01-msa),module名为sca-nacos-provider(创建module工程时在父工程上右键创建module)。

nacos中注册的地址是docker容器地址_ide_05


第二步:添加项目依赖,关键代码如下:

<dependencies>

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

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

第三步:创建并修改配置文件application.yml(或者application.properties),实现服务注册,关键代码如下:

server:
   port: 8081
spring:
  application:
    name: sca-provider
  cloud:
    nacos:
      server-addr: localhost:8848

注意:服务名不要使用下划线(“_”),应使用横杠(“-”),这是规则。
第四步:创建启动类,并定义处理请求的控制层对象和方法,关键代码如下:

package com.cy;

@SpringBootApplication
public class ScaProviderApplication {

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

@Value("${server.port}")
private String server;

    @RestController
    public class ProviderController {
        @GetMapping(value = "/provider/echo/{msg}")
        public String doEcho(@PathVariable String msg) {
            return server+"say:Hello Nacos Discovery " + msg;
        }
    }

}

第五步:启动启动类,然后刷先nacos服务,检测是否服务注册成功,如图所示:

nacos中注册的地址是docker容器地址_ci_06


第六步:打开浏览器,输入http://localhost:8081/provider/echo/msa,然后进行访问。

消费者服务发现及调用

第一步:创建服务消费者继承parent工程,module名为sca-nacos-consumer。

nacos中注册的地址是docker容器地址_ide_07

第二步:添加项目依赖,关键代码如下:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
  		<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    	</dependency>
</dependencies>

第三步:修改配置文件application.yml,关键代码如下:

server:
  port: 8090
spring:
  application:
    name: sca-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #从哪里去查找服务

第四步:创建启动类并实现服务消费,关键代码如下:

package com.cy;
@SpringBootApplication
public class ScaConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ScaConsumerApplication.class,args);
    }
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
    @RestController
    public class ConsumerController{

        @Value("${spring.application.name}")
        private String appName;
        @Autowired
        private RestTemplate restTemplate;
        @GetMapping("/consumer/doRestEcho1")
        public String doRestEcho01(){
            String url = "http://localhost:8081/provider/echo/"+appName;
            System.out.println("request url:"+url);
           return restTemplate.getForObject(url, String.class);
        }
    }
}

第五步:启动消费者服务,并在浏览器输入http://localhost:8090/consumer/doRestEcho1地址进行访问,假如访问成功会出现,如图所示效果:

小节面试分析

  • 为什么要将服务注册到nacos?(为了更好的查找这些服务)
  • 在Nacos中服务提供者是如何向Nacos注册中心(Registry)续约的?(5秒心跳)
  • 对于Nacos服务来讲它是如何判定服务实例的状态?(检测心跳包,15,30)
  • 服务启动时如何找到服务启动注册配置类?(NacosNamingService)
  • 服务消费方是如何调用服务提供方的服务的?(RestTemplate)

服务负载均衡设计及实现(重点)

入门案例

一个服务实例可以处理请求是有限的,假如服务实例的并发访问比较大,我们会启动多个服务实例,让这些服务实例采用一定策略均衡(轮询,权重,随机,hash等)的处理并发请求,在Nacos中服务的负载均衡(Nacos客户端负载均衡)是如何应用的?

第一步:修改ConsumerController类,注入LoadBalancerClient对象,
并添加doRestLoadBalancerClientEcho方法,然后进行服务访问.

@Autowired
  private LoadBalancerClient loadBalancerClient;
   
  @GetMapping("/consumer/doRestEcho02")
 public String doRestEcho02(){
     ServiceInstance serviceInstance = loadBalancerClient.choose("sca-provider");
     String url = String.format("http://%s:%s/provider/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
     System.out.println("request url:"+url);
     return restTemplate.getForObject(url, String.class);
     }
 }

第二步:打开Idea服务启动配置,如图所示:

nacos中注册的地址是docker容器地址_ide_08


第三步:修改并发运行选项(假如没有找到这个选项我们需要通过搜索引擎基于组合查询的方法,去找到对应的解决方案,例如搜索 idea allow parallel run),如图所示:

nacos中注册的地址是docker容器地址_ci_09


第四步:修改sca-provider的配置文件端口,分别以8081,8082端口方式进行启动。

server:
  port: 8081
spring:
  application:
    name: sca-provider
  cloud:
    nacos:
      server-addr: localhost:8848

启动成功以后,访问nacos的服务列表,检测服务是否成功注册,如图所示:

nacos中注册的地址是docker容器地址_spring_10


第四步:启动sca-consumer项目模块,打开浏览器,输入如下网址进行反复服务访问:

http://localhost:8090/consumer/doRestEcho02

然后会发现sca-provider的两个服务都可以处理sca-consumer的请求。

nacos中注册的地址是docker容器地址_spring_11


nacos中注册的地址是docker容器地址_ci_12


这里多个实例并发提供服务的方式为负载均衡,这里的负载均衡实现默认是因为Nacos集成了Ribbon来实现的,Ribbon配合RestTemplate,可以非常容易的实现服务之间的访问。Ribbon是Spring Cloud核心组件之一,它提供的最重要的功能就是客户端的负载均衡(客户端可以采用一定算法,例如轮询访问,访问服务端实例信息),这个功能可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡方式的服务调用。

@LoadBalanced