学习一下 SpringCloud (六)-- 注册中心与配置中心 Nacos、网关 Gateway

(1) 相关博文地址:html

学习一下 SpringCloud (一)-- 从单体架构到微服务架构、代码拆分(maven 聚合): https://www.cnblogs.com/l-y-h/p/14105682.html
学习一下 SpringCloud (二)-- 服务注册中心 Eureka、Zookeeper、Consul、Nacos :https://www.cnblogs.com/l-y-h/p/14193443.html
学习一下 SpringCloud (三)-- 服务调用、负载均衡 Ribbon、OpenFeign : https://www.cnblogs.com/l-y-h/p/14238203.html
学习一下 SpringCloud (四)-- 服务降级、熔断 Hystrix、Sentinel : https://www.cnblogs.com/l-y-h/p/14364167.html    
学习一下 SpringCloud (五)-- 配置中心 Config、消息总线 Bus、链路追踪 Sleuth、配置中心 Nacos : https://www.cnblogs.com/l-y-h/p/14447473.html

(2)代码地址:java

https://github.com/lyh-man/SpringCloudDemo

 

1、了解一下 SpringCloud Alibaba

一、SpringCloudAlibaba

(1)简单说明mysql

【说明:】
    经过前面几篇博客的介绍,已对 SpringCloud 部分框架有了一些认识,好比: Eureka、Ribbon、Hystrix、Config、Bus 等。
    但这些框架都有相似的问题:进入了维护模式 或者 功能不完善(使用场景有限,没法很好地适应新需求)
注:
    模块置于维护模式意味着 Spring Cloud 团队再也不向模块添加新功能。仅修复拦截器漏洞和安全问题。
    
    SpringCloud 版本迭代速度挺快的,这就致使了一个问题: 一些旧版本出现的问题还未解决就推出了一个新的版本。
    而某模块进入了维护模式,即再也不开发新功能,其使用价值有限,使用人数也就逐渐减小,至关于 打入冷宫,难有翻身余地。
    
    一个旧技术的没落,一定有一个新技术取而代之。
    而 SpringCloudAlibaba 就是这个新技术之一,有必要重点学习一下。    

 

 

 

(2)SpringCloudAlibabanginx

【SpringCloudAlibaba:】
    Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。
    此项目包含开发分布式应用微服务的必需组件,方便开发者经过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
    依托 Spring Cloud Alibaba,您只须要添加一些注解和少许配置,就能够将 Spring Cloud 应用接入阿里微服务解决方案,经过阿里中间件来迅速搭建分布式应用系统。

【相关地址:】
    https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md
    https://spring-cloud-alibaba-group.github.io/github-pages/hoxton/en-us/index.html
    https://github.com/alibaba/spring-cloud-alibaba/wiki
    
【版本管理:】
    当前 Spring Cloud Alibaba 最新版本为 2.2.5.RELEASE。
    其推荐对应 Spring Cloud 版本为 Spring Cloud Hoxton.SR8,
    其推荐对应 Spring Boot 版本为 2.3.2.RELEASE。
可参考:
    https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E

 

 

 

(3)引入依赖
  使用 SpringCloudAlibaba 与使用 SpringCloud 相似,通常都在父工程的 pom.xml 文件中经过 <dependencyManagement> 标签进行版本管理。而后在使用其组件时,直接引入相关组件依赖,无需管理版本。
  固然直接引入相关组件依赖 并 指定版本号的方式亦可。git

【在父工程中管理版本:】
<properties>
    <spring.cloud.alibaba.version>2.2.5.RELEASE</spring.cloud.alibaba.version>
</properties>

<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>

 

二、SpringCloudAlibaba 主要功能 与 实现组件

(1)SpringCloudAlibaba 主要功能 与 实现组件github

【功能与实现组件:】
服务限流降级:
    基本说明:
        默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 RocketMQ 限流降级功能的接入,
        能够在运行时经过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。
    实现组件:
        Sentinel: 把流量做为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
        
服务注册与发现:
    基本说明:
        适配 Spring Cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。
    实现组件:
        Nacos: 一个更易于构建云原生应用的动态服务发现和服务管理平台。
        
分布式配置管理:
    基本说明:
        支持分布式系统中的外部化配置,配置更改时自动刷新。
    实现组件:    
        Nacos: 一个更易于构建云原生应用的配置管理平台。
        
消息驱动能力:
    基本说明:
        基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。
    实现组件:    
        RocketMQ: 一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。

分布式事务:
    基本说明:
        使用 @GlobalTransactional 注解, 高效而且对业务零侵入地解决分布式事务问题。
    实现组件:
        Seata: 阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
        
阿里云对象存储:
    基本说明:
        阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任什么时候间、任何地点存储和访问任意类型的数据。
    实现组件:
        Alibaba Cloud OSS: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您能够在任何应用、任什么时候间、任何地点存储和访问任意类型的数据。
        
分布式任务调度:
    基本说明:
        提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。同时提供分布式的任务执行模型,如网格任务。网格任务支持海量子任务均匀分配到全部 Worker(schedulerx-client)上执行。
    实现组件:    
        Alibaba Cloud SchedulerX: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。

阿里云短信服务:
    基本说明:
        覆盖全球的短信服务,友好、高效、智能的互联化通信能力,帮助企业迅速搭建客户触达通道。
    实现组件:
        Alibaba Cloud SMS: 覆盖全球的短信服务,友好、高效、智能的互联化通信能力,帮助企业迅速搭建客户触达通道。    

 

(2)开发中常使用的技术搭配web

【开发中使用的技术:】
    在平时开发中使用的技术搭配,我通常采用一下方案:
SpringCloud:
    OpenFeign:   声明式 HTTP 客户端(即 远程服务调用)。
    Ribbon:      负载均衡(OpenFeign 中已集成,无需单独引入)。
    Gateway:     API 网关。
    Sleuth:      分布式链路追踪(即 请求调用链监控)。
    
SpringCloudAlibaba:
    Nacos:      注册中心 以及 配置中心(即 服务注册、发现  以及  动态配置管理)。
    Sentinel:   服务容错(即限流、降级、熔断)。
    Seata:      解决分布式事务。
    
注:
    经过前面几篇博客的学习,知道了 OpenFeign、Ribbon、Sleuth、Sentinel 相关操做。
    OpenFeign、Ribbon 相关操做详见:https://www.cnblogs.com/l-y-h/p/14238203.html
    Sleuth 相关操做详见:https://www.cnblogs.com/l-y-h/p/14447473.html#_label4
    Sentinel 相关操做详见:https://www.cnblogs.com/l-y-h/p/14364167.html#_label2
    
下面将逐个学习 Nacos、Gateway、Seata。

 

2、服务注册中心、配置中心 -- Nacos

一、什么是 Nacos?

(1)Nacos正则表达式

【Nacos:】
    Nacos 即 Dynamic Naming and Configuration Service(动态命名与配置服务)。由 Naming 前两个字母,Configuration 前两个字母,以及 Service 首字母组成。
    Nacos 是一个更易于构建云原生应用的动态服务发现、配置管理 以及 服务管理平台。
简单的理解:
    Nacos 就是 注册中心 + 配置中心。 
    即 Nacos = Eureka + Config + Bus。
    
【相关地址:】
    https://nacos.io/zh-cn/index.html
    https://github.com/alibaba/nacos

 

(2)如何使用 Nacosspring

【如何使用 Nacos:】
    Nacos 分为 Server、Client,其中 Server 做为注册中心以及配置中心,能够独立部署。
    而想要使用 Nacos,仅需在 微服务当中引入 client 相关依赖便可。
其中:
    Server 最新版本为 1.4.1,根据实际状况能够自行选择版本。
    使用注册中心功能,须要引入 spring-cloud-starter-alibaba-nacos-discovery 依赖。
    使用配置中心功能,须要引入 spring-cloud-starter-alibaba-nacos-config 依赖。
注:
    下载地址:https://github.com/alibaba/nacos/releases/download/1.4.1/nacos-server-1.4.1.tar.gz

 

二、安装 Nacos Server 单机版(Linux 直接下载并启动、持久化数据到 MySQL 8)

(1)说明:
  Nacos 默认使用内嵌数据库(Derby)实现数据的存储,通常使用 单机版 Nacos Server 无需额外配置持久化操做,直接启动便可。
  但大型的项目中,Nacos Server 通常采用集群方式部署,若仍使用默认数据库进行数据存储,那么各个 Nacos Server 之间的数据一致性就是一个头疼的问题。 Nacos 支持持久化数据到 MySQL 中,集群中全部节点共享 MySQL 数据源,从而保证数据一致性。sql

