SpringCloud-微服务入门之统一配置中心Config(5)

x33g5p2x  于2022-06-10 转载在 Spring  
字(8.9k)|赞(0)|评价(0)|浏览(421)

要做好微服务的配置管理,则需要处理好以下几个问题:

  1. 在微服务架构中配置数据与服务实例不要在同一个地方,最好各自独立分开。
  2. 解决非侵入式配置数据的植入通过对配置文件的集中式管理,
  3. 可以非常方便地对微服务的配置进行统一修改和发布,并能够建立版本机制,以便后续进行配置数据的回溯。
  4. 保障配置服务的高可用性

Spring Cloud Config简介

SpringCloud Config核心就是配置中心,通过一个服务端和多个客户端实现配置服务。具有中心化、版本控制、支持动态更新和语言独立等特性,其优点:

  1. 提供配置服务器和配置客户端两种角色,便于部署和使用,使开发者可以集中管理分布式环境下的应用配置。
  2. 配置服务器集中对配置资源进行管理,并支持多种配置资源存储方式,如Git、SVN及文件系统。
  3. 通过对Git、SVN的支持,便于对配置文件进行版本管理,可以对配置文件的变更做审查。
  4. 应用通过简单的注解就可以实现配置的统一管理。
  5. Spring Cloud Config提供与Spring Boot配置类似的机制,可以非常容易地实现对应用开发环境、测试环境、灰度环境和生产环境的配置、切换和迁移等处理。
  6. 配置服务器可以方便地与Eureka和Consul等进行整合,快速构建一个高可用的配置服务。
  7. 配置服务器也可以用于其他语言开发的服务中。

Spring Cloud Config有两个角色Server和Client

1, 当配置客户端获取配置时,服务端及时从Git仓库中获取配置副本,从而保证配置数据为最新。
2,支持从yml、json、properties等文件加载配置
3,配置Eureka可实现服务发现,配置Cloud Bus可实现配置推送更新
4,默认配置存储基于Git,从而支持配置的版本管理。Client只需要在引导配置文件中声明所使用的配置服务器地址即可。

Spring配置加载顺序和覆盖问题

bootstrap.yml文件也是Spring Boot的默认配置文件,而且其加载的时间相比于application.yml更早。application.yml和bootstrap.yml虽然都是Spring Boot的默认配置文件,但是定位却不相同。bootstrap.yml,可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。application.yml 可以用来定义应用级别的,总结就是,bootstrap.yml文件相当于项目启动时的引导文件,内容相对固定 能保证服务正常启动。application.yml文件是针对当前微服务 配置一些细节方面的东西变化比较频繁。

他们两个文件是可以同时存在的那么有人会问了 bootstrap.yml文件内容是从 git 上获取而application.yml 是当前服务的配置文件,如果内容相同会不会冲突 ? 答案不会 bootstrap.yml 加载的时间相比于application.yml更早。 如果有些配置属性相同的话就会被application.yml内覆盖配置

当服务中同时有bootstrap.yml ,application.yml时,application.yml中的端口则不会覆盖掉bootstrap.yml中的端口,也就是 默认使用的是bootstrap.yml的端口号 ,还有就是application.yml在application.properties之前加载,同名属性会被application.properties覆盖, 远程配置中心会最后兜底,覆盖掉所有同名属性

使用Gitee作为远程配置仓库

知名的Git远程仓库有国外的GitHub和国内的码云(gitee);但是使用GitHub时,国内的用户经常遇到的问题是访
问速度太慢,有时候还会出现无法连接的情况。如果希望体验更好一些,可以使用国内的Git托管服务——码云(gitee.com)。
与GitHub相比,码云也提供免费的Git仓库。此外,还集成了代码质量检测、项目演示等功能。对于团队协作开发,
码云还提供了项目管理、代码托管、文档管理的服务。本章中使用的远程Git仓库是码云。码云访问地址:https://gitee.com/
创建远程仓库
首先要使用码云上的私有远程git仓库需要先注册帐号;请先自行访问网站并注册帐号,然后使用帐号登录码云控制台并创建公开仓库

新建仓库

公开仓库

