一文读懂新版Nacos的使用方式

news2024/9/23 13:20:15

文章目录

  • 什么是 Nacos
    • Nacos 架构
    • Nacos 的本地启动
  • 构建提供者 provider-nacos-8081
    • 搭建环境
    • 编写配置文件 application.yaml
    • 构建数据库
    • 编写业务
      • 实体类
      • 控制器类
      • 逻辑层与数据层接口
    • 模块结构
  • 构建消费者 consumer-nacos-8080
    • 搭建环境
    • 编写 yaml 文件配置
    • 编写业务
      • 编写配置类
      • 编写 Controller
  • 启动服务进行进行测试
    • 启动 provider 和 consumer 进行测试
    • 将 provider 和 consumer 注入 nacos
  • 获取服务列表
  • nacos 注册表缓存
  • 临时实例和持久实例
    • 如何设置
    • 区别
    • 将 provider 设置成持久实例
  • Nacos 的 CAP 模式
  • 数据持久化到外部 MySQL
  • Nacos 集群本地部署
  • Nacos 数据模型
  • 服务隔离
  • Nacos Config 服务配置中心
    • 获取远程配置
    • 在 nacos config 中进行配置
  • 常见配置中心工作原理
    • Spring Cloud Config
    • Apollo
    • Nacos Config
    • Zookeeper
    • 一致性问题
  • provider 由配置中心读取配置文件
  • 共享配置
  • 配置动态更新
  • 多环境选择
  • 配置隔离

  • 所有提供者将自己提供服务的名称以及自己的主机详情(IP,端口,版本等)写入到作为服务注册中心的主机中的一个列表中,而该表称为服务注册表
  • 所有消费者需要调用微服务时,会从注册中心首先将服务注册表下载到本地,然后根据消费者本地设置好的负载均衡策略算法选择一个服务提供者进行调用,这个过程称为服务发现
  • 可以作为 SpringCloud 服务注册中心的服务器有很多,Zookeeper,Eureka,Consul 等,Spring Cloud Alibaba 中使用的注册中心是 Nacos
  • 服务在启动后,当发生调用时会自动从 Nacos 注册中心下载并缓存注册表到本地。所以,即使 Nacos 发生宕机,会发现消费者仍然是可以调用到提供者的。只不过此时已经不能再有服务进行注册了,服务中缓存的注册列表信息无法更新。"


什么是 Nacos

官网

image.png

  • 云原生应用简单来说就是 SaaS,跑在 IaaS,PaaS 上的 SaaS
  • 开发应用时只需要考虑如何充分利用云端的弹性,容错能力分布式能力,有异于本地化开发
  • 简而言之云原生=DevOps+CI/CD+容器化

Nacos 架构

image.png

  • Java 语言本身集成 Nacos 使用的是 Nacos Client
  • Nacos 为其它语言的集成提供了 Nacos Sidecar(多语言异构模块)
    • 为其它语言使用 SpringCloud Alibaba 提供可能
  • NameService
    • 支持dns,vip(虚拟ip),address-server
  • 通过客户端调用 OpenApi支持,http,dns,udp,tls就能使用 ConfigService 和 NamingService(服务发现) 两大核心功能
  • Nacos 集群遵循数据一致性协议 Consistency Protocol
    • priv-raft,sync renew,rdbms based
    • ConfigService 使用关系型数据库 rdbms based
    • NamingService 使用 priv-raft 算法

Nacos 的本地启动

  • 下载 nacos2.2.1,解压进入 conf 文件夹
  • 进入 application.properties 文件

image.png

  • 鉴权配置帮助文档
nacos.core.auth.enabled=true #开启鉴权
nacos.core.auth.server.identity.key=nacosIdKey			#设key值
nacos.core.auth.server.identity.value=nacosIdValue 	#设value值
### The default token (Base64 String):
nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
  • 进入 nacos,bin 目录下执行 startup.cmd -m standalone指定单机启动,默认是集群启动

image.png

  • 通过启动日志输出的后台地址进入 nacos 管理后台,默认账号密码均为 nacos

image.png
image.png

  • 进入后台初始页面配置列表默认都是空的此处由于小李在之前进行过配置,作为配置中心进行的配置会持久化存储到 database 中

image.png

  • 与配置中心不同,作为注册中心,nacos 中注册的服务默认为临时实例,不会进行持久化存储

构建提供者 provider-nacos-8081