(2)下载、并解压 nacos-server

【下载:】
wget https://github.com/alibaba/nacos/releases/download/1.4.1/nacos-server-1.4.1.tar.gz

【解压:】
tar -axvf nacos-server-1.4.1.tar.gz

 

(3)直接启动
  未进行持久化配置,使用默认的 Derby 进行数据存储。

【进入解压后的 bin 目录:】
    cd ./nacos/bin

【以单机模式启动:】
    sh startup.sh -m standalone
注:
    经过执行 sh shutdown.sh 能够关闭 Nacos。

【登陆 Nacos:】
    默认经过 8848 端口能够访问 Nacos。
    帐号、密码默认均为 nacos
好比:
    http://120.26.184.41:8848/nacos

 

 

 

 

 

 

(4)持久化数据到 MySQL 中
Step1:
  链接数据库,并构建数据表。

【构建数据表:】
    进入解压后的 nacos 的 conf 目录,能够看到有 nacos-mysql.sql 文件。
    链接上 MySQL,新建一个数据库(nacos_config),并执行 nacos-mysql.sql 文件中的 SQL 语句。
注:
    能够直接使用官方提供的 nacos-mysql.sql 文件。
    https://github.com/alibaba/nacos/blob/master/distribution/conf/nacos-mysql.sql

注:
    MySQL 请自行安装,此处不赘述。
可参考以下博客(仅供参考,长时间未更新,可能会出现一些问题):
    Windows 安装 MySQL:https://www.cnblogs.com/l-y-h/p/11700113.html
    Linux 安装 MySQL:https://www.cnblogs.com/l-y-h/p/12576633.html
    Docker 安装 MySQL:https://www.cnblogs.com/l-y-h/p/12622730.html#_label5
    Docker Compose 安装 MySQL:https://www.cnblogs.com/l-y-h/p/12622730.html#_label8_2

 

 

 

 

 

 

Step2:
  配置 nacos 与 mysql 链接信息。

【配置数据源信息:】
    一样在 conf 目录下,有一个 application.properties 文件。
    编辑该文件,在文件末尾添加以下数据源信息(根据 MySQL 信息自行修改):

spring.datasource.platform=mysql

db.num=1
db.url.0=jdbc:mysql://120.26.184.41:3306/nacos_config?useUnicode=true&characterEncoding=utf8
db.user=root
db.password=123456

 

 

 

