nacos注册中心配置中心集群搭建

文章目录

  • 学习连接
  • 1.Nacos安装与简单使用
    • 1.1. Nacos安装指南
      • Windows安装
        • 下载安装包
        • 解压
        • 端口配置
        • 启动
        • 访问
      • Linux安装
        • 安装JDK
        • 上传安装包
        • 解压
        • 端口配置
        • 启动
    • 1.2.服务注册到nacos
      • 使用步骤
        • 引入依赖
        • 配置nacos地址
        • 重启
      • 示例
        • 父工程pom.xml
        • user-service
          • pom.xml
          • application.yml
          • UserApplication
          • UserController
          • UserService
        • order-service
          • pom.xml
          • application.yml
          • UserApplication
          • OrderService
          • UserClient
        • 访问nacos
  • 2.服务分级存储模型
    • 集群介绍
    • 服务跨集群调用问题
    • 服务集群属性
    • 同集群优先的负载均衡
      • 给user-service配置集群
        • 修改user-service的yml配置文件
        • 访问nacos
      • 给order-service配置集群
        • 修改order-service的yml配置文件
        • 访问nacos
      • 测试
    • 权重负载均衡
      • 测试
    • 环境隔离
      • Nacos环境隔离
      • 测试
  • 3. Nacos注册中心原理
    • nacos注册中心细节分析
      • nacos与eureka区别
        • nacos的 临时实例&非临时实例
        • 主动推送变更消息
        • 总结
        • 测试
  • 4. Nacos配置管理
    • 统一配置管理
      • 在nacos中添加配置文件
      • 从微服务拉取配置
        • 示例
        • 总结
    • 配置热更新
      • 方式一:@RefreshScope
      • 方式二:@ConfigurationProperties
      • 测试
    • 多环境配置共享
      • 优先级
      • 测试一
        • 添加一个环境共享配置
        • 在user-service中读取共享配置
        • 运行两个UserApplication,使用不同的profile
      • 测试二
        • 添加一个redis.yml
        • 修改UserApplication1的bootstrap.yaml
        • 修改redis.yml,并发布,再次访问测试
  • 5. Nacos集群
    • 集群结构图
    • 搭建集群
      • 初始化数据库
      • 下载nacos
      • 配置nacos
      • 启动
      • nginx反向代理
      • 项目配置
        • 依赖
        • bootstrap.yaml
        • application.yml
        • UserApplication
        • UserController2
      • 测试

学习连接

SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式

nacos官网

nacos github地址

【微服务】Nacos注册中心

nacos核心源码深度剖析

国内公司一般都推崇阿里巴巴的技术,比如注册中心,SpringCloudAlibaba也推出了一个名为Nacos的注册中心。

1.Nacos安装与简单使用

在这里插入图片描述

1.1. Nacos安装指南

Windows安装

开发阶段采用单机安装即可。

下载安装包

在Nacos的GitHub页面,提供有下载链接,可以下载编译好的Nacos服务端或者源代码:

GitHub主页:https://github.com/alibaba/nacos

GitHub的Release下载页:https://github.com/alibaba/nacos/releases

如图:

在这里插入图片描述

本课程采用1.4.1.版本的Nacos,课前资料已经准备了安装包:

在这里插入图片描述

windows版本使用nacos-server-1.4.1.zip包即可。

解压

将这个包解压到任意非中文目录下,如图:

在这里插入图片描述

目录说明:

  • bin:启动脚本
  • conf:配置文件
端口配置

Nacos的默认端口是8848,如果你电脑上的其它进程占用了8848端口,请先尝试关闭该进程。

如果无法关闭占用8848端口的进程,也可以进入nacos的conf目录,修改配置文件中的端口:

在这里插入图片描述

修改其中的内容:
在这里插入图片描述

启动

启动非常简单,进入bin目录,结构如下:

在这里插入图片描述

然后执行命令即可:

  • windows命令:

    ## 此时由于没有修改配置文件, 默认将数据持久化到与bin文件夹同级目录data文件夹中
    startup.cmd -m standalone
    

执行后的效果如图:

在这里插入图片描述

访问

在浏览器输入地址:http://127.0.0.1:8848/nacos即可:

在这里插入图片描述

默认的账号和密码都是nacos,进入后:

在这里插入图片描述

Linux安装

Linux或者Mac安装方式与Windows类似。

安装JDK

Nacos依赖于JDK运行,索引Linux上也需要安装JDK才行。

上传jdk安装包:

在这里插入图片描述

上传到某个目录,例如:/usr/local/
在这里插入图片描述

然后解压缩:

tar -xvf jdk-8u144-linux-x64.tar.gz

然后重命名为java

配置环境变量:

export JAVA_HOME=/usr/local/java
export PATH=$PATH:$JAVA_HOME/bin

设置环境变量:

source /etc/profile
上传安装包

如图:
在这里插入图片描述

也可以直接使用课前资料中的tar.gz:

上传到Linux服务器的某个目录,例如/usr/local/src目录下:

在这里插入图片描述

解压

命令解压缩安装包:

tar -xvf nacos-server-1.4.1.tar.gz

然后删除安装包:

rm -rf nacos-server-1.4.1.tar.gz

目录中最终样式:

在这里插入图片描述

目录内部:
在这里插入图片描述

端口配置

与windows中类似

启动

在nacos/bin目录中,输入命令启动Nacos:

sh startup.sh -m standalone

1.2.服务注册到nacos

Nacos是SpringCloudAlibaba的组件,而SpringCloudAlibaba也遵循SpringCloud中定义的服务注册、服务发现规范。因此使用Nacos和使用Eureka对于微服务来说,并没有太大区别。