搭建环境

  • 创建一个父工程,利用 maven 依赖的传递性,在父工程的 pom 文件中指定 springboot 父工程版本以及 springcloud,springcloudalibaba 版本

image.png

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.0.7</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <groupId>com.cheese</groupId>
  <artifactId>springcloudalibaba</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>pom</packaging>
  <name>springcloudalibaba</name>
  <description>springcloudalibaba</description>
  <modules>
    <module>01-provider-nacos-8081</module>
    <module>02-consumer-nacos-8080</module>
    <module>03-provider-config-8081</module>
    <module>04-consumer-openfegin-8080</module>
  </modules>

  <properties>
    <java.version>17</java.version>
    <spring-cloud.version>2022.0.0</spring-cloud.version>
    <spring-cloud-alibaba.version>2022.0.0.0-RC2</spring-cloud-alibaba.version>
  </properties>
  <!--管理子工程的springcloudalibaba版本-->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>${spring-cloud.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>${spring-cloud-alibaba.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>

  </dependencies>

</project>

  • 在 provider-nacos-8081 和 consumer-nacos-8080 中只需要指定父工程的 gav 信息即可自动获取父工程的依赖,剩下的只需要引入自身所需要的依赖即可,另外新引入的版本也在父工程的 spring-boot-parent 中进行默认配置,子工程中引入的依赖可默认继承版本配置,也可自定义依赖版本
<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>
  <!--指定父工程gav-->
    <parent>
        <groupId>com.cheese</groupId>
        <artifactId>springcloudalibaba</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>01-provider-nacos-8081</artifactId>
    <packaging>jar</packaging>

    <name>01-provider-nacos-8081</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
      <!--外部依赖需要指定version-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.23</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>
</project>

编写配置文件 application.yaml

  • 指定端口号
server:
  port: 8081
  • 配置微服务名称
spring:
  #微服务名称
  application:
    name: depart-provider
  • 配置 spring-data-jpa
spring:
  jpa:
    generate-ddl: true #指定spring容器启动时创建表,默认为false
    show-sql: true #sql是否在控制台显示sql语句,默认为fasle
    hibernate:
      ddl-auto: none #设置应用重启时不更新表

构建数据库

-- auto-generated definition
create schema alibaba2024 collate utf8mb4_0900_ai_ci;
use alibaba2024;
-- auto-generated definition
create table depart_entity
(
    id   int          not null
        primary key,
    name varchar(255) null
);

编写业务

实体类

@Data
@Entity
@JsonIgnoreProperties({"hibernateLazyInitializer","handler","fieldHandler"})
/**
 * JPA查询对象,默认延迟加载,忽略延迟加载
 */
public class DepartEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)//自增ID
    public Integer id;
    public String name;
}

控制器类

@RequestMapping("/provider/depart")
@RestController
public class DepartController {
    @Autowired
    private DepartService departService;
    /**
     * 一般生产环境中会采用同一个接口名称,CRUD通请求方式进行区分
     * @param depart
     * @return
     */
    //新增
    @PostMapping("/save")
    public Boolean addDepart(@RequestBody DepartEntity depart) {
        return departService.addDepart(depart);
    }
    //删除
    @DeleteMapping("/del/{id}")
    public Boolean deleteDepart(@PathVariable("id") Integer id) {
        return departService.deleteDepartById(id);
    }

    //修改
    @PutMapping("/update")
    public Boolean updateDepart(@RequestBody DepartEntity depart) {
        return departService.updateDepart(depart);
    }

    //获取
    @GetMapping("/get/{id}")
    public DepartEntity getDepart(@PathVariable("id") Integer id) {
        return departService.getDepartById(id);
    }

    //列表
    @GetMapping("/list")
    public List<DepartEntity> getDepartList() {
        return departService.getAllDepart();
    }

}

逻辑层与数据层接口

  • controller 调取 service 接口
public interface DepartService {
    //insert
    boolean addDepart(DepartEntity depart);
    //update
    boolean updateDepart(DepartEntity depart);
    //delete
    boolean deleteDepartById(Integer id);
    //get
    DepartEntity getDepartById(Integer id);
    //Query
    List<DepartEntity> getAllDepart();
}
  • service 调取 repostitory
@Service
public class DepartServiceImpl implements DepartService {

    @Resource
    private DepartRepository departRepository;


    @Override
    public boolean addDepart(DepartEntity depart) {
        return departRepository.save(depart) != null;
    }

    @Override
    public boolean updateDepart(DepartEntity depart) {
        return addDepart(depart);//JPA底层使用了saveOrUpdate方法区别在于传入的对象ID属性是否null
    }