Step3:
  从新启动 nacos,再次登陆nacos (http://120.26.184.41:8848/nacos) ,并新增一个配置文件。
  此时在 MySQL 中能够看到相关信息。

 

 

 

三、安装 Nacos Server 单机版(docker-compose 启动,持久化数据到 MySQL 8)

(1)说明
  若需持久化到 mysql,一样也得在 mysql 中生成相应的表,相关 SQL 文件能够参考上面 持久化操做(此处省略)。
  能够直接使用官方提供的 MySQL 镜像,nacos/nacos-mysql:8.0.16,其有一个数据库 nacos_devtest 已包含了相关的表结构。

【nacos-docker 相关连接:】
    https://nacos.io/zh-cn/docs/quick-start-docker.html
    https://github.com/nacos-group/nacos-docker

【docker-compose 使用参考连接:】
    https://www.cnblogs.com/l-y-h/p/12622730.html#_label8_2
    
【nacos-mysql SQL:】
    https://github.com/alibaba/nacos/blob/master/distribution/conf/nacos-mysql.sql

 

 

 

(2)使用已有的 mysql 文件。
  简化操做,直接使用上面的 mysql。
  若需启动新的 mysql,须要手动执行 SQL,用于建立 nacos 所需相关表结构。
注:
  https://github.com/alibaba/nacos/blob/master/distribution/conf/nacos-mysql.sql

【docker-compose.yml】
version: '3.7'
services:
  nacos:
    image: nacos/nacos-server:1.4.1
    container_name: nacos
    restart: always
    environment:
      - MODE=standalone
      - TZ=Asia/Shanghai
      - SPRING_DATASOURCE_PLATFORM=mysql
      - MYSQL_SERVICE_HOST=120.26.184.41
      - MYSQL_SERVICE_PORT=3306
      - MYSQL_SERVICE_DB_NAME=nacos_config
      - MYSQL_SERVICE_USER=root
      - MYSQL_SERVICE_PASSWORD=123456
      - JVM_XMS=50m
      - JVM_MMS=50m
    volumes:
      - ./standalone-logs/:/home/nacos/logs
    ports:
      - 8848:8848

相关参数设置以下(对于高版本 Nacos 参数有些许不一样):
  NACOS_SERVER_PORT 须要改成 NACOS_APPLICATION_PORT
  多个带有 MASTER 的参数须要去掉 MASTER,好比:MYSQL_MASTER_SERVICE_HOST 须要改成 MYSQL_SERVICE_HOST。

 

 

 

经过 docker-compose up -d 启动后,访问 http://120.26.184.41:8848/nacos。
成功登陆后,能够看到以前配置的文件,即启动 nacos 成功。

 

 

 

(3)使用 nacos 官方提供的 mysql 镜像进行持久化操做。
注意:
  此处使用的 nacos 镜像为:nacos/nacos-server:1.4.1。
  使用的 mysql 镜像为:nacos/nacos-mysql:8.0.16。

坑:
  执行 docker-compose up -d 后,访问 nacos。若访问 nacos 失败时,能够查看日志文件 start.out,若出现 Caused by: java.lang.IllegalStateException: No DataSource set 的问题,能够从新启动一下容器(docker-compose restart)。若仍然出错,则将 nacos-mysql:8.0.16 更换为 nacos-mysql:5.7 。

【docker-compose.yml】
version: '3.7'
services:
  mysql:
    container_name: nacos-mysql
    image: nacos/nacos-mysql:8.0.16
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=nacos_devtest
      - MYSQL_USER=nacos
      - MYSQL_PASSWORD=nacos
    volumes:
      - ./mysql/data:/var/lib/mysql
      - ./mysql/log:/var/log/mysql
    ports:
      - "3307:3306"
  nacos:
    image: nacos/nacos-server:1.4.1
    container_name: nacos
    restart: always
    environment:
      - MODE=standalone
      - TZ=Asia/Shanghai
      - SPRING_DATASOURCE_PLATFORM=mysql
      - MYSQL_SERVICE_HOST=120.26.184.41
      - MYSQL_SERVICE_PORT=3307
      - MYSQL_SERVICE_DB_NAME=nacos_devtest
      - MYSQL_SERVICE_USER=root
      - MYSQL_SERVICE_PASSWORD=root
      - JVM_XMS=50m
      - JVM_MMS=50m
    volumes:
      - ./standalone-logs/:/home/nacos/logs
    depends_on:
      - mysql
    ports:
      - 8848:8848

 

四、Nacos 做为 服务注册中心(服务注册与发现)

(1)说明:

【说明:】
    经过前面的操做,已经成功启动了 Nacos Server,接下来整合 Nacos Client 便可。
    此处的 Nacos Server 为注册中心。
    新建三个模块 nacos_client_7100、nacos_client_710一、nacos_client_7102 用于演示服务提供者。
    新建一个模块 nacos_client_consumer 用于演示服务消费者(使用 OpenFeign 调用服务)。
    Nacos 已集成 Ribbon 并提供负载均衡。
注:
    此处模块建立仅 描述 主要流程,不详细截图(可参考以前的博客)。

【参考连接:】
    https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html
    https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-discovery
    https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme-zh.md

 

(2)新建模块 nacos_client_7100
Step1:
  修改 pom.xml,引入 nacos-discovery 依赖。

【引入 Nacos 依赖:】
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

 

 

 

Step2:
  修改 application.yml,配置 nacos。

【application.yml】
server:
  port: 7100

spring:
  application:
    name: nacos-client
  cloud:
    nacos:
      discovery:
        # 配置 nacos 地址
        server-addr: 120.26.184.41:8848

 

 

 

Step3:
  编写一个测试 controller,简单测试一下是否正常。

【TestController】
package com.lyh.springcloud.nacos_client_7100.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RequestMapping("/nacos")
@RestController
public class TestController {
    @Value("${server.port}")
    private String port;

    @Value("${spring.application.name}")
    private String name;

    @Autowired
    private DiscoveryClient discoveryClient;

    @RequestMapping("/info")
    public String getInfo() {
        return name + "-" + port;
    }

    @GetMapping("/discovery")
    public Map<String, List<ServiceInstance>> discovery() {
        // 获取服务名列表
        List<String> servicesList = discoveryClient.getServices();

        // 根据服务名 获取 每一个服务名下的 各个服务的信息
        Map<String, List<ServiceInstance>> map = new HashMap<>();
        servicesList.stream().forEach(service -> {
            map.put(service, discoveryClient.getInstances(service));
        });

        return map;
    }
}

 

 

 

Step4:
  启动当前服务。
  在启动类上添加 @EnableDiscoveryClient 注解(不添加貌似也没啥影响)。

 

 

 

Step5:
  访问 http://120.26.184.41:8848/nacos/
  登录后,选择 “服务管理” ==》“服务列表”,便可看到当前有哪些服务注册进来了。

 

 

 访问 http://localhost:7100/nacos/discovery

 

 

 访问 http://localhost:7100/nacos/info

 

 

 

(3)新建模块 nacos_client_710一、nacos_client_7102
  这两个模块与 nacos_client_7100 相似,仅端口号不一样(建立过程此处省略)。
  启动服务后,再次查看 nacos 控制台,能够看到出现 3 个实例。

 

 

 

 

 

 

(4)新建模块 nacos_client_consumer
  nacos-discovery 已集成 Ribbon,默认实现负载均衡方式为 轮询。

 

 

 

Step1:
  引入 nacos-discovery 、openfeign 依赖。

【依赖:】
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

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

 

 

 

Step2:
  修改 application.yml 文件。

【application.yml】
server:
  port: 7200

spring:
  application:
    name: nacos-client-consumer
  cloud:
    nacos:
      discovery:
        # 配置 nacos 地址
        server-addr: 120.26.184.41:8848

 

 

 

Step3:
  编写 openfeign 接口,调用 nacos_client 服务。

【ConsumerFeign】
package com.lyh.springcloud.nacos_client_consumer.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

@Component
@FeignClient(name = "nacos-client")
public interface ConsumerFeign {

    @RequestMapping("/nacos/info")
    String getInfo();
}

 

 

 

Step4:
  编写 controller,用于测试。

【TestController】
package com.lyh.springcloud.nacos_client_consumer.controller;

import com.lyh.springcloud.nacos_client_consumer.service.ConsumerFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/consumer")
@RestController
public class TestController {

    @Autowired
    private ConsumerFeign consumerFeign;

    @RequestMapping("/info")
    public String getInfo() {
        return consumerFeign.getInfo();
    }
}

 

 

 

Step5:
  简单测试一下 负载均衡。

 

 

 

访问:http://localhost:7200/consumer/info  ,默认轮询调用 nacos-client 服务。

 

 

 

五、Nacos 做为配置中心(自动刷新)

(1)说明

【说明:】
    前面使用 Nacos Server 做为注册中心,此处做为 配置中心。
    修改 nacos_client_7100 模块做为演示。
注:
    Nacos 做为配置中心时,用法与 Config 很相似。
    Config 使用可参考:https://www.cnblogs.com/l-y-h/p/14447473.html#_label1

【参考连接:】
    https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-config
    https://github.com/alibaba/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/nacos-example/nacos-config-example

 

(2)修改 nacos_client_7100
Step1:
  添加 nacos-config 依赖。

【依赖:】
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

 

 

 

Step2:
  添加 bootstrap.yml 文件,并进行配置中心相关设置。
  修改 application.yml 文件,修改其环境为 dev。
注:
  配置文件默认拼接为:${spring.cloud.nacos.prefix} - ${spring.profiles.active} . ${spring.cloud.nacos.file-extension}
  spring.cloud.nacos.prefix 默认为 spring.application.name。
  spring.profiles.active 为当前环境(好比:dev、test、prod 等)。
  spring.cloud.nacos.file-extension 为配置文件后缀名,通常为:yaml、properties。

下面配置文件,将会读取配置中心中 nacos-client-config-dev.yml 文件。

【bootstrap.yml】
server:
  port: 7100

spring:
  application:
    name: nacos-client-config
  cloud:
    nacos:
      discovery:
        # 配置 nacos server 地址(做为注册中心)
        server-addr: 120.26.184.41:8848
      config:
        # 配置 nacos server 地址(做为配置中心)
        server-addr: 120.26.184.41:8848
        # 设置配置文件前缀,默认为 ${spring.application.name}
        prefix: ${spring.application.name}
        # 设置配置文件后缀名
        file-extension: yml
        
【application.yml】
spring:
  profiles:
    active: dev

config:
  info: ${spring.application.name}-${server.port}-${spring.profiles.active}

 

 

 

Step3:
  编写测试 controller,用于测试。
  须要添加 @RefreshScope 注解,用于自动刷新。

【TestConfigController】
package com.lyh.springcloud.nacos_client_7100.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/config")
@RestController
@RefreshScope
public class TestConfigController {

    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/info")
    public String getInfo() {
        return configInfo;
    }
}

 

 

 

Step4:
  访问:http://localhost:7100/config/info
  初始时,若 Nacos Server 中不存在配置文件,则会先加载本地 配置文件中的 config.info。

 

 

 在配置中心添加配置文件以下:

 

 

 

再次访问,则获取到的是配置中心最新的配置信息。

 

 

 

六、Namespace、Group、DataID

(1)问题与解决:

【问题:】
    实际开发中,一个服务可能会对应多个配置环境(dev、test、prod 等)。
    那么如何保证服务启动时 能 读取到 正确的 配置文件?
    
    一个大型的微服务系统中,存在不少服务,每一个服务都有不一样的配置环境,
    那么可否统一的、有规划的对配置进行管理呢?
    
【解决:】
    Nacos 中 使用 命名空间(Namespace)、Group(分组)、DataID(配置文件 ID)对配置文件进行管理。

 

(2)Namespace、Group、DataID

【Namespace:】
Namespace 默认为 public。通常用于实现环境隔离,不一样的命名空间是相互隔离的。
好比:
    如今有三个环境:开发、测试、生产,则能够建立三个命名空间,每一个命名空间对应一个环境。
    须要切换环境时,只需切换 命名空间 便可。

【Group:】
Group 默认为 DEFAULT_GROUP。经过一个有意义的字符串对 配置集 或者 服务 进行分组。

【DataID:】
DataID 就是每一个配置文件的惟一标识。

【简单理解:】
    Namespace、Group、DataID 的关系能够理解成一个 文件系统。
    Namespace 为最顶层的目录,其能够包含多个 Group。
    Group 为 二级目录,其能够包含多个 DataID。
    DataID 为 文件名。
    Namespace + Group + DataID 组成配置文件的惟一标识。
注:
    Namespace 能够经过 spring.cloud.nacos.config.namespace 指定(在 bootstrap.yml 中指定,且为 命名空间的 id 值)。
    Group 能够经过 spring.cloud.nacos.config.group 指定(在 bootstrap.yml 中指定)。

 

 

 

(3)演示
Step1:
  修改 nacos_client_7100 配置文件以下,添加一个分组 TEST_GROUP。

 

 

 

Step2:
  访问配置中心,查看当前配置文件列表。
  以下图所示,仅有一个分组为 DEFAULT_GROUP 的配置文件。

 

 

 

Step3:
  访问:http://localhost:7100/config/info
  因为配置中心中不存在 TEST_GROUP 分组的配置文件,因此加载本地配置文件信息。

 

 

 

Step4:
  在配置中心添加一个 nacos-client-config-dev.yml 且分组为 TEST_GROUP 的文件。

 

 

 

Step5:
  再次访问 http://localhost:7100/config/info
  能够读取到 分组为 TEST_GROUP 的 nacos-client-config-dev.yml 文件中的信息。

 

 

 

七、nacos 获取配置的方式(配置共享)

(1)问题与解决

【问题:】
    经过前面的使用,已经知道最基本的 配置文件获取方式为 ${spring.cloud.nacos.prefix} - ${spring.profiles.active} . ${spring.cloud.nacos.file-extension}。
    若仅仅这么使用,只能获取到配置中心的一个配置文件。
    当服务部署了集群后,每一个服务对应一个配置文件,此时这些配置文件可能会出现不少重复的内容。
    服务出现变更时,可能须要修改每一个配置文件,增长了无用的工做量。
    
    那么可否拆分配置文件,使部分配置文件能够共享?
    可否使服务同时获取多个配置文件?
    
【解决:】
    nacos 提供了三种获取配置文件的方式。
方式:
    A:经过内部相关规则自动生成相关的 Data Id 配置(${spring.cloud.nacos.prefix} - ${spring.profiles.active} . ${spring.cloud.nacos.file-extension})。
    B:经过 spring.cloud.nacos.config.extension-configs[n].data-id 的方式支持多个扩展 Data Id 的配置。
    C:经过 spring.cloud.nacos.config.shared-configs[n].data-id 支持多个共享 Data Id 的配置。
优先级:
    A > B > C
注:
    extension-configs、shared-configs 支持获取多个配置文件(n 越大优先级越高)。

 

(2)演示 extension-configs 使用
Step1:
  extension-configs 说明:

【extension-configs 说明:】
    extension-configs 类型为 List<NacosConfigProperties.Config>
Config:
    dataId   String 类型,即配置文件名(好比:config-dev.yml)
    group    String 类型,即分组名,默认为 DEFAULT_GROUP
    refresh  boolean 类型,是否具有自动刷新,默认为 false(修改配置文件不自动刷新)

 

Step2:
  修改 bootstrap.yml 、application.yml以下:

【bootstrap.yml】
server:
  port: 7100

spring:
  application:
    name: nacos-client-config
  cloud:
    nacos:
      discovery:
        # 配置 nacos server 地址(做为注册中心)
        server-addr: 120.26.184.41:8848
      config:
        # 配置 nacos server 地址(做为配置中心)
        server-addr: 120.26.184.41:8848
        # 设置配置文件前缀,默认为 ${spring.application.name}
        prefix: ${spring.application.name}
        # 设置配置文件后缀名
        file-extension: yml
        extension-configs[0]:
          data-id: test-0-dev.yml
        extension-configs[1]:
          data-id: test-1-dev.yml
        extension-configs[2]:
          data-id: test-2-dev.yml
          group: DEFAULT_GROUP
          refresh: true

【application.yml】
spring:
  profiles:
    active: dev

config:
  info: ${spring.application.name}-${server.port}-${spring.profiles.active}
  test-0: test-0
  test-1: test-1
  test-2: test-2

 

 

 

Step3:
  修改 controller,获取配置信息。

package com.lyh.springcloud.nacos_client_7100.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/config")
@RestController
@RefreshScope
public class TestConfigController {

    @Value("${config.info}")
    private String configInfo;

    @Value("${config.test-0}")
    private String test0;

    @Value("${config.test-1}")
    private String test1;

    @Value("${config.test-2}")
    private String test2;

    @GetMapping("/test")
    public String test() {
        return test0 + " ---- " + test1 + " ---- " + test2;
    }

    @GetMapping("/info")
    public String getInfo() {
        return configInfo;
    }
}

 

 

 

 

Step4:
  访问配置中心,查看当前配置列表。

 

 

 

Step5:
  访问:http://localhost:7100/config/test
  因为配置列表为空,服务仅加载本地配置文件。

 

 

 

Step6:
  添加配置文件。

 

 

 

 

 

 

 

 

Step7:
  再次访问:http://localhost:7100/config/test
  因为 test-0-dev.yml 以及 test-1-dev.yml 没有配置自动刷新,因此值没有正常变化。
  而 test-2-dev.yml 配置了自动刷新,其值正常变化。

 

 

 

(3)演示 shared-configs 使用
  shared-configs 用法 与 extension-configs 相同,区别是 extension-configs 优先级高于 shared-configs。(此处省略验证步骤,参考上面 extension-configs 的使用)

【bootstrap.yml】
server:
  port: 7100

spring:
  application:
    name: nacos-client-config
  cloud:
    nacos:
      discovery:
        # 配置 nacos server 地址(做为注册中心)
        server-addr: 120.26.184.41:8848
      config:
        # 配置 nacos server 地址(做为配置中心)
        server-addr: 120.26.184.41:8848
        # 设置配置文件前缀,默认为 ${spring.application.name}
        prefix: ${spring.application.name}
        # 设置配置文件后缀名
        file-extension: yml
        shared-configs[0]:
          data-id: test-0-dev.yml
        shared-configs[1]:
          data-id: test-1-dev.yml
        shared-configs[2]:
          data-id: test-2-dev.yml
          group: DEFAULT_GROUP
          refresh: true

 

八、docker-compose 部署 Nacos Server(伪集群版)

(1)说明:
  集群至少得有 3 个 Nacos Server 节点。节点多的话 能够搞个 Nginx 作个代理。
  有条件的能够搞三台 云服务器 玩玩。没条件的能够搞三台 虚拟机 玩玩。
  想偷懒的能够直接在一台服务器上启动 三个 Nacos Server 节点(大坑,不建议作)。
注:
  此处为了偷懒,使用 docker-compose 一次性启动 mysql 以及3 个 Nacos 节点,相关的坑我也作了一些说明,鬼知道我为了解决这些坑经历了什么 (=_=)。

(2)Nacos 经常使用几个日志文件(此处以 伪集群版日志 进行举例)

【判断 nacos 是否正常启,通常看下面几个日志文件:】
日志文件:
    /home/nacos/logs/start.out            nacos 是否正常启动
    /home/nacos/logs/nacos.log            nacos 执行过程当中是否报错
    /home/nacos/logs/naming-raft.log      nacos 选举是否异常

【对于 start.out 文件:】
若 Nacos 一直未启动完成,通常会输出:  
    Nacos is starting...
好比:
    2021-03-25 15:11:05,419 INFO Nacos is starting...
    
若 Nacos 启动完成,通常会输出:
    Nacos started successfully in cluster mode. use external storage
好比:
    2021-03-25 15:11:06,811 INFO Nacos started successfully in cluster mode. use external storage
    
【对于 naming-raft.log 文件:】
若 Nacos 一直未选举成功,其输出日志以下:
   ERROR NACOS-RAFT vote failed: 500, url: http://120.26.184.41:8850/nacos/v1/ns/raft/vote
   ERROR NACOS-RAFT vote failed: 500, url: http://120.26.184.41:8851/nacos/v1/ns/raft/vote
   WARN [IS LEADER] no leader is available now!

若选举成功,输出日志为:
2021-03-26 09:46:49,896 INFO received approve from peer: {"ip":"120.26.184.41:8850","voteFor":"120.26.184.41:8849","term":5,"leaderDueMs":19506,"heartbeatDueMs":3500,"state":"FOLLOWER"}
2021-03-26 09:46:49,897 INFO 120.26.184.41:8849 has become the LEADER
2021-03-26 09:46:49,898 INFO received approve from peer: {"ip":"120.26.184.41:8851","voteFor":"120.26.184.41:8849","term":5,"leaderDueMs":17941,"heartbeatDueMs":3500,"state":"FOLLOWER"}

【对于 nacos.log 文件:】
当 Nacos 选举异常时,可能会输出:
    java.lang.IllegalStateException: can not find peer: 172.22.0.5:8848

若没有错误日志输出,输出以下日志,能够认为启动正常:
2021-03-26 09:34:08,199 INFO Started Nacos in 94.251 seconds (JVM running for 100.9)
2021-03-26 09:34:08,199 INFO Nacos Log files: /home/nacos/logs
2021-03-26 09:34:08,208 INFO Nacos Log files: /home/nacos/conf
2021-03-26 09:34:08,208 INFO Nacos Log files: /home/nacos/data
2021-03-26 09:34:08,209 INFO Nacos started successfully in cluster mode. use external storage
2021-03-26 09:34:08,873 INFO Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-03-26 09:34:08,873 INFO Initializing Servlet 'dispatcherServlet'
2021-03-26 09:34:08,954 INFO Completed initialization in 81 ms

 

(3)伪集群版(大坑)
Step1:编写 docker-compose.yml 文件
  与单机版 docker-compose.yml 相似,
  多了参数 NACOS_SERVERS、NACOS_APPLICATION_PORT。
  修改了 JVM_XMS 、JVM_MMS 等参数。
  修改了 nacos-mysql 版本。
  修改了 nacos-server 版本。
注意:
  添加了 NACOS_APPLICATION_PORT 后,须要修改相应的端口映射 ports。
  添加了 NACOS_SERVERS 后,设置多节点可使用 逗号 或者 空格 隔开。
  JVM_XMS 等参数设置太小时,Nacos 可能跑不起来(适量调大一点)。
  若你尝试过一切手段,配置均正常时,Nacos 仍然跑不起来 或者 选举失败,而在网上找不到任何解决办法时,这边建议你 更换 镜像版本试一下 (=_=),鬼知道我试了多少次才解决的。


这边使用的都是官方镜像,能够本身手动生成镜像,具体有些什么坑,请自行尝试!!!

【docker-compose.yml】
version: '3.7'
services:
  mysql:
    container_name: nacos-cluster-mysql
    image: nacos/nacos-mysql:5.7
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=nacos_devtest
      - MYSQL_USER=nacos
      - MYSQL_PASSWORD=nacos
    volumes:
      - ./mysql/data:/var/lib/mysql
      - ./mysql/log:/var/log/mysql
    ports:
      - "3308:3306"
  nacos1:
    image: nacos/nacos-server:1.3.0
    container_name: nacos1
    restart: always
    environment:
      - NACOS_SERVERS=120.26.184.41:8849 120.26.184.41:8850 120.26.184.41:8851
      - NACOS_SERVER_IP=120.26.184.41
      - NACOS_APPLICATION_PORT=8849
      - TZ=Asia/Shanghai
      - SPRING_DATASOURCE_PLATFORM=mysql
      - MYSQL_SERVICE_HOST=120.26.184.41
      - MYSQL_SERVICE_PORT=3308
      - MYSQL_SERVICE_DB_NAME=nacos_devtest
      - MYSQL_SERVICE_USER=root
      - MYSQL_SERVICE_PASSWORD=root
      - JVM_XMS=100m
      - JVM_MMS=100m
    volumes:
      - ./cluster-logs/nacos1:/home/nacos/logs
    depends_on:
      - mysql
    ports:
      - 8849:8849
  nacos2:
    image: nacos/nacos-server:1.3.0
    container_name: nacos2
    restart: always
    environment:
      - NACOS_SERVERS=120.26.184.41:8849 120.26.184.41:8850 120.26.184.41:8851
      - NACOS_SERVER_IP=120.26.184.41
      - NACOS_APPLICATION_PORT=8850
      - TZ=Asia/Shanghai
      - SPRING_DATASOURCE_PLATFORM=mysql
      - MYSQL_SERVICE_HOST=120.26.184.41
      - MYSQL_SERVICE_PORT=3308
      - MYSQL_SERVICE_DB_NAME=nacos_devtest
      - MYSQL_SERVICE_USER=root
      - MYSQL_SERVICE_PASSWORD=root
      - JVM_XMS=100m
      - JVM_MMS=100m
    volumes:
      - ./cluster-logs/nacos2:/home/nacos/logs
    depends_on:
      - mysql
    ports:
      - 8850:8850
  nacos3:
    image: nacos/nacos-server:1.3.0
    container_name: nacos3
    restart: always
    environment:
      - NACOS_SERVERS=120.26.184.41:8849 120.26.184.41:8850 120.26.184.41:8851
      - NACOS_SERVER_IP=120.26.184.41
      - NACOS_APPLICATION_PORT=8851
      - TZ=Asia/Shanghai
      - SPRING_DATASOURCE_PLATFORM=mysql
      - MYSQL_SERVICE_HOST=120.26.184.41
      - MYSQL_SERVICE_PORT=3308
      - MYSQL_SERVICE_DB_NAME=nacos_devtest
      - MYSQL_SERVICE_USER=root
      - MYSQL_SERVICE_PASSWORD=root
      - JVM_XMS=100m
      - JVM_MMS=100m
    volumes:
      - ./cluster-logs/nacos3:/home/nacos/logs
    depends_on:
      - mysql
    ports:
      - 8851:8851

      
【巨坑:】
    想偷懒,却掉进了个大坑(没解决),特此记录一下,有时间再仔细研究。
情景再现:
    在阿里云服务器上,想使用 docker-compose 一次性启动三个 Nacos Server 以及 mysql,结果一直启动失败。
坑一:    
    nacos-mysql:8.0.16 没法启动,更换成 nacos-mysql:5.7 以后正常启动。
    但若 nacos-mysql:8.0.16 是事先就启动好的(即不跟随 Nacos Server 启动),那么链接是正常的。
    为何会出现这种状况,没有仔细研究,此处仅简单记录一下可能存在的问题。

坑二:
    访问 http://120.26.184.41:8850/nacos,能够成功登陆进去。
    但点击 “集群管理” =》 “节点列表”,依次点击 “节点元数据”,能够发现其 "state" 均为 "CANDIDATE"。
    即 集群中三个节点 并未选举成功,未成功选举出 LEADER、FOLLOWER。
    
坑三:
    集群节点 "state" 均为 "FOLLOWER",没有 "LEADER"。选举仍然失败。
    出现了 8848 端口,貌似其被选择为 LEADER。
    
坑四:
    当前以为你的配置没有问题了,可是 选举依然失败,这边建议你更换一下镜像看看。
    此处 nacos/nacos-server:1.4.1 选举老是失败,更换 nacos/nacos-server:1.3.0 以后没问题了。
    具体缘由没有深刻研究,此处仅记录一下可能存在的问题。

 

Step2:填坑记录一:
  将 nacos-mysql:8.0.16 镜像替换为 nacos-mysql:5.7 后,从新启动便可。

 

 

 

 

 

 

Step3:填坑记录二:
  若在控制台页面中,看见节点 “state” 均为 “CANDIDATE”。这是选举出问题了,能够查看 nacos 日志(naming-raft.log、nacos.log)。

【nacos.log 错误日志为:(以下两句语句循环出现)】
    java.lang.IllegalStateException: can not find peer: 172.22.0.3:8848
    java.lang.IllegalStateException: can not find peer: 172.22.0.5:8848
    
【naming-raft.log 错误日志为:】
    ERROR NACOS-RAFT vote failed: 500, url: http://120.26.184.41:8850/nacos/v1/ns/raft/vote
    ERROR NACOS-RAFT vote failed: 500, url: http://120.26.184.41:8851/nacos/v1/ns/raft/vote
    WARN [IS LEADER] no leader is available now!
    
【分析:】
    经过 nacos.log 的 ip 地址,能够猜想当前 nacos 读取到的是内网 IP。
    而集群列表中不存在这个 IP,因此没法链接到其他 节点(没法通讯),进而选举失败。
    
【解决:】
    既然获取不到 IP 地址,那就手动输入 IP 地址。
    在环境变量中,经过 NACOS_SERVER_IP 指定当前主机的 IP 便可。
    好比: - NACOS_SERVER_IP=120.26.184.41

 

 

 

 

 

 

 

 

 

Step4:填坑记录三
  经过上面截图,能够看到三个节点状态均从 "CANDIDATE" 变为了 "FOLLOWER",为何没有选举出 "LEADER"?

【查看 naming-raft.log 日志以下:】
2021-03-25 17:45:09,770 INFO received approve from peer: {"ip":"120.26.184.41:8848","voteFor":"120.26.184.41:8848","term":9,"leaderDueMs":18440,"heartbeatDueMs":2000,"state":"FOLLOWER"}
2021-03-25 17:45:09,772 INFO received approve from peer: {"ip":"120.26.184.41:8848","voteFor":"120.26.184.41:8848","term":9,"leaderDueMs":18531,"heartbeatDueMs":5000,"state":"CANDIDATE"}
2021-03-25 17:45:09,788 INFO received approve from peer: {"ip":"120.26.184.41:8848","voteFor":"120.26.184.41:8848","term":9,"leaderDueMs":18671,"heartbeatDueMs":5000,"state":"FOLLOWER"}
2021-03-25 17:45:15,001 WARN [IS LEADER] no leader is available now!
2021-03-25 17:45:28,123 INFO vote 120.26.184.41:8848 as leader, term: 10

【分析:】
    经过日志能够看到貌似 120.26.184.41:8848 这个东西被选为了 LEADER,
    而实际上 我开放的是 884九、8850、8851 三个端口,可是这三个端口并无被访问。

【解决:】
    默认端口号为 8848。既然获取不到端口,那就手动设置端口。
    在环境变量中,经过 NACOS_APPLICATION_PORT 指定当前主机须要访问的端口便可。  
    修改 NACOS_APPLICATION_PORT 后,端口映射 ports 也须要修改。
好比:
    environment:
      - NACOS_APPLICATION_PORT=8851
    ports:
      - 8851:8851

 

 

 

 

 

 

 

 

 

(4)链接 Nacos 集群
  在 Nacos Client 配置文件中,直接经过 server-addr 设置节点地址便可,多个节点之间可以使用 逗号 隔开。
  若使用 Nginx 作代理,则 server-addr 设置 Nginx 访问地址便可。
  Nginx 在 Nacos 真集群版中使用(请继续往下看)。

【好比:】
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 120.26.184.41:8849,120.26.184.41:8850,120.26.184.41:8851
      config:
        server-addr: 120.26.184.41:8849,120.26.184.41:8850,120.26.184.41:8851

【bootstrap.yml】
server:
  port: 7100

spring:
  application:
    name: nacos-client-config
  cloud:
    nacos:
      discovery:
        # 配置 nacos server 地址(做为注册中心)
        # server-addr: 120.26.184.41:8848
        server-addr: 120.26.184.41:8849,120.26.184.41:8850,120.26.184.41:8851
      config:
        # 配置 nacos server 地址(做为配置中心)
        # server-addr: 120.26.184.41:8848
        server-addr: 120.26.184.41:8849,120.26.184.41:8850,120.26.184.41:8851
        # 设置配置文件前缀,默认为 ${spring.application.name}
        prefix: ${spring.application.name}
        # 设置配置文件后缀名
        file-extension: yml
        shared-configs[0]:
          data-id: test-0-dev.yml
        shared-configs[1]:
          data-id: test-1-dev.yml
        shared-configs[2]:
          data-id: test-2-dev.yml
          group: DEFAULT_GROUP
          refresh: true

 

 

 

九、docker-compose 部署 Nacos Server(真集群版)

(1)说明:
  上面使用 docker-compose 演示了伪集群的操做,许多坑已经踩过了。真集群部署就更加简单了,将上面伪集群版的 docker-compose.yml 文件拆分红 几个小的 docker-compose.yml 文件,分别在不一样的机器上启动便可(固然 ip 是须要修改的)。
此处建立三个 虚拟机,地址分别为:192.168.157.12八、192.168.157.12九、192.168.157.130。
  在 192.168.157.128 上启动 mysql、nginx、nacos1。
  在 12九、130 上分别启动 nacos二、nacos3。
其中:
  使用 nginx 反向代理 nacos一、nacos二、nacos3。经过 nginx 访问 Nacos Server。
  使用 mysql 作配置信息持久化操做。
注:
  此处可使用较高版本的 mysql、nacos。好比:nacos-mysql:8.0.1六、nacos-server:1.4.1 。

(2)配置 mysql 以及 nginx。
Step1:
  自定义一个 nginx.conf,进行代理配置。
  以下所示,主要关注 server 以及 upstream nacos_server。

 

【nginx.conf】
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    # 负载均衡
    upstream nacos_server {
    # 默认加权轮询方式执行负载均衡
    # weight 表示服务器权重,默认为 1。
    # max_fails 表示 nginx 与 服务器通讯失败 的最大次数。默认为 1。
    # fail_timeout 为失败超时时间。默认 10 秒。在 fail_timeout 时间内,失败次数达到 max_fails,则 Nginx 认为该服务器不可用。
        server 192.168.157.128:8849 weight=1 max_fails=2 fail_timeout=10s;
        server 192.168.157.129:8850 weight=1 max_fails=2 fail_timeout=10s;
        server 192.168.157.130:8851 weight=1 max_fails=2 fail_timeout=10s;
    }

    server {
        listen  10080;     # 设置监听端口
        server_name 192.168.157.128;         # 设置 IP 地址
        location / {
            # 设置代理地址(根据 upstream 的值修改)
            # 访问请求 http://192.168.157.128:10080 时,会替换为 http://192.168.157.128:8849/nacos/ 
            proxy_pass http://nacos_server/nacos/;
            
        # 下面几个设置默认便可
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header REMOTE-HOST $remote_addr;
            add_header X-Cache $upstream_cache_status;
            add_header Cache-Control no-cache;
        }
    }
    include /etc/nginx/conf.d/*.conf;
}

 

Step2:
  编写 docker-compose.yml 文件,配置 mysql、nginx。
  须要将 上面自定义的 conf 文件 挂载到 nginx 的 /etc/nginx/nginx.conf 目录下。

【docker-compose.yml】
version: '3.7'
services:
  nginx:
    container_name: nginx
    image: nginx:latest
    restart: always
    ports:
      - "10080:10080"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./logs:/var/log/nginx/
  mysql:
    container_name: nacos-cluster-mysql
    image: nacos/nacos-mysql:5.7
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=nacos_devtest
      - MYSQL_USER=nacos
      - MYSQL_PASSWORD=nacos
    volumes:
      - ./mysql/data:/var/lib/mysql
      - ./mysql/log:/var/log/mysql
    ports:
      - "3308:3306"

 

(3)配置 nacos一、nacos二、nacos3

【nacos1:】
version: '3.7'
services:
  nacos1:
    image: nacos/nacos-server:1.3.0
    container_name: nacos1
    restart: always
    environment:
      - NACOS_SERVERS=192.168.157.128:8849 192.168.157.129:8850 192.168.157.130:8851
      - NACOS_SERVER_IP=192.168.157.128
      - NACOS_APPLICATION_PORT=8849
      - TZ=Asia/Shanghai
      - SPRING_DATASOURCE_PLATFORM=mysql
      - MYSQL_SERVICE_HOST=192.168.157.128
      - MYSQL_SERVICE_PORT=3308
      - MYSQL_SERVICE_DB_NAME=nacos_devtest
      - MYSQL_SERVICE_USER=root
      - MYSQL_SERVICE_PASSWORD=root
      - JVM_XMS=100m
      - JVM_MMS=100m
    volumes:
      - ./nacos1:/home/nacos/logs
    ports:
      - 8849:8849
      
【nacos2:】
version: '3.7'
services:
  nacos2:
    image: nacos/nacos-server:1.3.0
    container_name: nacos2
    restart: always
    environment:
      - NACOS_SERVERS=192.168.157.128:8849 192.168.157.129:8850 192.168.157.130:8851
      - NACOS_SERVER_IP=192.168.157.129
      - NACOS_APPLICATION_PORT=8850
      - TZ=Asia/Shanghai
      - SPRING_DATASOURCE_PLATFORM=mysql
      - MYSQL_SERVICE_HOST=192.168.157.128
      - MYSQL_SERVICE_PORT=3308
      - MYSQL_SERVICE_DB_NAME=nacos_devtest
      - MYSQL_SERVICE_USER=root
      - MYSQL_SERVICE_PASSWORD=root
      - JVM_XMS=100m
      - JVM_MMS=100m
    volumes:
      - ./nacos2:/home/nacos/logs
    ports:
      - 8850:8850

【nacos3:】
version: '3.7'
services:
  nacos3:
    image: nacos/nacos-server:1.3.0
    container_name: nacos3
    restart: always
    environment:
      - NACOS_SERVERS=192.168.157.128:8849 192.168.157.129:8850 192.168.157.130:8851
      - NACOS_SERVER_IP=192.168.157.130
      - NACOS_APPLICATION_PORT=8851
      - TZ=Asia/Shanghai
      - SPRING_DATASOURCE_PLATFORM=mysql
      - MYSQL_SERVICE_HOST=192.168.157.128
      - MYSQL_SERVICE_PORT=3308
      - MYSQL_SERVICE_DB_NAME=nacos_devtest
      - MYSQL_SERVICE_USER=root
      - MYSQL_SERVICE_PASSWORD=root
      - JVM_XMS=100m
      - JVM_MMS=100m
    volumes:
      - ./nacos3:/home/nacos/logs
    ports:
      - 8851:8851

 

(4)启动
  分别启动 nginx、mysql、nacos一、nacos二、nacos3。
  访问:http://192.168.157.128:10080/ 会自动跳转到相应的 Nacos 控制台界面。

 

 

 

手动关闭 8850 端口的 Nacos,剩余节点会从新进行选举,选举出 LEADER。

 

 

 

(5)链接 nacos 集群
  若未使用 Nginx 代理时,直接在 Nacos Client 配置文件中,直接经过 server-addr 设置节点地址便可,多个节点之间可以使用 逗号 隔开。

spring:
  cloud:
    nacos:
      discovery:
        # 配置 nacos server 地址(做为注册中心)
        server-addr: 192.168.157.128:8849,192.168.157.129:8850,192.168.157.130:8851
      config:
        # 配置 nacos server 地址(做为配置中心)
        server-addr: 192.168.157.128:8849,192.168.157.129:8850,192.168.157.130:8851

  若使用 Nginx 作代理,则 server-addr 设置 Nginx 访问地址便可。
注:
  此处关于 proxy_pass 设置的地址 有个小坑记录一下。

server{
    listen  10080;     # 设置监听端口
    server_name 192.168.157.128;         # 设置 IP 地址
    location / {
        # 设置代理地址(根据 upstream 的值修改)
        # 访问请求 http://192.168.157.128:10080 时,会替换为 http://192.168.157.128:8849/nacos/ 
        proxy_pass http://nacos_server/nacos/;
        #proxy_pass http://nacos_server/;
}

若使用 proxy_pass http://nacos_server/,则在 Nacos Client 中直接配置 Nginx 地址便可。
此时,客户端正常启动,能够经过 Nginx 访问到 Nacos Server 集群,获取配置文件。
可是直接经过 Nginx 地址(http://192.168.157.128:10080 或者 http://192.168.157.128:10080/nacos),没法跳转到 Nacos 控制台界面。

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.157.128:10080
      config:
        server-addr: 192.168.157.128:10080

 

若使用 proxy_pass http://nacos_server/nacos/,则经过 Nginx 地址(http://192.168.157.128:10080) 正常跳转进 Nacos 控制台界面,但若此时 Nacos Client 直接配置 Nginx 地址时,服务启动会异常,启动失败。
报错信息以下:

【错误信息:】
org.springframework.context.ApplicationContextException: Failed to start bean 'webServerStartStop'; nested exception is java.lang.reflect.UndeclaredThrowableException

Caused by: java.lang.reflect.UndeclaredThrowableException: null

Caused by: com.alibaba.nacos.api.exception.NacosException: failed to req API:/nacos/v1/ns/instance after all servers([192.168.157.128:10080]) tried: ErrCode:404, ErrMsg:<html><body><h1>Whitelabel Error Page</h1><p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p><div id='created'>Fri Mar 26 20:22:33 CST 2021</div><div>There was an unexpected error (type=Not Found, status=404).</div><div>No message available</div></body></html>

 

为了使服务正常执行,此处使用 proxy_pass http://nacos_server/ 。
Nginx 跳转不了 Nacos Server 控制台界面问题,有时间再来解决。

 

3、网关 -- Gateway

一、什么是 Gateway?

(1)什么是 Gateway?

【Gateway:】
    Gateway 直译为 网关,是基于 Spring Boot 2.x、Spring WebFlux、Project Reactor 构建的 API 网关服务。
    Gateway 目的是 提供一个简单的方式进行 路由转发,用于保护、控制、加强 对于 API 接口的访问。
简单理解:
    Gateway 能够理解为 全部流量(请求)的入口,全部浏览器请求 都得经过 Gateway 进行路由,才能访问到服务提供的 API 接口。能够类比于 Nginx 反向代理进行理解。
    Gateway 底层使用的是 Netty 框架。
注:
    在 Gateway 以前,会使用 Zuul 做为网关,有兴趣的请自行了解。
    Zuul 1.x 是基于 Servlet 2.5 的 阻塞 I/O 的 API 网关,不支持长链接。
    Zuul 2.x 是基于 Netty 的 非阻塞 I/O 的 API 网关,支持长链接。
    SpringCloud 并无整合 Zuul 2.x,而是本身开发的一个 Gateway。
    Gateway 毕竟是亲生的,在微服务中整合起来相对简单,因此使用较多的仍是 Gateway。
     
【官网地址:】
    https://spring.io/projects/spring-cloud-gateway
    https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/

 

 

 

 

(2)网关使用场景?
  以下图所示,网关做为全部流量的 入口,根据路由规则 将请求路由到各个微服务上。

  若网关部署为 集群时,可使用 Nginx 对其进行负载均衡。

 

 

 

(3)Gateway 功能
Gateway 基于 Spring Framework 5,Project Reactor、Spring Boot 2.0 构建,其基本功能以下:
  可以匹配任何请求属性的路由(支持动态路由,能够根据微服务名进行路由)。
  能够针对特殊路由指定 Predicates 和 Filter 规则,且 Filter、Predicates 易编写。
  集成 断路器 功能(Circuit Breaker)。
  集成 服务发现 功能(Spring Cloud DiscoveryClient)。
  集成 请求限流 功能。
  支持 路径重写 功能。


二、Gateway 核心概念(Route、Filter、Predicate)

(1)Route(路由)
  路由是构建网关的基本模块,基本构成组件: ID、目标 URL、Predicate 集合、Filter 集合 组成。当 Predicate 为 true 时,匹配该路由。

(2)Predicate(断言)
  能够参考 JDK8 中 java.util.function.Predicate 进行理解。
  能够根据 HTTP 请求中的内容(好比:请求头、请求参数 等)进行匹配,若是匹配结果为 true,则匹配该路由。

(3)Filter(过滤)
  指的是 Spring 框架中 GatewayFilter 的实例,根据过滤器,能够在 请求被 路由前 或者 路由后 对请求进行更改。

(4)gateway 工做流程
  Gateway 整个工做流程就是 路由转发 + 过滤器链。
  客户端 向 Gateway 发送请求,在 Gateway Handler Mapping 中找到与 请求匹配的 路由(根据 Predicate 匹配 Route),而后将其转发到 Gateway Web Handler 进行处理。
  Handler 经过指定的过滤器链后,将请求发送到实际的业务逻辑进行处理,处理完成后返回。同时过滤器也能够对返回数据进行处理。
  过滤器 能够在路由处理前 进行 参数校验、权限校验、流量监控、协议转换 等操做。
  过滤器 能够在路由处理后 进行 响应内容修改、日志输出、流量监控等操做。

 

 

 

三、简单使用一下 Gateway

(1)说明
  新建一个子模块 gateway_7200,经过配置文件的方式,简单测试一下 路由匹配规则。此处简单的与 前面使用的 Nacos 一块儿使用。具体使用规则可参考官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/

(2)使用 Gateway
Step1:
  引入 Gateway 依赖。Gateway 注册到 Nacos Server 中。
注:
  添加 Gateway 依赖后,须要排除 spring-boot-starter-web 依赖。若不排除,则启动网关服务时将会出错。

【依赖:】
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

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

【错误:】
    若出现以下异常,须要移除 spring-boot-starter-web 依赖,不然会与 webflux 的 jar 包冲突致使启动失败。
   Description:
        Parameter 0 of method modifyRequestBodyGatewayFilterFactory in org.springframework.cloud.gateway.config.GatewayAutoConfiguration required a bean of type 'org.springframework.http.codec.ServerCodecConfigurer' that could not be found.
    Action:
        Consider defining a bean of type 'org.springframework.http.codec.ServerCodecConfigurer' in your configuration.

 

 

 

Step2:
  配置 Gateway。
  以下所示,配置 Nacos 注册中心地址为 120.26.184.41:8848。
  配置路由规则,此处演示 Path 进行匹配。
注:
  若使用 Path 进行路径匹配时,匹配成功后,真实访问路径其实就是 uri + Path。
好比:
  当请求为 http://localhost:7200/nacos/info/ 时,其将跳转到 http://localhost:7101/nacos/info 进行处理。
  当请求为 http://localhost:7200/ 时,其将跳转到 https://www.baidu.com/ 进行处理。

【application.yml】
server:
  port: 7200

spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        # 配置 nacos 地址
        server-addr: 120.26.184.41:8848
    # 网关配置
    gateway:
      # 配置路由规则
      routes:
      # 路由惟一 id 名
      - id: gateway_route
        # 断言为 true 时,需执行的 路由地址
        uri: http://localhost:7101
        # 定义断言,即 地址匹配 规则
        predicates:
        # 当访问 http://localhost:7200/naocs/info 时,此时断言匹配成功,根据 uri 将跳转到 http://localhost:7101/nacos/info
        - Path=/nacos/info
      - id: gateway_route2
        uri: https://www.baidu.com/
        predicates:
        - Path=/

 

Step3:
  启动 nacos_client_710一、gateway_7200。
  访问 http://localhost:7200/nacos/info 时,将跳转到 http://localhost:7101/nacos/info 处理。

 

 

 

  访问 http://localhost:7200/ 时,将跳转到 https://www.baidu.com/ 处理。

 

 

 

(3)根据微服务名进行 路由(动态路由)
  实际开发中,一个服务一般以集群的方式部署,若 uri 配置固定的地址进行跳转,确定是不合适的。而 微服务注册在 注册中心中,网关 只须要经过 注册中心 提供的 微服务名 找到真实的 微服务,进行路由便可。

修改的配置以下:
  在 uri 中使用 lb://微服务名 进行配置便可。lb 表示负载均衡。
  确保能根据 微服务名 进行路由,需配置 spring.cloud.gateway.discovery.locator.enabled=true
注:
  若注册中心为 nacos,仅需设置 uri 为 lb://微服务名 便可根据 微服务名进行 路由跳转,且实现负载均衡。其余注册中心 Eureka、Zookeeper、Consul 等此处并未进行尝试,若不能路由,则配置一下 discovery.locator.enabled=true 应该就好了。

 

 

【application.yml】
server:
  port: 7200

spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        # 配置 nacos 地址
        server-addr: 120.26.184.41:8848
    # 网关配置
    gateway:
      routes:
      - id: gateway_route3
        uri: lb://nacos-client
        predicates:
        # 配置多个地址时,可使用 逗号 隔开
        - Path=/nacos/info,/nacos/discovery

 

启动 nacos_client_710一、nacos_client_7102,微服务名为 nacos-client。
当访问 http://localhost:7200/nacos/info 时,会路由到 http://localhost:7101/nacos/info 与 http://localhost:7102/nacos/info ,并实现负载均衡(此处默认为 轮询)。

 

 

 

 

 

 

四、predicates 规则

  Gateway 内部有许多 Route Predicate factories,能够与 HTTP 请求的不一样属性进行匹配,多个 Predicate 规则能够组合使用。请求匹配成功后,则根据 uri 进行路由跳转。

常见的 Predicate 规则以下。
(1)时间相关(Before、After、Between)
  Before 表示在 指定时间(datetime) 前的请求 才能匹配路由。
  After 表示在 指定时间(datetime) 后的请求 才能匹配路由。
  Between 表示在 指定时间段(datetime1,datetime2) 内的请求 才能匹配路由。
注:
  时间参数 datetime 为 ZonedDateTime 的数据。
  可使用 System.out.println(ZonedDateTime.now()); 输出当前地区、时间。
  好比:2021-03-31T10:35:43.706+08:00[Asia/Shanghai]

【格式:】
predicates:
- After=datetime
- Before=datetime
- Between=datetime1,datetime2

【举例:】
predicates:
- After=2021-03-31T10:35:43.706+08:00[Asia/Shanghai]
- Before=2021-03-31T10:35:43.706+08:00[Asia/Shanghai]
- Between=2021-03-31T10:35:43.706+08:00[Asia/Shanghai],2021-03-31T10:40:43.706+08:00[Asia/Shanghai]


【举例:(以下,在指定时间以后的请求才能 路由。指定时间以前,路由将失败。)】
server:
  port: 7200

spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        # 配置 nacos 地址
        server-addr: 120.26.184.41:8848
    # 网关配置
    gateway:
      routes:
      - id: gateway_route3
        uri: lb://nacos-client
        predicates:
        # 配置多个地址时,可使用 逗号 隔开
        - Path=/nacos/info,/nacos/discovery
        - After=2021-03-31T10:40:00.706+08:00[Asia/Shanghai]

 

 

 

(2)Cookie 相关
  Cookie 规则具有两个参数,一个是 Cookie 属性名(name),一个是正则表达式(regexp)。
  根据 name 以及 regexp 去匹配路由。带有指定 cookie 信息的请求才能匹配路由。
有两种写法格式。

【格式一:】
predicates:
- Cookie=mycookiename,mycookievalue

【格式二:】
predicates:
- name: Cookie
  args:
    name: mycookiename
    regexp: mycookievalue
    
【举例:当请求 cookie 中携带 username 为 jarry 时,才能匹配路由】
server:
  port: 7200

spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        # 配置 nacos 地址
        server-addr: 120.26.184.41:8848
    # 网关配置
    gateway:
      routes:
      - id: gateway_route3
        uri: lb://nacos-client
        predicates:
        # 配置多个地址时,可使用 逗号 隔开
        - Path=/nacos/info,/nacos/discovery
        - After=2021-03-31T10:40:00.706+08:00[Asia/Shanghai]
        - Cookie=username,jarry
#        - name: Cookie
#          args:
#            name: username
#            regexp: tom

【经过 curl 模拟请求:】
curl http://localhost:7200/nacos/info --cookie "username=jarry"    路由匹配成功
curl http://localhost:7200/nacos/info --cookie "username=jarry1"   路由匹配失败

 

 

(3)Header、Host、Method、Path、Query、Weight 等
  能够自行尝试,此处不一一举例。

【Header:】
参数:
    name、regexp。 与 Cookie 规则相似。
    带有指定请求头的请求才能匹配路由。

格式:
predicates:
- Header=X-Request-Id, \d+

【Host:】
参数:
    patterns
    带有指定 host 的请求才能匹配路由。
    
格式:
predicates:
- Host=**.lyh.com

【Method:】
参数:
    methods
    带有指定方法的请求才能匹配路由。
    
格式:
predicates:
- Method=GET,POST

【Path:】
参数:
    PathMatcher
    带有指定路径的请求才能匹配路由。多路径使用逗号隔开。
    
格式:
predicates:
- Path=/red/{segment},/blue/{segment}

【Query:】
参数:
    param、regexp。 与 Cookie 规则相似。
    带有指定参数的请求才能匹配路由。
    
格式:
predicates:
- Query=green

【Weight:】
参数:
    group、weight。
    根据权重进行请求分流,80% 请求匹配到 weight_high,20% 请求匹配到 weight_low。
    
格式:
routes:
  - id: weight_high
    uri: https://weighthigh.org
    predicates:
    - Weight=group1, 8
  - id: weight_low
    uri: https://weightlow.org
    predicates:
    - Weight=group1, 2

【举例:】
server:
  port: 7200

spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        # 配置 nacos 地址
        server-addr: 120.26.184.41:8848
    # 网关配置
    gateway:
      routes:
      - id: gateway_route3
        uri: lb://nacos-client
        predicates:
        # 配置多个地址时,可使用 逗号 隔开
        - Path=/nacos/info,/nacos/discovery
        - After=2021-03-31T10:40:00.706+08:00[Asia/Shanghai]
        - Query=green,test.
        - Method=GET,POST
        - Host=**.lyh.com
        - Header=X-Request-Id, \d+
        - Cookie=username,jarry
        
【经过 curl 测试:(发送 GET、POST 请求)】
curl -X POST "http://localhost:7200/nacos/info?green=test1" --cookie "username=jarry" --header "X-Request-Id:123" --header "Host:www.lyh.com
curl "http://localhost:7200/nacos/info?green=test1" --cookie "username=jarry" --header "X-Request-Id:123" --header "Host:www.lyh.com

 

 

五、Filter 规则

  Gateway 内部有许多 GatewayFilter Factories,能够修改 HTTP 请求 以及 HTTP 响应。
  仅简单介绍几个 Filter,其他请自行参阅官方文档进行使用。
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories

(1)添加参数(好比:AddRequestParameter)
  参数为 name、value。用于在请求末尾追加参数(好比: ?name1=value1&name2=value2)
  能够在 predicates 指定变量 segment,并处理。

【格式:】
spring:
  cloud:
    gateway:
      routes:
      - id: add_request_parameter_route1
        uri: https://example.org
        predicates:
        - Path=/test/{segment}
        filters:
        - AddRequestParameter=foo, bar-{segment}
      - id: add_request_parameter_route2
        uri: https://example.org
        filters:
        - AddRequestParameter=red, blue
        
【举例:(修改 gateway 配置文件以下)】
server:
  port: 7200

spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        # 配置 nacos 地址
        server-addr: 120.26.184.41:8848
    # 网关配置
    gateway:
      routes:
      - id: gateway_route4
        uri: http://localhost:7101
        predicates:
        - Path=/nacos/test/{username}
        filters:
        - AddRequestParameter=password,{username}
        - AddRequestParameter=email,jarry@163.com
        
【在 nacos_client_7101 中添加以下代码:】
@GetMapping("/test/{username}")
public String test(@PathVariable String username,
                   @RequestParam(required = false) String password,
                   @RequestParam(required = false) String email,
                   @RequestParam(required = false) Integer age) {
    username = (username != null ? username : "hello");
    password = (password != null ? password : "helloworld");
    email = (email != null ? email : "tom@163.com");
    age = (age != null ? age : 24);
    return username + " " + password + " " + email + " " + age;
}

当访问 http://localhost:7200/nacos/test/hello 时,predicates 匹配成功,filters 发挥最用,等同于发送请求 http://localhost:7101/nacos/test/hello?password=hello&email=jarry@163.com

 

 (2)修改路径(好比:PrefixPath、StripPrefix)

【PrefixPath:】
    PrefixPath 用于指定 路径前缀。
好比:
gateway:
  routes:
  - id: gateway_route5
    uri: http://localhost:7101
    predicates:
    - Path=/info
    filters:
    - PrefixPath=/nacos
    
当访问 http://localhost:7200/info 时,将跳转到 http://localhost:7101/nacos/info

【StripPrefix:】
    StripPrefix 用于跳过 路径前缀(数值型)。
好比:
gateway:
  routes:
  - id: gateway_route5
    uri: http://localhost:7101
    predicates:
    - Path=/info/**
    filters:
    - StripPrefix=1

当访问 http://localhost:7200/info/nacos/info 时,将跳转到 http://localhost:7101/nacos/info

其他 Filter 可自行参考文档。也能够自定义 Filter。后续有时间再来补充。。。