在新建的仓库中创建需要被统一配置管理的配置文件。配置文件的命名方式:{application}-{profifile}.yml 或 {application}-{profifile}.properties
application: 为应用名称
profifile: 用于区分开发环境,测试环境、生产环境等
如common-dev.yml,表示公共模块通用开发环境下使用的配置文件这里将common工程的配置文件application.yml文件的内容复制作为common-dev.yml文件的内容,具体配置如下:

创建common-dev.yml配置文件

将之前common模块的application-common.yml内容添加到这个里, 不要eureka配置相关内容

以上都完成了那么 我们就开始搭建搭建配置中心微服务

项目结构

搭建配置中心微服务

创建一个config-server子模块

添加Maven依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
    </dependencies>

然后添加application.yml配置文件

#设置端口号
server:
  port: 12000

# 设置  服务名 config-server
spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
         uri: https://gitee.com/huanminabc/spring-cloud-config.git  #码云 配置文件仓库地址

#注册Eureka
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8000/eureka,http://127.0.0.1:8001/eureka,http://127.0.0.1:8002/eureka

启动类

package com.itheima.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

以上都完成了那么将eureka服务启动然后在启动config-server访问http://localhost:12000/common-dev.yml

服务配置文件改造

先改造producer1的配置, 配置文件信息不再由common模块提供,而是从配置中心获取。
application.yml内容如下:

server:
  port: 9010

# 设置服务名称  会在Eureka中显示
spring:
  application:
    name: producer

bootstrap.yml内容如下:

spring:
  cloud:
    config:
      name: common,producer     # 与远程仓库中的配置文件的application保持一致 ,多个配置使用,分割
      profile: dev   # 远程仓库中的配置文件的profile保持一致
      label: master   # 远程仓库中(分支名称)	
      discovery:
        enabled: true  # 使用配置中心
        service-id: config-server   # 配置中心服务名称

#向Eureka 中注册实例
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8000/eureka,http://127.0.0.1:8001/eureka,http://127.0.0.1:8002/eureka

然后添加Maven

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

然后在将producer1和producer2也都更换为配置中心的方式 ,其他依赖common模块的都要改,相关的配置需要在gitee上补充文件

消费者因为使用了feign相关的配置那么我们可以将内容移入consumer-dev.yml里

消费者目前的配置如下:
application.yml

server:
  port: 9001

# 设置服务名称  会在Eureka中显示 而且其他方也要用的
spring:
  application:
    name: consumer

bootstrap.yml

spring:
  cloud:
    config:
      name: common,consumer     # 与远程仓库中的配置文件的application保持一致 ,多个配置使用,分割
      profile: dev   # 远程仓库中的配置文件的profile保持一致
      label: master   # 远程仓库中(分支名称)
      discovery:
        enabled: true  # 使用配置中心
        service-id: config-server   # 配置中心服务名称

#向Eureka 中注册实例
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8000/eureka,http://127.0.0.1:8011/eureka,http://127.0.0.1:8002/eureka

如果以上服务都能正常启动那么说明没问题,然后访问消费者试试,如果也ok那么就说明配置中心搭建好了

消息总线

上面的案例会面临着新的问题 就是我们修改gitee中的配置文件内容 但是并不会立马生效 必须重启使用配置文件的那个服务才行,在项目上线后如果我们重启服务肯定是不现实的那么如何在不重启服务的情况下完成刷新配置文件呢?可以使用Spring Cloud Bus来实现配置的自动更新(热部署)。需要注意的是Spring Cloud Bus底层是基于RabbitMQ实现的,默认使用本地的消息队列服务,所以需要提前启动本地RabbitMQ服务(安装RabbitMQ以后才有),如下:

config服务端配置

然后我们在config-server 里pom.xml添加:

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-bus</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
        </dependency>

然后修改config-server 里 application.yml 内容

spring:
  # rabbitmq的配置信息;  我下面使用的是rabbitmq自带的默认配置
  rabbitmq:
    host: 127.0.0.1    #ip
    port: 5672   #端口 5672 固定端口
    username: guest   #账号
    password: guest  #密码
    
management:
  endpoints:
    web:
      exposure:
      # 暴露触发消息总线的地址 : xxx/actuator/bus-refresh   固定的访问方式
        include: "*"

重启config-server服务

config客户端配置

在客户端服务添加对应的maven依赖和在需要使用配置刷新的类上加上@RefreshScope 就行了

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--bus-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>