主要差异在于:

  • 依赖不同
  • 服务地址不同

使用步骤

引入依赖

在cloud-demo父工程的pom文件中的<dependencyManagement>中引入SpringCloudAlibaba的依赖:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
    <version>2.2.6.RELEASE</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

然后在user-service和order-service中的pom文件中引入nacos-discovery依赖:

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

注意:不要忘了注释掉eureka的依赖。

配置nacos地址

在user-service和order-service的application.yml中添加nacos地址:

spring:
  cloud:
    nacos:
      server-addr: localhost:8848

注意:不要忘了注释掉eureka的地址

重启

重启微服务后,登录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>cn.itcast.demo</groupId>
    <artifactId>cloud-demo</artifactId>
    <version>1.0</version>
    <modules>
        <module>user-service</module>
        <module>order-service</module>
    </modules>

    <packaging>pom</packaging>

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

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR10</spring-cloud.version>
        <mysql.version>5.1.47</mysql.version>
        <mybatis.version>2.1.1</mybatis.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- springCloud -->
            <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>2.2.5.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- mysql驱动 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <!--mybatis-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
</project>


user-service
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-demo</artifactId>
        <groupId>cn.itcast.demo</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>user-service</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>

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

    </dependencies>

    <build>
        <finalName>app</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
application.yml
server:
  port: 8081
spring:
  application:
    name: user-service
  cloud:
    nacos:
      server-addr: localhost:8848
  datasource:
    url: jdbc:mysql://localhost:3306/cloud-user?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
UserApplication
@MapperScan("cn.itcast.user.mapper")
@SpringBootApplication
public class UserApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }
}
UserController
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 路径: /user/110
     *
     * @param id 用户id
     * @return 用户
     */
    @GetMapping("/{id}")
    public User queryById(@PathVariable("id") Long id) {
        return userService.queryById(id);
    }
}

UserService
@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public User queryById(Long id) {
        return userMapper.findById(id);
    }
}
order-service
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-demo</artifactId>
        <groupId>cn.itcast.demo</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>order-service</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>

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

        <!--feign客户端依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--引入HttpClient依赖-->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>

    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
application.yml
server:
  port: 8080
spring:
  application:
    name: order-service
  cloud:
    nacos:
      server-addr: localhost:8848
  datasource:
    url: jdbc:mysql://localhost:3306/cloud-order?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
UserApplication
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients("cn.itcast.order.feign")
public class OrderApplication {

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

}
OrderService
@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private UserClient userClient;

    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        // 2.用Feign远程调用
        User user = userClient.findById(order.getUserId());
        // 3.封装user到Order
        order.setUser(user);
        // 4.返回
        return order;
    }
}
UserClient
@FeignClient(value = "user-service")
public interface UserClient {

    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

访问nacos

将user-service分别以8081和8082启动,order以8080启动。

效果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.服务分级存储模型

集群介绍

一个服务可以有多个实例,例如我们的user-service,可以有:

  • 127.0.0.1:8081
  • 127.0.0.1:8082
  • 127.0.0.1:8083

假如这些实例分布于全国各地的不同机房,例如:

  • 127.0.0.1:8081,在上海机房
  • 127.0.0.1:8082,在上海机房
  • 127.0.0.1:8083,在杭州机房

Nacos就将同一机房内的实例 划分为一个集群

也就是说,user-service是服务,一个服务可以包含多个集群,如杭州、上海,每个集群下可以有多个实例(按地域划分集群),形成分级模型,如图:

在这里插入图片描述

服务跨集群调用问题

微服务互相访问时,应该尽可能访问同集群实例,因为本地访问速度更快。当本集群内不可用时,才访问其它集群。例如:

在这里插入图片描述
杭州机房内的order-service应该优先访问同机房的user-service。

服务集群属性

Nacos服务分级存储模型

  • 一级是服务,例如userservice
  • 二级是集群,例如杭州或上海
  • 三级是实例,例如杭州机房的某台部署了userservice的服务器

如何设置实例的集群属性

  • 修改application.yml文件,添加spring.cloud.nacos.discovery.cluster-name属性即可

同集群优先的负载均衡

默认的ZoneAvoidanceRule并不能实现根据同集群优先来实现负载均衡。
因此Nacos中提供了一个NacosRule的实现,可以优先从同集群中挑选实例。

NacosRule负载均衡策略

  • 优先选择同集群服务实例列表
  • 本地集群找不到提供者,才去其它集群寻找,并且会报警告
  • 确定了可用实例列表后,再采用随机负载均衡挑选实例

下面通过1个示例来演示

给user-service配置集群

修改user-service的yml配置文件

在前面最基础的示例上,仅修改user-service的yml配置文件,启动3个user-service实例,分别占用8081,8082,8083端口,其中8081,8082的集群名称使用HZ,8083的集群名称使用SH

server:
  port: 8081
spring:
  application:
    name: user-service
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos服务地址
      discovery:
        cluster-name: HZ          # 配置集群名称,也就是机房位置,例如:HZ代指杭州
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_user?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
访问nacos

在这里插入图片描述
点击详情进去查看
在这里插入图片描述

给order-service配置集群

修改order-service的yml配置文件

在前面最基础的示例上,仅修改order-service的yml配置文件

server:
  port: 8080
spring:
  application:
    name: order-service
  cloud:
    nacos:
      server-addr: localhost:8848  # nacos服务地址
      discovery:
        cluster-name: HZ           # 设置当前服务实例所属集群名称
  datasource:
    url: jdbc:mysql://localhost:3306/cloud-order?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
访问nacos

在这里插入图片描述
在这里插入图片描述

测试

现在我们多次调用:http://localhost:8080/order/103,发现:order-service会轮询调用这3个实例。可是,我们知道order-service服务是在HZ这个集群的,它应当要优先选择HZ集群下的user-service服务,当HZ集群下的user-service服务不可用时,再去选择其它集群下的user-service服务实例。

为了解决上面这个问题,我们在order-service中设置负载均衡的IRule为NacosRule(如下配置),这个规则优先会寻找与自己同集群的服务,重启order-service后,多次调用:http://localhost:8080/order/103发现:order-service会去HZ集群中随机选择1个user-service实例,而SH集群的user-service实例没有被选择。此时,把HZ集群下的user-service实例全部关掉,多次调用:http://localhost:8080/order/103发现:刚开始报错几次之后,就选择到了SH集群下的user-service实例,并且此时order-service下会有WARN级别的日志:[nio-8080-exec-3] c.alibaba.cloud.nacos.ribbon.NacosRule : A cross-cluster call occurs,当查看到这个日志时,就知道发生了跨集群调用了。

server:
  port: 8080
spring:
  application:
    name: order-service
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: HZ
  datasource:
    url: jdbc:mysql://localhost:3306/cloud-order?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule  # 负载均衡规则

权重负载均衡

实际部署中会出现这样的场景:

  • 服务器设备性能有差异,部分实例所在机器性能较好,另一些较差,我们希望性能好的机器承担更多的用户请求

  • Nacos提供了权重配置来控制访问频率,权重越大则访问频率越高

实例的权重控制

  • Nacos控制台可以设置实例的权重值,0~1之间
  • 同集群内的多个实例,权重越高被访问的频率越高
  • 权重设置为0则完全不会被访问(可以用作平滑升级:当某个服务需要升级时,先把权重调的很低,先放部分用户过来,当没有问题时,再提高权重)

测试

如下修改8082的权重为0.1,现在我们调用:http://localhost:8080/order/103 20次,发现:18次都在8081上,有2次再8082上,说明权重设置是生效的。

在这里插入图片描述
可以看到8082的权重改为了0.1,而8081的权重仍然为1
在这里插入图片描述

再尝试把8081的权重设置为0,8082的权重恢复为1,发现:8081没有被访问,全都到了8082上。在这里插入图片描述

环境隔离

Nacos提供了namespace来实现环境隔离功能。Nacos中服务存储数据存储最外层都是一个名为namespace的东西,用来做最外层隔离

  • nacos中可以有多个namespace
  • namespace下可以有group、service等(而服务由下分为:服务-集群-实例)
  • 不同namespace之间相互隔离,例如不同namespace的服务互相不可见(不同namespace下的各服务完全隔离,互相之间完全看不见对方)

在这里插入图片描述

Nacos环境隔离

  • 每个namespace都有唯一id
  • 服务设置namespace时要写id而不是名称
  • 不同namespace下的服务互相不可见(如果要让2个服务之间能调用,那么它们必须在同1个namespace下)

测试

最初的默认配置如下:在这里插入图片描述
在这里插入图片描述
创建1个dev的命名空间:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
修改order-service的application.yml,添加namespace(注意是命名空间id),重启order-service,发现:order-service已经从public命名空间下移除掉了,并且注册到了dev命名空间下,此时访问:http://localhost:8080/order/103,就会报错:com.netflix.client.ClientException: Load balancer does not have available server for client: user-service负载均衡已经找不到user-service
服务

server:
  port: 8080
spring:
  application:
    name: order-service
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: HZ
        namespace: 7fe7efeb-e4a4-4cd1-82f4-46d46c6f7bba # 填命名空间ID
  datasource:
    url: jdbc:mysql://localhost:3306/cloud-order?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
user-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule  # 负载均衡规则

在这里插入图片描述
在这里插入图片描述

3. Nacos注册中心原理

nacos注册中心细节分析

服务提供者在启动时,都会把自己的信息提交给注册中心,注册中心就会把服务提供者的信息保存下来。当消费者需要消费时,就会从注册中心拉取服务提供者的信息(或者叫作服务发现),缓存到本地服务列表中,这样当下一次需要获取服务信息时,就不用从注册中心拉取了,而是使用缓存的服务列表信息。

当注册中心的服务列表变化时,就需要消费者定时从注册中心拉取服务信息缓存到本地,其中,eureka就每隔默认30s从注册中心拉取服务信息。当消费者获取到服务后,从提供的服务中根据负载均衡策略挑选服务发起远程调用。
在这里插入图片描述

nacos与eureka区别

nacos的 临时实例&非临时实例

Nacos的服务实例分为两种类型:

  • 临时实例:如果实例宕机超过一定时间,会从服务列表剔除,默认的类型(如果不作任何配置,默认就是临时实例;临时实例每隔一段时间,定时向注册中心发送1次心跳报告健康状态,这一点与eureka相同;超过一定时间未收到心跳,将会从服务列表中剔除)。
  • 非临时实例:如果实例宕机,不会从服务列表剔除,也可以叫永久实例。(非临时实例不会向注册中心发送心跳请求,而是由注册中心主动询问健康状态;nacos主动发请求询问,如果检测不到,也不会清除这个服务,而是会一直等待这个非临时实例好为止)
主动推送变更消息

当服务提供者信息发生变化,而服务消费者由于采用的是定时拉取,未能及时更新本地缓存服务列表,此时发起远程调用会发生问题。eureka采取的是pull定时拉取方案,因此更新的不够及时,服务列表更新效率差,而nacos采取的是pull定时拉取 + 主动推送变更消息,如果服务提供信息发生变化时,会立即将此变更消息推送到消费者。

总结
  • Nacos与eureka的共同点
    • 都支持服务注册和服务拉取
    • 都支持服务提供者心跳方式做健康检测
  • Nacos与Eureka的区别
    • Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式
    • 临时实例心跳不正常会被剔除,非临时实例则不会被剔除
    • Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
    • Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式
测试

修改order-service的application.yml配置文件,将order-service注册为非临时实例

server:
  port: 8080
spring:
  application:
    name: order-service
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: HZ
        namespace: 7fe7efeb-e4a4-4cd1-82f4-46d46c6f7bba # 填命名空间ID
        ephemeral: false  # 是否临时实例
  datasource:
    url: jdbc:mysql://localhost:3306/cloud-order?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
user-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule  # 负载均衡规则

从中可以看到order-service注册为非临时实例了,这与之前的注册为临时实例是不同的在这里插入图片描述在这里插入图片描述

当关闭order-service,发现order-service仍然还在列表中(如果是临时实例,会直接在列表中被移除掉。因此,只能手动移除它。)
在这里插入图片描述
在这里插入图片描述
当order-service重新上线,就恢复了

4. Nacos配置管理

Nacos除了可以做注册中心,同样可以做配置管理来使用。

统一配置管理

当微服务部署的实例越来越多,达到数十、数百时,逐个修改微服务配置就会让人抓狂,而且很容易出错。我们需要一种统一配置管理方案,可以集中管理所有实例的配置。
在这里插入图片描述
Nacos一方面可以将配置集中管理,另一方可以在配置变更时,及时通知微服务,实现配置的热更新
在这里插入图片描述

在nacos中添加配置文件

在Nacos中添加配置信息,点击“+”号:

在这里插入图片描述
然后在弹出的表单中,填写配置信息(注意:项目的核心配置,需要热更新的配置才有放到nacos管理的必要。基本不会变更的一些配置还是保存在微服务本地比较好。):

在这里插入图片描述
在这里插入图片描述

从微服务拉取配置

微服务要拉取nacos中管理的配置,并且与本地的application.yml配置合并,才能完成项目启动。

但如果尚未读取application.yml,又如何得知nacos地址呢?

因此spring cloud引入了一种新的配置文件:bootstrap.yaml文件,会在application.yml之前被读取,流程如下:
在这里插入图片描述

示例

第一步:给user-service 引入Nacos的配置管理客户端依赖:

<?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-demo</artifactId>
        <groupId>cn.itcast.demo</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>user-service</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>

        <!--nacos服务发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!--nacos配置管理依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

    </dependencies>

    <build>
        <finalName>app</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

第二步:添加bootstrap.yaml
然后,在user-service中添加一个bootstrap.yaml文件,内容如下:

spring:
  application:
    name: user-service # 服务名称
  profiles:
    active: dev # 开发环境,这里是dev
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址
      config:
        file-extension: yaml # 文件后缀名

这里会根据spring.cloud.nacos.server-addr获取nacos地址,再根据
${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}作为文件id,来读取配置。本例中,就是去读取user-service-dev.yaml

此时的application.yml配置如下:

server:
  port: 8081
spring:
  cloud:
    nacos:
      discovery:
        cluster-name: HZ # 配置集群名称,也就是机房位置,例如:HZ代指杭州
  datasource:
    url: jdbc:mysql://localhost:3306/cloud-user?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS

第三步:修改UserController,注入nacos配置文件的配置,测试是否生效

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
	
	// ... 省略其它代码
	
	/* 注入nacos配置文件的配置 */
    @Value("${pattern.dataFormat}")
    private String dataFormat;

    @GetMapping("now")
    public String now(){
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dataFormat));
    }
}

第四步:以8081端口,重启user-service服务,发现user-service已成功注册到了nacos,并且是在HZ集群。此时访问:http://localhost:8081/user/now,返回如下
在这里插入图片描述

总结

将配置交给Nacos管理的步骤

  • 在Nacos中添加配置文件
  • 在微服务中引入nacos的config依赖
  • 在微服务中添加bootstrap.yml,配置nacos地址、当前环境、服务名称、文件后缀名。这些决定了程序启动时去nacos读取哪个文件

配置热更新

我们最终的目的,是修改nacos中的配置后,微服务中无需重启即可让配置生效,也就是配置热更新

Nacos中的配置文件变更后,微服务无需重启就可以感知。不过需要通过下面两种配置实现:

方式一:@RefreshScope

在@Value注入的变量所在类上添加注解@RefreshScope
在这里插入图片描述

方式二:@ConfigurationProperties

使用@ConfigurationProperties注解,此时无需使用@RefreshScope注解

在这里插入图片描述

测试

修改UserController,如下:

@Slf4j
@RestController
@RequestMapping("/user")
@RefreshScope // 添加@RefreshScope注解
public class UserController {

	// ...省略其它代码

    @Value("${pattern.dataFormat}")
    private String dataFormat;

    @GetMapping("now")
    public String now(){
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dataFormat));
    }
}

创建UserController2,如下:

@Slf4j
@RestController
@RequestMapping("/user2")
@RefreshScope
public class UserController2 {

    @Autowired
    private PatternProperties properties;

    @GetMapping("now")
    public String now(){
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(properties.getDataFormat()));
    }

}
@Data
@Component
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
    private String dataFormat;
    private String envSharedValue;
    private String name;
}

重启user-service,访问如下:
在这里插入图片描述
此时修改nacos中的配置,如下:
在这里插入图片描述
此时,可以看到user-service日志输出如下:

06-15 16:27:23:837  INFO 15636 --- [-localhost_8848] c.a.n.client.config.impl.ClientWorker    : [fixed-localhost_8848] [polling-resp] config changed. dataId=user-service-dev.yaml, group=DEFAULT_GROUP
06-15 16:27:23:837  INFO 15636 --- [-localhost_8848] c.a.n.client.config.impl.ClientWorker    : get changedGroupKeys:[user-service-dev.yaml+DEFAULT_GROUP]
06-15 16:27:23:840  INFO 15636 --- [-localhost_8848] c.a.n.client.config.impl.ClientWorker    : [fixed-localhost_8848] [data-received] dataId=user-service-dev.yaml, group=DEFAULT_GROUP, tenant=null, md5=a64c8b4c6e466eaa891f821c40ee71c1, content=pattern:
  dataFormat: yyyy-MM-dd, type=yaml
06-15 16:27:23:840  INFO 15636 --- [-localhost_8848] c.a.nacos.client.config.impl.CacheData   : [fixed-localhost_8848] [notify-context] dataId=user-service-dev.yaml, group=DEFAULT_GROUP, md5=a64c8b4c6e466eaa891f821c40ee71c1
06-15 16:27:25:999  WARN 15636 --- [-localhost_8848] c.a.c.n.c.NacosPropertySourceBuilder     : Ignore the empty nacos configuration and get it based on dataId[user-service] & group[DEFAULT_GROUP]
06-15 16:27:26:002  WARN 15636 --- [-localhost_8848] c.a.c.n.c.NacosPropertySourceBuilder     : Ignore the empty nacos configuration and get it based on dataId[user-service.yaml] & group[DEFAULT_GROUP]
06-15 16:27:26:005  INFO 15636 --- [-localhost_8848] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-user-service-dev.yaml,DEFAULT_GROUP'}, BootstrapPropertySource {name='bootstrapProperties-user-service.yaml,DEFAULT_GROUP'}, BootstrapPropertySource {name='bootstrapProperties-user-service,DEFAULT_GROUP'}]
06-15 16:27:26:009  INFO 15636 --- [-localhost_8848] o.s.boot.SpringApplication               : The following profiles are active: dev
06-15 16:27:26:014  INFO 15636 --- [-localhost_8848] o.s.boot.SpringApplication               : Started application in 2.173 seconds (JVM running for 313.295)
06-15 16:27:26:044  INFO 15636 --- [-localhost_8848] o.s.c.e.event.RefreshEventListener       : Refresh keys changed: [pattern.dataFormat]
06-15 16:27:26:044  INFO 15636 --- [-localhost_8848] c.a.nacos.client.config.impl.CacheData   : [fixed-localhost_8848] [notify-ok] dataId=user-service-dev.yaml, group=DEFAULT_GROUP, md5=a64c8b4c6e466eaa891f821c40ee71c1, listener=com.alibaba.cloud.nacos.refresh.NacosContextRefresher$1@22606caa 
06-15 16:27:26:044  INFO 15636 --- [-localhost_8848] c.a.nacos.client.config.impl.CacheData   : [fixed-localhost_8848] [notify-listener] time cost=2204ms in ClientWorker, dataId=user-service-dev.yaml, group=DEFAULT_GROUP, md5=a64c8b4c6e466eaa891f821c40ee71c1, listener=com.alibaba.cloud.nacos.refresh.NacosContextRefresher$1@22606caa 

此时,再次访问如下,发现,在未重启user-service的情况下,对配置的修改已生效
在这里插入图片描述

多环境配置共享

其实微服务启动时,会去nacos读取多个配置文件,例如:

  • [spring.application.name]-[spring.profiles.active].yaml,例如:user-service-dev.yaml

  • [spring.application.name].yaml,例如:user-service.yaml

[spring.application.name].yaml不包含环境,因此会被多个环境共享(也就是user-service.yaml这个配置文件会被所有的spring.application.name为user-service的服务所共享)。

即:无论profile如何变化,[spring.application.name].yaml这个文件一定会加载,因此多环境共享配置可以写入这个文件,如果不同的配置文件的配置了相同的属性,那么优先级是:[服务名]-[环境].yaml >[服务名].yaml > 本地配置

优先级

在这里插入图片描述

微服务默认读取的配置文件:

  • [服务名]-[spring.profile.active].yaml,默认配置
  • [服务名].yaml,多环境共享

不同微服务共享的配置文件:

  • 通过shared-configs指定
  • 通过extension-configs指定

优先级:

  • 环境配置 >服务名.yaml > extension-config > extension-configs > shared-configs > 本地配置

测试一

添加一个环境共享配置

我们在nacos中添加一个userservice.yaml文件:

在这里插入图片描述
此时配置如下:
在这里插入图片描述

在user-service中读取共享配置

在user-service服务中,修改PatternProperties类,读取新添加的属性:

@Data
@Component
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
    private String dataFormat;
	
	// 读取定义在user-service.yaml中的配置
    private String envSharedValue;
    
    private String name;
}

UserController2,如下

@Slf4j
@RestController
@RequestMapping("/user2")
@RefreshScope
public class UserController2 {

    @Autowired
    private PatternProperties properties;

    @GetMapping("props")
    public PatternProperties props(){
        return properties;
    }

}

运行两个UserApplication,使用不同的profile

user-service的配置同:统一配置管理中的示例。在此配置的基础上,作如下修改:

修改UserApplication2这个启动项,改变其profile值为test(等价于修改spring.profile.active的值)
在这里插入图片描述

这样,UserApplication(8081)使用的profile是dev,UserApplication2(8082)使用的profile是test。