    @Override
    public boolean deleteDepartById(Integer id) {
        if (departRepository.existsById(id)) {
            departRepository.deleteById(id);
            return true;
        }
        return false;
    }

    @Override
    public DepartEntity getDepartById(Integer id) {
        if (departRepository.existsById(id)) {
            return departRepository.getReferenceById(id);
        }
        DepartEntity depart = new DepartEntity();
        depart.setName("not exist this depart");
        return depart;
    }

    @Override
    public List<DepartEntity> getAllDepart() {
        return departRepository.findAll();
    }
}
  • repostitory 接口调用了 spring-data-jpa 中的底层方法完成数据的读写操作
public interface DepartRepository extends JpaRepository<DepartEntity, Integer> {
}

模块结构

image.png

构建消费者 consumer-nacos-8080

搭建环境

  • 外除去父工程依赖于 provider-nacos-8081一致外 consumer 作为消费者所需要的环境依赖和功能只会更加简单,因此此处不做展开

编写 yaml 文件配置

# 端口号
server:
  port: 8080
spring:
  #微服务名称
  application:
    name: depart-consumer

编写业务

  • 实体类与 provicer-nacos-8081 保持一致即可,消费者不需要 service 和 repostitory
  • 采用 spring 自带的 RestTemplate 进行远程访问

编写配置类

@Configuration
public class DepartConfig {
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

编写 Controller

@RestController
@RequestMapping("/consumer/depart")
public class DeportController {
    @Resource
    private RestTemplate restTemplate;
    //直连方式
    public static final String SERVICE_PROVIDER = "http://localhost:8081/provider/depart";
   
    //新增
    @PostMapping("/")
    public Boolean addDepart(@RequestBody DepartEntity depart) {
        return restTemplate.postForObject(SERVICE_PROVIDER + "/save", depart, Boolean.class);
    }

    //修改
    @PutMapping("/")
    public void modifyDepart(@RequestBody DepartEntity depart) {
        restTemplate.put(SERVICE_PROVIDER + "/update", depart);
    }

    //删除
    @DeleteMapping("/{id}")
    public void deleteDepart(@PathVariable Integer id) {
        restTemplate.delete(SERVICE_PROVIDER + "/del/" + id);
    }
    //查询
    @GetMapping("/{id}")
    public DepartEntity getDepart(@PathVariable Integer id) {
        return restTemplate.getForObject(SERVICE_PROVIDER + "/get/" + id, DepartEntity.class);
    }
    //列表
    @GetMapping("/list")
    public List<DepartEntity> getDepartList() {
       return restTemplate.getForObject(SERVICE_PROVIDER + "/list", List.class);
    }
}

启动服务进行进行测试

启动 provider 和 consumer 进行测试

image.png

  • 测试 provider
    • 新增人资部,财务部

image.png

  • 查询列表

image.png

  • 查询财务部

image.png

  • 修改为研发部

image.png
image.png

  • 删除研发部

image.png
image.png

  • 测试 consumer 类似上述方式进行,此处仅测试一次
    • 获取人资部

image.png

将 provider 和 consumer 注入 nacos

  • 在 provider-nacos-8081 ,consumer-nacos-8080的 yaml 文件中新增如下配置
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #nacos注册中心地址
        username: nacos
        password: nacos
  • 将 consumer 中的 DepartConterller 就行如下修改
    //直连方式
    //public static final String SERVICE_PROVIDER = "http://localhost:8081/provider/depart";
    //微服务调用方式
    public static final String SERVICE_PROVIDER = "http://depart-provider/provider/depart";
  • 依次启动 nacos,provider,consumer,进入 nacos 管理后台

image.png

注意:在 nacos2.2.0.1 版本以后摈弃了 ribbon 客户端负载均衡器,使用了 springcloud 社区的 loadbalancer,consumer 中需要新增如下依赖

        <!--nacos2.2.0.1往后版本的客户端负载均衡依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
  • DepartConfig 新增注解
@Configuration
public class DepartConfig {
    @Bean
    //负载均很方式调用,Netflix组件中的负载均衡在nacos中不再使用,
    //nacos使用新的依赖spring-cloud-starter-loadbalancer实现客户端负载均衡
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
  • 如不进行上述配置 consumer 将找不到名称为depart-provider的微服务

获取服务列表