注意:自动刷新 只能刷新 @RefreshScope 注解下的配置,一些特殊配置,如数据库等,需要先设置数据库链接ConfigServer类,然后通过加 @RefreshScope 注解方式否则还是需要重启服务的 ,然后重启config-server 就行了,必须重启,别忘了,不然客户端会报错的

然后添加rabbitmq配置信息到对应的客户端的远程配置文件里,这里我以消费者consumer为例:

spring:
  # rabbitmq的配置信息;  我下面使用的是rabbitmq自带的默认配置
  rabbitmq:
    host: 127.0.0.1    #ip
    port: 5672   #端口 5672 固定端口
    username: guest  #账号
    password: guest  #密码

在消费者consumer的controller里添加一个接口,并且在当前controller类上添加@RefreshScope //动态刷新配置

@Value("${test.name}")
    private  String name;
    @GetMapping("/testConfig")
    public ResponseEntity testConfig() {

        return ResponseEntity.ok(name);
    }

然后我们请求接口

然后我们修改远程配置中的test.name ,之后在请求,发现参数没有变化,这是怎么回事呢? ,因为刷新方式需要我手动或者自动去刷新,自动刷新需要进行配置的

手动刷新就是我们修改了远程配置后,调用config-server服务提供的内置的刷新缓存接口,然后从新从gitee上读取新的配置,http://localhost:12000/actuator/bus-refresh POST请求

会有点慢,当刷新完毕后,我们在请求消费者就发现获取的参数就变更了

自动刷新需要利用Gitee中的WebHooks

如果自己测试的话,可以使用内网穿透工具进行代理自己的电脑ip,让外网能访问到自己的电脑,我这里有教程自行参考外网访问内网(内网穿透)

WebHook 推送数据格式说明 ,因为我们/actuator/bus-refresh 不允许发送请求体不然会报错

我们可以在config-server服务内自己写一个http://域名或者ip/refresh代理接口来绕过, 添加mvc的Maven依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/refresh")
public class RefreshController {

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

    @PostMapping("")
    public  void  refresh(){
        sendPostRequest("http://127.0.0.1:"+port+"/actuator/bus-refresh");
    }

    /**
     * 向目的URL发送post请求
     * @param url       目的url
     * @return  ResultVO
     */
    public static String sendPostRequest(String url){
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        HttpEntity<String> formEntity = new HttpEntity<String>(headers);
        return restTemplate.postForObject(url, formEntity, String.class);
    }
}

然后我们修改Gitee中的 common-dev.yml 内容test.name ,之后我们回到WebHooks里查看请求记录,每次修改提交…都会自动请求我们的/refresh刷新接口,而我们内部就会转发请求去访问实际的配置刷新接口,来完成自动化刷新配置的动作

然后你就可以试试了, 修改gitee中的配置后立马就会作用到项目里, 访问的配置信息会一直是最新的

配置中心高可用

将相同的config-server搭建3个都注册到eureka就行了,当我们刷新一台config-server上的配置那么,全部集群都会进行同步数据的,因为会触发消息队列广播模式,会通知其他的集群节点从新拉取最新数据

config-server: 12000 , config-server1:120001 , config-server2:120002

注意: 如果我们 config-server: 12000 宕机了, 配置中心的自动刷新配置就会失效,但是config的服务还是可以正常使用的,而且还是可以进行手动刷新的 ,因为我们在WebHooks里设置的url是指定ip和端口号的,就算配置的域名,那么域名本身也只能绑定一个应用 ,那么解决办法就是,使用nginx进行负载这3台config-server, 然后将nginx地址作为WebHooks的url

然后我们在WebHooks配置nginx的地址即可 http//:nginx:15000/refresh, 之后就不用在担心config-server宕机了导致配置不会自动刷新的问题了

Spring Cloud 体系技术综合应用概览图

注意事项

启动顺序问题

先启动eureka,然后在启动config-server,然后在启动其他服务, 不然会出问题的,因为config-server会先注册到eureka中,其他服务才能发现

点赞 -收藏-关注-便于以后复习和收到最新内容有其他问题在评论区讨论-或者私信我-收到会在第一时间回复如有侵权,请私信联系我感谢,配合,希望我的努力对你有帮助^_^

相关文章