启动UserApplication和UserApplication2(启动UserApplication2,此时日志会输出:The following profiles are active: test

访问http://localhost:8081/user2/props,结果:
在这里插入图片描述
访问http://localhost:8082/user2/props,结果:
在这里插入图片描述
可以看出来,不管是dev,还是test环境,都读取到了envSharedValue这个属性的值,而dev还读取到了自己的user-service-dev.yaml中配置的pattern.dataFormat的值。

可以看出,每个服务实例不仅会加载当前所设置的profile配置(user-service-dev.yaml),还会默认加载上不带profile的公共配置(user-service.yaml)

测试二

有的时候,某个服务实例,需要加载自己所需要的配置,这些配置被某些服务实例所共享,但其它服务却是不需要的。此时,可以用到nacos提供的扩展配置

添加一个redis.yml

在这里插入图片描述
此时配置如下:
在这里插入图片描述

修改UserApplication1的bootstrap.yaml

添加 spring.cloud.nacos.config.extension-configs 配置

spring:
  application:
    name: user-service # 服务名称
  profiles:
    active: dev # 开发环境,这里是dev
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址
      config:
        file-extension: yaml # 文件后缀名
        extension-configs:
          - data-id: redis.yml
            group: common
            refresh: true

此时的application.yml配置文件(未作任何修改)

server:
  port: 8081
spring:
  cloud:
    nacos:
      discovery:
        cluster-name: HZ # 配置集群名称,也就是机房位置,例如:HZ代指杭州
  datasource:
    url: jdbc:mysql://localhost:3306/cloud-user?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS

重启UserApplication1,访问测试,发现读取到了redis.yml中的配置
在这里插入图片描述

修改redis.yml,并发布,再次访问测试

在这里插入图片描述
可以看到,redis.port的值 热更新了
在这里插入图片描述

5. Nacos集群

Nacos生产环境下一定要部署为集群状态

集群结构图

官方给出的Nacos集群图
在这里插入图片描述
其中包含3个nacos节点,然后一个负载均衡器代理3个Nacos。这里负载均衡器可以使用nginx。

我们计划的集群结构,Nginx做负载均衡,MySQL集群做数据共享

在这里插入图片描述
三个Nacos节点的地址

节点ipport
nacos1192.168.134.58845
nacos2192.168.134.58846
nacos3192.168.134.58847

搭建集群

搭建集群的基本步骤

  • 搭建数据库,初始化数据库表结构
  • 下载nacos安装包
  • 配置nacos
  • 启动nacos集群
  • nginx反向代理

初始化数据库

Nacos默认数据存储在内嵌数据库Derby中,不属于生产可用的数据库。

官方推荐的最佳实践是使用带有主从模式的高可用数据库集群,这里我们以单点的数据库为例来讲解

首先新建一个数据库,命名为nacos,而后导入下面的SQL:

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info   */
/******************************************/
CREATE TABLE `config_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(255) DEFAULT NULL,
  `content` longtext NOT NULL COMMENT 'content',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
  `app_name` varchar(128) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  `c_desc` varchar(256) DEFAULT NULL,
  `c_use` varchar(64) DEFAULT NULL,
  `effect` varchar(64) DEFAULT NULL,
  `type` varchar(64) DEFAULT NULL,
  `c_schema` text,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_aggr   */
/******************************************/
CREATE TABLE `config_info_aggr` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(255) NOT NULL COMMENT 'group_id',
  `datum_id` varchar(255) NOT NULL COMMENT 'datum_id',
  `content` longtext NOT NULL COMMENT '内容',
  `gmt_modified` datetime NOT NULL COMMENT '修改时间',
  `app_name` varchar(128) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';


/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_beta   */
/******************************************/
CREATE TABLE `config_info_beta` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL COMMENT 'content',
  `beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_tag   */
/******************************************/
CREATE TABLE `config_info_tag` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
  `tag_id` varchar(128) NOT NULL COMMENT 'tag_id',
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL COMMENT 'content',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_tags_relation   */
/******************************************/
CREATE TABLE `config_tags_relation` (
  `id` bigint(20) NOT NULL COMMENT 'id',
  `tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
  `tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
  `nid` bigint(20) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`nid`),
  UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = group_capacity   */
/******************************************/
CREATE TABLE `group_capacity` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',
  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值',
  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = his_config_info   */
/******************************************/
CREATE TABLE `his_config_info` (
  `id` bigint(64) unsigned NOT NULL,
  `nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `data_id` varchar(255) NOT NULL,
  `group_id` varchar(128) NOT NULL,
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL,
  `md5` varchar(32) DEFAULT NULL,
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `src_user` text,
  `src_ip` varchar(50) DEFAULT NULL,
  `op_type` char(10) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`nid`),
  KEY `idx_gmt_create` (`gmt_create`),
  KEY `idx_gmt_modified` (`gmt_modified`),
  KEY `idx_did` (`data_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';


/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = tenant_capacity   */
/******************************************/
CREATE TABLE `tenant_capacity` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',
  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';


CREATE TABLE `tenant_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `kp` varchar(128) NOT NULL COMMENT 'kp',
  `tenant_id` varchar(128) default '' COMMENT 'tenant_id',
  `tenant_name` varchar(128) default '' COMMENT 'tenant_name',
  `tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
  `create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
  `gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
  `gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';

CREATE TABLE `users` (
	`username` varchar(50) NOT NULL PRIMARY KEY,
	`password` varchar(500) NOT NULL,
	`enabled` boolean NOT NULL
);

CREATE TABLE `roles` (
	`username` varchar(50) NOT NULL,
	`role` varchar(50) NOT NULL,
	UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
);

CREATE TABLE `permissions` (
    `role` varchar(50) NOT NULL,
    `resource` varchar(255) NOT NULL,
    `action` varchar(8) NOT NULL,
    UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
);

INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);

INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');

下载nacos

nacos在GitHub上有下载地址: https://github.com/alibaba/nacos/tags,可以选择任意版本下载。

本例中采用1.4.1版本
在这里插入图片描述

配置nacos

将这个包解压到任意非中文目录下,如图:
在这里插入图片描述
目录说明

  • bin:启动脚本
  • conf:配置文件

进入nacos的conf目录,修改配置文件cluster.conf.example,重命名为cluster.conf,然后添加每个nacos节点的ip和端口,内容如下:
在这里插入图片描述
然后,修改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?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=root

启动

将nacos文件夹复制三份,分别命名为: nacos1、nacos2、nacos3
在这里插入图片描述
然后分别修改三个文件夹中的application.properties

nacos1:

server.port=8845

nacos2:

server.port=8846

nacos3:

server.port=8847

然后分别启动三个nacos节点:双击 startup.cmd 以集群模式启动即可
在这里插入图片描述

nginx反向代理

解压nginx-1.18.0.zip压缩包,如下:
在这里插入图片描述
将如下内容,添加到http块中,以实现nginx对nacos集群的负载均衡

	upstream nacos-cluster {
		server 192.168.134.5:8845;
		server 192.168.134.5:8846;
		server 192.168.134.5:8847;
	}
	
	server {
		listen 80;
		server_name 192.168.134.5;
		location /nacos {
			proxy_pass http://nacos-cluster;
		}
	}

此时访问nacos就不用带端口号了:http://192.168.134.5/nacos
在这里插入图片描述
添加user-service-dev.yaml配置文件
在这里插入图片描述

在这里插入图片描述

项目配置

仅修改了user-service的bootstrap.yaml配置文件的spring.cloud.nacos.server-addr配置,其它未动,这里将user-service的重要配置列出来

依赖
<!--nacos服务发现-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<!--nacos配置管理依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
bootstrap.yaml

仅修改了spring.cloud.nacos.server-addr=192.168.134.5:80

spring:
  application:
    name: user-service # 服务名称
  profiles:
    active: dev # 开发环境,这里是dev
  cloud:
    nacos:
      server-addr: 192.168.134.5:80 # nacos集群地址(就是nginx作负载均衡的地址)
      config:
        file-extension: yaml # 文件后缀名
        extension-configs:
          - data-id: redis.yml
            group: common
            refresh: true
application.yml
server:
  port: 8081
spring:
  cloud:
    nacos:
      discovery:
        cluster-name: HZ # 配置集群名称,也就是机房位置,例如:HZ代指杭州
  datasource:
    url: jdbc:mysql://localhost:3306/cloud-user?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
UserApplication
@MapperScan("cn.itcast.user.mapper")
@SpringBootApplication
public class UserApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }
}

UserController2

此处使用@RefreshScope的方式来热更新

@Slf4j
@RestController
@RequestMapping("/user2")
@RefreshScope 
public class UserController2 {

    @Autowired
    private PatternProperties properties;

    @GetMapping("props")
    public PatternProperties props(){
        return properties;
    }
}

测试

访问http://localhost:8081/user2/props
在这里插入图片描述
在这里插入图片描述
如上修改配置后,再次访问http://localhost:8081/user2/props
在这里插入图片描述
说明集群搭建成功

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/718949.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Jupyter Notebook 中 %run 魔法命令

目录 基本用法运行 Python 脚本运行 Jupyter Notebook 的其他单元格传递命令行参数 示例运行 Python 脚本示例运行其他 Jupyter Notebook 示例传递命令行参数示例 注意事项与 import 命令的区别%runimport 结论 %run 是 Jupyter Notebook 中的一个强大工具&#xff0c;它允许你…

【机器学习】第4章 决策树算法(重点)

一、概念 1.原理看图&#xff0c;非常简单&#xff1a; &#xff08;1&#xff09;蓝的是节点&#xff0c;白的是分支&#xff08;条件&#xff0c;或者说是特征&#xff0c;属性&#xff0c;也可以直接写线上&#xff0c;看题目有没有要求&#xff09;&#xff0c; &#xff0…

MySQL----InooDB行级锁、间隙锁

行级锁 行锁&#xff0c;也称为记录锁&#xff0c;顾名思义就是在记录上加的锁。 注意&#xff1a; InnoDB行锁是通过给索引上的索引项加锁来实现的&#xff0c;而不是给表的行记录加锁实现的&#xff0c;这就意味着只有通过索引条件检索数据&#xff0c;InnoDB才使用行级锁…

【开发工具】git服务器端安装部署+客户端配置

自己安装一个轻量级的git服务端&#xff0c;仅仅作为代码维护&#xff0c;尤其适合个人代码管理。毕竟代码的版本管理是很有必要的。 这里把git服务端部署在centos系统里&#xff0c;部署完成后可以通过命令行推拉代码&#xff0c;进行版本和用户管理。 一、服务端安装配置 …

【Kubernetes】k8s--安全机制

机制说明 Kubernetes 作为一个分布式集群的管理工具&#xff0c;保证集群的安全性是其一个重要的任务。API Server 是集群内部各个组件通信的中介&#xff0c; 也是外部控制的入口。所以 Kubernetes 的安全机制基本就是围绕保护 API Server 来设计的。 比如 kubectl 如果想向 …

新版FMEA培训内容中关于团队协作的部分可以怎么展开?

团队协作&#xff0c;作为新版FMEA的核心要素之一&#xff0c;其重要性不言而喻。在FMEA的分析过程中&#xff0c;团队成员的密切合作与沟通是确保分析全面性和准确性的关键。通过团队协作&#xff0c;不同领域的专家能够共同参与到潜在故障模式的识别、评估与预防中来&#xf…

解决ubuntu22.04共享文件夹问题

刚开机发现ubuntu里面的共享文件夹访问不了了 ubuntuwxy:/mnt/hgfs$ ls找了几篇博客&#xff0c;设置如下指令即可&#xff0c;记得退出当前目录重新进入刷新一下 sudo vmhgfs-fuse .host:/ /mnt/hgfs/ -o allow_other -o uid1000 仅供参考

针对indexedDB的简易封装

连接数据库 我们首先创建一个DBManager类&#xff0c;通过这个类new出来的对象管理一个数据库 具体关于indexedDB的相关内容可以看我的这篇博客 indexedDB class DBManager{}我们首先需要打开数据库&#xff0c;打开数据库需要数据库名和该数据库的版本 constructor(dbName,…

[WTL/Win32]_[中级]_[MVP架构在实际项目中应用的地方]

场景 在开发Windows和macOS的界面软件时&#xff0c;Windows用的是WTL/Win32技术&#xff0c;而macOS用的是Cocoa技术。而两种技术的本地语言一个主打是C,另一个却是Object-c。界面软件的源码随着项目功能增多而增多&#xff0c;这就会给同步Windows和macOS的功能造成很大负担…

Aigtek高压放大器在柔性爬行机器人驱动性能研究中的应用

实验名称&#xff1a;柔性爬行机器人的材料测试 研究方向&#xff1a;介电弹性体的最小能量结构是一种利用DE材料的电致变形与柔性框架形变相结合设计的新型柔性驱动器&#xff0c;所谓最小能量是指驱动器在平衡状态时整个系统的能量最小&#xff0c;当系统在外界的电压刺激下就…

开发一个python工具,pdf转图片,并且截成单个图片,然后修整没用的白边

今天推荐一键款本人开发的pdf转单张图片并截取没有用的白边工具 一、开发背景&#xff1a; 业务需要将一个pdf文件展示在前端显示&#xff0c;但是基于各种原因&#xff0c;放弃了h5使用插件展示 原因有多个&#xff0c;文件资源太大加载太慢、pdf展示兼容性问题、pdf展示效果…

应急便携式气象观测站

TH-BQX5自然灾害&#xff0c;如台风、暴雨、洪涝、干旱等&#xff0c;给人们的生命财产安全带来了巨大威胁。在应对这些灾害时&#xff0c;准确的气象观测数据是制定有效应对策略的基础。近年来&#xff0c;应急便携式气象观测站在自然灾害的监测和预警中发挥了越来越重要的作用…

在 Blazor 中在子组件和父组件之间共享数据

介绍 可以在Blazor 中创建一个子组件并在另一个组件中重用它。我们将非常轻松地在这些组件之间共享数据。我们将创建一个自定义文本框作为子组件。此自定义文本框将显示文本框中的当前字符数&#xff0c;并在需要时限制字符总数。我将逐步解释所有操作。 在 Visual Studio 中…

购物App需要进行软件测试吗?包括哪些测试内容?

随着移动互联网的飞速发展&#xff0c;购物App在人们的日常生活中扮演着越来越重要的角色。然而&#xff0c;由于App开发的复杂性和用户对于购物体验的高要求&#xff0c;保证App的质量成为了一项重要的任务。而软件测试作为确保App质量的关键环节&#xff0c;也日益受到重视。…

文件操作(1)(C语言版)

前言&#xff1a; 为什么要学习文件操作&#xff1a; 1、如果大家写过一些代码&#xff0c;当运行结束的时候&#xff0c;这些运行结果将不复存在&#xff0c;除非&#xff0c;再次运行时这些结果才能展现在屏幕上面&#xff0c;就比如之前写过的通讯录。 现实中的通讯录可以保…

智游剪辑手机版发布!

耗时一个多月&#xff0c;手机版终于开发的差不多了&#xff0c;下面带大家一起来看下效果咋样吧&#xff01; 功能介绍 打开应用就可以直接看到我们的所有功能了&#xff0c;支持分类查看和关键词搜索功能&#xff0c;每个功能都可以查看帮助教程和收藏&#xff0c;点击即可进…

Day40

Day40 监听器 概念&#xff1a; 监听器用于监听web应用中某些对象信息的创建、销毁、增加&#xff0c;修改&#xff0c;删除等动作的 发生&#xff0c;然后作出相应的响应处理。当范围对象的状态发生变化的时候&#xff0c;服务器自动调用 监听器对象中的方法。 常用于统计在线…

AWS——01篇(AWS入门 以及 AWS之EC2实例及简单实用)AWS

AWS——01篇&#xff08;AWS入门 以及 AWS之EC2实例及简单实用&#xff09; 1. 前言 2. 创建AWS账户 3. EC2 3.1 启动 EC2 新实例 3.1.1 入口 3.1.2 设置名称 选择服务 3.1.3 创建密钥对 3.1.4 网络设置——安全组 3.1.4.1 初始设置 3.1.4.2 添加安全组规则&#xff08;开放新…

0X0-基于Sklearn的机器学习入门:聚类(上)

本节及后续章节将介绍深度学习中的几种聚类算法&#xff0c;所选方法都在Sklearn库中聚类模块有具体实现。本节为上篇&#xff0c;将介绍几种相对基础的聚类算法&#xff0c;包括K-均值算法和均值漂移算法。 目录 X.1 聚类概述 X.1.1 聚类的种类 X.1.2 Sklearn聚类子模块 …

【JVM结构、JVM参数、JVM垃圾回收】

JVM&#xff1a;Java Virtual Machine java虚拟机 虚拟机&#xff1a;使用软件技术模拟出与具有完整硬件系统功能、运行在一个隔离环境中的计算机系统。 JVM官方文档&#xff1a;https://docs.oracle.com/javase/specs/jvms/se8/html/index.html java 一些命令 javac 将文件编…