  • 在 provider-nacos-8081 中的 DepartController 中新增以下接口和配置
@RequestMapping("/provider/depart")
@RestController
public class DepartController {
    .....
    @Autowired
    private DiscoveryClient discoveryClient; //服务发现客户端

    @GetMapping("/discovery")
    public List<String> discoveryHandle() {
        List<String> services = discoveryClient.getServices();
        services.forEach(v1->{
            //获取微服务名称的所有微服务实例
            discoveryClient.getInstances(v1).forEach(v2->{
                HashMap<String, Object> map = new HashMap<>();
                map.put("serviceName", v1);
                map.put("serviceId", v2.getServiceId());
                map.put("serviceHost", v2.getHost());
                map.put("servicePort", v2.getPort());
                map.put("uri", v2.getUri());
                System.out.println("map = " + map);
            });
        });
        return services; //返回注册中心中所有活跃的微服务名称列表
    }

    .......
}
  • 获取当前实例

image.png

  • 查看控制台输出信息

image.png

nacos 注册表缓存

  • nacos 服务器挂了,客户端依旧可以使用本地缓存的注册表找到 provider,只是无法进行注册表的更新

image.png

  • consumer 测试

image.png

  • discovery 找不到服务列表了

image.png

  • 注册表只在发生调用时进行下载,若 nacos 启动,服务也正常启动,在此之后 nacos 直接挂了,则 consumer 没有下载注册表到本地,无法找到 provider

image.png
image.png

  • nacos 挂了,consumer 又没有存在本地注册表时,检索微服务名称时就会找不到 provider,根据微服务名称获取微服务就会调取失败
  • discovery 不存在检索微服务名称的问题,因此可以正常访问,不过,只能获取空列表

临时实例和持久实例

如何设置

  • Nacos 中的实例分为临时实例与持久实例。
    • 在服务注册时有一个属性 ephemeral 用于描述当前实例在注册时是否以临时实例出现。
    • 为 true 则为临时实例,默认值;为false 则为持久实例。

image.png

区别

  • 临时实例与持久实例的实例存储的位置与健康检测机制是不同的。
  • 临时实例
    • 默认情况。
    • 服务实例仅会注册在Nacos 内存,不会持久化到Nacos磁盘。
    • 其健康检测机制为 Client 模式,即 Client 主动向 Server 上报其健康状态。默认心跳间隔为5 秒。在 15 秒内 Server 未收到 client 心跳,则会将其标记为“不健康”状态;在 30 秒内若收到了 client 心跳,则重新恢复“健康”状态,否则该实例将从 Server 端内存清除。
  • 持久实例
    • 服务实例不仅会注册到Nacos内存,同时也会被持久化到 Nacos 磁盘。
    • 其健康检测机制为 Server 模式,即 Server 会主动去检测 client 的健康状态,默认每 20 秒检测一次。健康检测失败后服务实例会被标记为“不健康”状态,但不会被清除,因为其是持久化在磁盘的。"

将 provider 设置成持久实例

  • 默认注册的服务均为临时实例,开发中大多数场景下也均为临时实例

image.png

  • 已经注册过的临时实例服务,不能再次注册为持久实例
spring:
  cloud:
      nacos:
        discovery:
          ephemeral: false #设置是否临时节点,默认为true,为临时节点,false,设置不为临时节点,即为持久实例,已注册的临时实例不可修改为持久实例

image.png
image.png

  • 注销持久实例
curl -d 'serviceName=depart-provider' \
  -d 'ip=192.168.1.102' \
  -d 'port=8081' \
  -d 'ephemeral=false' \
  -d 'username=nacos' \
  -d 'password=nacos' \
  -X DELETE 'http://127.0.0.1:8848/nacos/v2/ns/instance'

image.png

Nacos 的 CAP 模式

默认情况下,Nacos Discovery集群的数据一致性采用的是 AP 模式。但其也支持 CP 模式,需要进行转换。若要转换为CP 的,可以提交如下 PUT 请求,完成 AP 到 CP 的转换。

  • http://localhost:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP

数据持久化到外部 MySQL

  • 官方文档

image.png

  • 找到 mysql-schema.sql 文件
    • nacos-server-2.2.1\nacos\conf路径下

image.png

  • 创建 nacos_config 数据库
create database nacos_config
  • 运行 mysql-schema.sql 文件

image.png
image.png

  • 修改配置文件
#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
### Deprecated configuration property, it is recommended to use `spring.sql.init.platform` replaced.
spring.datasource.platform=mysql
spring.sql.init.platform=mysql

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

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

image.png

  • 在 mysql 新增一个角色

image.png

  • 使用新增的角色进行登录

image.png

Nacos 集群本地部署

  • 创建集群配置文件 cluster.conf
#端口号不可连续避免系统端口被占用
192.168.1.102:8849
192.168.1.102:8851
192.168.1.102:8853
  • 创建集群,修改端口号

image.png

  • 双击 startup.cmd默认集群启动

image.png

  • provider 注册 nacos 集群
spring:
  cloud:
    nacos:
      discovery:
        #server-addr: localhost:8848 #nacos注册中心地址
        #集群注册
        server-addr: localhost:8849,localhost:8851,localhost:8853 #nacos注册中心地址
        username: dev
        password: dev01

image.png

  • 官方集群部署架构图

无论采用何种部署方式,推荐用户把Nacos集群中所有服务节点放到一个vip下面,然后挂到一个域名下面。
<http://ip1:port/openAPI> 直连ip模式,机器挂则需要修改ip才可以使用。
<http://SLB:port/openAPI> 挂载SLB模式(内网SLB,不可暴露到公网,以免带来安全风险),直连SLB即可,下面挂server真实ip,可读性不好。
<http://nacos.com:port/openAPI> 域名 + SLB模式(内网SLB,不可暴露到公网,以免带来安全风险),可读性好,而且换ip方便,推荐模式

image.png

在使用VIP时,需要开放Nacos服务的主端口(默认8848)以及gRPC端口(默认9848)、同时如果对Nacos的主端口有所修改的话,需要对vip中的端口映射作出配置,具体端口的映射方式参考部署手册概览-Nacos部署架构

Nacos 数据模型

Nacos 中的服务是由三元组唯一确定的:namespace、group 与服务名称 service。namespace 与 group 的作用是相同的,用于划分不同的区域范围,隔离服务。不同的是,namespace 的范围更大,不同的 namespace 中可以包含相同的group。不同的 group 中可以包含相同的 service。namespace 的默认值为 public,group 的默认值为 DEFAULT GROUP。。它们之间的关系就如官方给出的下图所示。
image.png

  • Nacos 数据模型 Key 由三元组唯一确定,Namespace默认是空串,”公共命名空间(public),分组默认是DEFAULT GROUP.

服务隔离

启动三个 provider-nacos-8081 实例,提供相同的服务,不同的 namespace,group,和 port

命名空间分组名称端口号
publicDEFAULT_GROUP8081
publicMY_GROUP8082
ns_testMY_GROUP8083
  • 在 DepartServiceImpl 中新增端口号
@Service
public class DepartServiceImpl implements DepartService {

    @Resource
    private DepartRepository departRepository;
    //获取端口号
    @Value("${server.port}")
    private Integer port;


    @Override
    public DepartEntity getDepartById(Integer id) {
        if (departRepository.existsById(id)) {
            return departRepository.getReferenceById(id);
        }
        DepartEntity depart = new DepartEntity();
        depart.setName("not exist this depart port: "+ port);
        return depart;
    }
}
  • consumer 调用时输出 port
  • 8081 默认值配置启动
  • 8082 更改如下配

image.png

  • 8083 做如下配置

image.png

  • 启动服务

image.png

  • consumer 中不做任何 namespace,group 配置

image.png

  • consumer 新增 group 配置

image.png
image.png

  • consumer 放开上述 namespace 注释

image.png

Nacos Config 服务配置中心

集群中每一台主机的配置文件都是相同的,对配置文件的更新维护就成为了一个棘手的问题。此时就出现了配置中心,将集群中每个节点的配置文件交由配置中心统一管理。相关产品很多,例如,Spring Cloud config、Zookeeper、Apollo、Disconf等。但 Spring Cloud Alibaba官方推荐使用 Nacos 作为微服务的配置中心。”

获取远程配置

  • 这里实现的需求是,应用的配置文件不在本地,而由Nacosconfig 进行管理。

在 nacos config 中进行配置

image.png
image.png

常见配置中心工作原理

Spring Cloud Config

17370752136d4f9351ba02adfcfd4f9.png

其存在三大问题:

  • 无法自动感知
  • 更新存在羊群效应
  • 系统架构过于复杂

Apollo

dd5590bd71f4331dfa4f8018e4e5d8c.png

其 Config client 可以自动感知配置文件的更新。但也存在两个不足:

  • 系统架构复杂。
  • 配置文件支持类型较少,其只支持xml、text、properties,不支持json、yml。

Nacos Config

39707516df2de19a2080aaa8401b0f7.png

  • Config client 通知自动感知配置中心中相应配置文件的更新。
  • 架构简单。
  • 支持的配置文件类型较多(支持 JSON 与 YML).

Zookeeper

dafea909db305050c1d37483d93b38b.png

  • Zookeeper 作为配置中心,其工作原理与前面的三种都不同。其没有第三方服务器去存储配置数据,而是将配置数据存放在自己的 Znode 中了。”
  • 当配置中心中的配置数据发生了变更,Configclient 也是可以自动感知到的(Watcher 监听机制)。

一致性问题

  • 配置中心中的配置数据一般都是持久化在第三方服务器的,例如 DBMS、Git 远程库等。
  • 由于这些配置中心 Server 中根本就不存放数据,所以它们的集群中就不存在数据一致性问题。
  • 但像 Zookeeper,其作为配置中心,配置数据是存放在自己本地的。
  • 所以该集群中的节点是存在数据一致性问题的。
  • Zookeeper 集群对于数据一致性采用的是 CP 模式。。
  • 作为注册中心,这些 Server 集群间是存在数据一致性问题的,它们采用的模式是不同的。Zookeeper(CP)、Eureka(AP)、Consul(AP)、Nacos(默认 AP,也支持 CP)。”

provider 由配置中心读取配置文件

  • nacos 新建配置项
  • 将本地配置放置到 nacos 中
  • 在 pom 文件中新增依赖
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
  • 新版中由于 springcloud2021 以后不在扫描 bootstrap.yaml 文件,新版 nacos 本地配置文件任然为 application.yaml
  • 本地的现有配置如下
spring:
  #微服务名称
  application:
    name: depart-provider
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        username: nacos
        password: nacos

  • 新版 nacos 需要指定配置文件拓展名
spring:
  cloud:
    nacos:
      config:
        file-extension: yaml #读取的配置文件类型

image.png

  • 新版本需要新增如下配置
spring:
  # 新版新增配置
  config:
    import:
      - optional:nacos:${spring.application.name}.${spring.cloud.nacos.config.file-extension}

共享配置

spring:
  cloud:
    nacos:
      config:
        #实现共享配置,前置条件,同一个namespace下的同一个group的不同服务共享
       shared-configs[0]:
         data-id: shareconfig.yaml
         refresh: true
       shared-configs[1]:
         data-id: shareconfig2.yaml
         refresh: true
        #实现拓展配置,不同namespace,不同group均可共享
       extension-configs[0]:
         data-id: extensionconfig.yaml
         refresh: true
       extension-configs[1]:
         data-id: extensionconfig2.yaml
         refresh: true
        # 配置加载顺序: 共享配置=>扩展配置=>当前配置
        # 配置优先级: 后加载的会覆盖先加载的=> 当前配置>扩展配置>共享配置
  • 当前服务的配置可以存在于三个地方
    • 远程配置文件(nacos 配置中心)

image.png

  • 快照配置文件

image.png

  • 本地配置文件(主动写入配置)

image.png

这三个同名文件也存在加载顺序问题,它们的加载顺序为:本地配置文件、远程配置文件、快照配置文件。只要系统加载到了配置文件,那么后面的就不再加载。

配置动态更新

  • nacos 配置中心新增部门配置

image.png

  • 修改 provider-config-8081 中的 DepartServiceImpl
@Service
@RefreshScope //实现动态刷新
public class DepartServiceImpl implements DepartService {

    @Resource
    private DepartRepository departRepository;
    //获取端口号
    @Value("${server.port}")
    private Integer port;

    //获取部门名称通过远程配置中心
    @Value("${depart.name}")
    private String departName;

  
    @Override
    public DepartEntity getDepartById(Integer id) {
        if (departRepository.existsById(id)) {
            return departRepository.getReferenceById(id);
        }
        DepartEntity depart = new DepartEntity();
        depart.setName("not exist this depart"+departName+" port: "+ port);
        return depart;
    }
}
  • 重新启动 provider 和 consumer

image.png

  • 修改为财务部,进行发布

image.png
image.png

多环境选择

在开发应用时,通常同一套程序会被运行在多个不同的环境,例如,开发、测试、生产环境等。每个环境的数据库地址、服务器端口号等配置都会不同。若在不同环境下运行时将配置文件修改为不同内容,那么,这种做法不仅非常繁琐,而且很容易发生错误。此时就需要定义出不同的配置信息,在不同的环境中选择不同的配置。

  • 在 nacos config 中对 depart-provider.yaml进行克隆

image.png

  • 本地 nacos-config-8081 中的 application.yaml 文件中做以下配置
spring:
  profiles:
    active: dev
  # 新版新增配置
  config:
    import:
      - optional:nacos:${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

image.png
image.png

配置隔离

启动三个 provider-config-8081 实例,提供相同的服务,不同的 namespace,group,和 port

命名空间分组名称端口号
publicDEFAULT_GROUP8081
publicMY_GROUP8082
ns_testMY_GROUP8083
  • 在 nacos config 配置中心中进行克隆

image.png
image.png

  • 8081 默认启动
  • 8082 做动态参数启动

image.png

  • 8083 做动态参数启动

image.png

  • 依次启动 consumer 和 provider 集群

image.png

  • consumer 当前配置

image.png

  • consumer 访问 provider

image.png

  • consumer 放开 namspace 注释,重启 consumer,再次访问

image.png


在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux系统之NFS服务配置

准备工作 克隆两台linux&#xff0c;并更改其Mac地址&#xff0c;作为NFS客户端&#xff1b;将服务器更名为学号nfsserver&#xff0c;配置IP地址为192.168.学号.1 将客户端Client1更名为学号client1&#xff0c;配置IP地址为192.168.学号.2 将客户端Client2更名为学号clien…

达梦数据库一体机在宜昌市财政局上线了!

财政作为国家治理的基础和重要支柱&#xff0c;其数字化转型已成为构建现代财政制度的必由之路&#xff0c;引领着财政管理体系向更高效、更智能的方向迈进。 达梦数据全面助力财政信息化转型与智能化发展&#xff0c;采用 DAMEGN PAI I 系列数据库一体机&#xff0c;为宜昌市财…

python实现图像分割算法3

python实现区域增长算法 算法原理基本步骤数学模型Python实现详细解释优缺点应用领域区域增长算法是一种经典的图像分割技术,它的目标是将图像划分为多个互不重叠的区域。该算法通过迭代地合并与种子区域相似的邻域像素来实现分割。区域增长算法通常用于需要精确分割的场景,如…

css实现文字根据条件渐变

body 选择器 body { padding: 50vh 0; text-align: center; font-size: 6em; } padding: 50vh 0; 设置了body的上下内边距为视口高度的50%&#xff0c;左右内边距为0。text-align: center; 使得body内的文本内容居中显示。font-size: 6em; 设置了字体大小为当前字体尺寸的6倍…

Solana 自建节点搭建教程:手把手教你成为区块链网络的重要一员

区块链技术正在迅速改变世界&#xff0c;而Solana作为新一代高性能公链&#xff0c;以其出色的性能和低廉的交易费用吸引了众多开发者和用户。如果你想成为Solana生态系统的一部分&#xff0c;搭建自己的Solana节点是一个绝佳的选择。本教程将详细介绍如何一步步搭建Solana自建…

MyBatis 如何通过拦截器修改 SQL

目录 1. 实现Interceptor接口2. 注册配置文件 假如我们想实现多租户&#xff0c;或者在某些 SQL 后面自动拼接查询条件。在开发过程中大部分场景可能都是一个查询写一个 SQL 去处理&#xff0c;我们如果想修改最终 SQL 可以通过修改各个 mapper.xml 中的 SQL 来处理。 但实际过…

【C语言】结构体内存布局解析——字节对齐

&#x1f984;个人主页:小米里的大麦-CSDN博客 &#x1f38f;所属专栏:https://blog.csdn.net/huangcancan666/category_12718530.html &#x1f381;代码托管:黄灿灿 (huang-cancan-xbc) - Gitee.com ⚙️操作环境:Visual Studio 2022 目录 一、引言 二、什么是字节对齐&…

开源个性化自托管服务仪表板:Dashy

**Dashy&#xff1a;**一站式管理&#xff0c;个性化展现- 精选真开源&#xff0c;释放新价值。 概览 Dashy是一个创新的自托管仪表板解决方案&#xff0c;旨在为用户提供一个集中管理多个在线服务的平台。通过直观的界面设计&#xff0c;Dashy允许用户快速访问他们的自托管应…

【C++】内联函数vs宏 nullptr

目录 宏的优缺点分析概念回顾宏的缺点宏的优点 内联函数&#xff08;inline&#xff09;inline函数的定义和声明总结 宏的优缺点分析 概念回顾 下面是宏的申明方式&#xff1a; #define name( parament-list ) stuff //其中的 parament-list 是一个由逗号隔开的符号表&#x…

一个能够在网上爬取思维导图的python小程序

这个小程序是为需要从网上爬取思维导图的朋友写的,时间久了怕被遗忘在垃圾箱里,所以贴出来,给需要的同学使用。 河西石原创地址:https://haigear.blog.csdn.net/article/details/140878039 二、使用方法及流程介绍 简单的说明一下使用的方法: 1、在网上找到自己需要的思…

GBase8c psycopg2安装(centos6)

GBase8c psycopg2安装(centos6) 安装步骤&#xff1a; [rootcentos6 ~]# cd /opt/python/ [rootcentos6 python]# ls psycopg2-2.7.7.tar.gz [rootcentos6 python]# tar -zxf psycopg2-2.7.7.tar.gz [rootcentos6 python]# cd psycopg2-2.7.7 # 安装命令 [rootcentos6 psycop…

【C++:jsoncpp库的配置CMAKE的安装】

CMAKE的安装&#xff1a; 安装路径&#xff1a;Download CMake安装就是无脑Next跳出以下窗口以上步骤完了之后&#xff0c;页面如此&#xff0c;然后点击generate jsoncpp库的配置&#xff1a; 打开生成的源文件所在路径&#xff0c;找到名为jsoncpp.sln的文件&#xff0c;以vs…

大数据信用报告怎么查?有哪些注意事项?

大数据信用对于有资金周转的人来说是比较重要的&#xff0c;主要由于大数据信用无形的被不少机构用于贷前风控&#xff0c;无论是机构要求的还是自查&#xff0c;提前了解大数据信用情况是常规操作&#xff0c;那大数据信用报告如何查询?有哪些需要注意的呢?本文详细为大家讲…

【Kubernetes】k8s集群的资源发布方式

目录 一.常见的发布方式 二.如何实现 1.滚动升级 2.蓝绿升级 3.实现金丝雀发布&#xff08;灰度发布&#xff09; 一.常见的发布方式 蓝绿发布&#xff1a;两套环境交替升级&#xff0c;旧版本保留一定时间便于回滚。优点 用户无感知&#xff0c;部署和回滚速度较快缺点 …

使用 Python 对雷达卫星 sar 图像进行降噪的三种方法

合成孔径雷达 (SAR) 图像广泛应用于各种领域(航空航天、军事、气象等)。问题是这种图像在其原始格式中受到噪点的影响。虽然这些图像通常也是沉重的文件,但从科学的角度来看,有效地对其进行去噪的任务似乎既具有挑战性,又在现实世界中非常有用。 卫星图像有两大类: 光学…

嵌入式C++、QML与MQTT:智能化农业灌溉管理系统设计思路(代码示例)

目录 一、项目概述 二、系统架构 三、环境搭建 1. 硬件环境 2. 软件环境 四、代码实现 1. 硬件端代码示例 2. 软件端代码示例 a. 后端代码&#xff08;Node.js MQTT&#xff09; b. 前端代码&#xff08;QML&#xff09; 五、项目总结 一、项目概述 随着全球对农业…

Xinference如何注册自定义模型

环境&#xff1a; Xinference 问题描述&#xff1a; Xinference如何注册自定义模型 解决方案&#xff1a; 1.写个model_config.json&#xff0c;内容如下 {"version": 1,"context_length": 2048,"model_name": "custom-llama-3"…

Java 中的缓冲流

字符流 前面学习的字节流和字符流都是基本流&#xff0c;其中字符流的底层其实已经在内存中创建了一个长度为8192的字节数组作为缓存区。而字节流中则是没有的。 在内存中增加缓冲区的目的是为了减少内存与硬盘的交互的次数&#xff0c;因为这一操作比较耗时。 下面是一个图…

PixelMaster - 图片像素化终极利器 !

PixelMaster 是将普通图像转变为令人惊叹的像素艺术杰作的终极工具。非常适合艺术家、设计师和像素艺术爱好者&#xff01; https://apps.apple.com/app/pixelmaster-image-pixelator/id6502478442 为什么选择 PixelMaster&#xff1f; • 自定义像素形状&#xff1a;选择或导…

【Linux修行路】进度条小程序

目录 ⛳️推荐 一、预备知识 1.1 回车换行 1.2 缓冲区 二、倒计时 2.1 注意事项 三、进度条 3.1 源代码 3.2 代码分析 3.2 实际使用场景 ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家…