如果需要客户端获取到最新的配置信息需要执行refresh,我们可以利用webhook的机制每次提交代码发送请求来刷新客户端,当客户端越来越多的时候,需要每个客户端都执行一遍,这种方案就不太适合了。使用Spring Cloud Bus可以完美解决这一问题。

Spring bus的一个核心思想是通过分布式的启动器对spring boot应用进行扩展,也可以用来建立一个多个应用之间的通信频道。目前唯一实现的方式是用AMQP消息代理作为通道,同样特性的设置(有些取决于通道的设置)在更多通道的文档中。其实本质是利用了MQ的广播机制在分布式的系统中传播消息,目前常用的有Kafka和RabbitMQ。

更新客户端配置文件整个流程是:

  1. 提交代码触发post请求给bus/refresh
  2. server端接收到请求并发送给Spring Cloud Bus
  3. Spring Cloud bus接到消息并通知给其它客户端
  4. 其它客户端接收到通知,请求Server端获取最新配置
  5. 全部客户端均获取到最新的配置

RocketMQ实现

《Spring Boot中使用RabbitMQ》一文中,我们已经介绍了关于消息代理、AMQP协议以及RabbitMQ的基础知识和使用方法。下面我们开始具体介绍Spring Cloud Bus的配置,并以一个Spring Cloud Bus与Spring Cloud Config结合的例子来实现配置内容的实时更新。

RabbitMQ实现

下面我们来具体动手尝试整个配置过程:

  • 准备工作:这里我们不做新的应用,但需要用到上一章中,我们已经实现的关于Spring Cloud Config的几个工程,若读者对其还不了解,建议先阅读第4章的内容。

    • config-repo:定义在Git仓库中的一个目录,其中存储了应用名为didispace的多环境配置文件,配置文件中有一个from参数。
    • config-server-eureka:配置了Git仓库,并注册到了Eureka的服务端。
    • config-client-eureka:通过Eureka发现Config Server的客户端,应用名为didispace,用来访问配置服务器以获取配置信息。该应用中提供了一个/from接口,它会获取config-repo/didispace-dev.properties中的from属性返回。
  • 扩展config-client-eureka应用
    • 修改pom.xml增加spring-cloud-starter-bus-amqp模块(注意spring-boot-starter-actuator模块也是必须的)。
1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
  • 在配置文件中增加关于RabbitMQ的连接和用户信息
1
2
3
4
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=springcloud
spring.rabbitmq.password=123456
  • 启动config-server-eureka,再启动两个config-client-eureka(分别在不同的端口上,比如7002、7003),我们可以在config-client-eureka中的控制台中看到如下内容,在启动时候,客户端程序多了一个/bus/refresh请求。
o.s.b.a.e.mvc.EndpointHandlerMapping : Mapped "{[/bus/refresh],methods=[POST]}" onto public void org.springframework.cloud.bus.endpoint.RefreshBusEndpoint.refresh(java.lang.String)
  • 到这里,我们已经能够通过Spring Cloud Bus来实时更新总线上的属性配置了。先访问两个config-client-eureka的/from请求,会返回当前config-repo/didispace-dev.properties中的from属性。
  • 接着,我们修改config-repo/didispace-dev.properties中的from属性值,并发送POST请求到其中的一个/bus/refresh
  • 最后,我们再分别访问启动的两个config-client-eureka的/from请求,此时这两个请求都会返回最新的config-repo/didispace-dev.properties中的from属性。

原理分析

我们通过使用Spring Cloud Bus与Spring Cloud Config的整合,并以RabbitMQ作为消息代理,实现了应用配置的动态更新。

整个方案的架构如上图所示,其中包含了Git仓库、Config Server、以及微服务“Service A”的三个实例,这三个实例中都引入了Spring Cloud Bus,所以他们都连接到了RabbitMQ的消息总线上。

当我们将系统启动起来之后,“Service A”的三个实例会请求Config Server以获取配置信息,Config Server根据应用配置的规则从Git仓库中获取配置信息并返回。

此时,若我们需要修改“Service A”的属性。首先,通过Git管理工具去仓库中修改对应的属性值,但是这个修改并不会触发“Service A”实例的属性更新。我们向“Service A”的实例3发送POST请求,访问/bus/refresh接口。此时,“Service A”的实例3就会将刷新请求发送到消息总线中,该消息事件会被“Service A”的实例1和实例2从总线中获取到,并重新从Config Server中获取他们的配置信息,从而实现配置信息的动态更新。

而从Git仓库中配置的修改到发起/bus/refresh的POST请求这一步可以通过Git仓库的Web Hook来自动触发。由于所有连接到消息总线上的应用都会接受到更新请求,所以在Web Hook中就不需要维护所有节点内容来进行更新,从而解决了通过Web Hook来逐个进行刷新的问题。

指定刷新范围

上面的例子中,我们通过向服务实例请求Spring Cloud Bus的/bus/refresh接口,从而触发总线上其他服务实例的/refresh。但是有些特殊场景下(比如:灰度发布),我们希望可以刷新微服务中某个具体实例的配置。

Spring Cloud Bus对这种场景也有很好的支持:/bus/refresh接口还提供了destination参数,用来定位具体要刷新的应用程序。比如,我们可以请求/bus/refresh?destination=customers:9000,此时总线上的各应用实例会根据destination属性的值来判断是否为自己的实例名,若符合才进行配置刷新,若不符合就忽略该消息。

destination参数除了可以定位具体的实例之外,还可以用来定位具体的服务。定位服务的原理是通过使用Spring的PathMatecher(路径匹配)来实现,比如:/bus/refresh?destination=customers:**,该请求会触发customers服务的所有实例进行刷新。

架构优化

既然Spring Cloud Bus的/bus/refresh接口提供了针对服务和实例进行配置更新的参数,那么我们的架构也相应的可以做出一些调整。在之前的架构中,服务的配置更新需要通过向具体服务中的某个实例发送请求,再触发对整个服务集群的配置更新。虽然能实现功能,但是这样的结果是,我们指定的应用实例就会不同于集群中的其他应用实例,这样会增加集群内部的复杂度,不利于将来的运维工作,比如:我们需要对服务实例进行迁移,那么我们不得不修改Web Hook中的配置等。所以我们要尽可能的让服务集群中的各个节点是对等的。

因此,我们将之前的架构做了一些调整,如下图所示:

我们主要做了这些改动:

  1. 在Config Server中也引入Spring Cloud Bus,将配置服务端也加入到消息总线中来。
  2. /bus/refresh请求不在发送到具体服务实例上,而是发送给Config Server,并通过destination参数来指定需要更新配置的服务或实例。

通过上面的改动,我们的服务实例就不需要再承担触发配置更新的职责。同时,对于Git的触发等配置都只需要针对Config Server即可,从而简化了集群上的一些维护工作。

本文完整示例:

通过消息总线Spring Cloud Bus实现配置文件刷新(使用Kafka或RocketMQ)的更多相关文章

  1. 第七篇: 消息总线(Spring Cloud Bus)

    Spring Cloud Bus 将分布式的节点用轻量的消息代理连接起来.它可以用于广播配置文件的更改或者服务之间的通讯,也可以用于监控.本文要讲述的是用Spring Cloud Bus实现通知微服务 ...

  2. 【SpringCloud 】第八篇: 消息总线(Spring Cloud Bus)

    前言: 必需学会SpringBoot基础知识 简介: spring cloud 为开发人员提供了快速构建分布式系统的一些工具,包括配置管理.服务发现.断路器.路由.微代理.事件总线.全局锁.决策竞选. ...

  3. 原 史上最简单的SpringCloud教程 | 第八篇: 消息总线(Spring Cloud Bus)(Finchley版本)

    转载请标明出处: 原文首发于:https://www.fangzhipeng.com/springcloud/2018/08/30/sc-f8-bus/ 本文出自方志朋的博客 转载请标明出处: Spr ...

  4. 史上最简单的SpringCloud教程 | 第八篇: 消息总线(Spring Cloud Bus)

    转载请标明出处: 原文首发于:https://www.fangzhipeng.com/springcloud/2017/07/12/sc08-bus/ 本文出自方志朋的博客 最新Finchley版本请 ...

  5. 一起来学Spring Cloud | 第八章:消息总线(Spring Cloud Bus)

    上一章节,我们讲解了分布式配置中心spring cloud config,我们把配置项存放在git或者本地,当我们修改配置时,需要重新启动服务才能生效.但是在生产上,一个服务部署了多台机器,重新启动比 ...

  6. SpringCloud学习(八)消息总线(Spring Cloud Bus)(Finchley版本)

    Spring Cloud Bus 将分布式的节点用轻量的消息代理连接起来.它可以用于广播配置文件的更改或者服务之间的通讯,也可以用于监控.本文要讲述的是用Spring Cloud Bus实现通知微服务 ...

  7. springCloud学习-消息总线(Spring Cloud Bus)

    1.简介 Spring Cloud Bus 将分布式的节点用轻量的消息代理连接起来.它可以用于广播配置文件的更改或者服务之间的通讯,也可以用于监控.本文要讲述的是用Spring Cloud Bus实现 ...

  8. SpringCloud 教程 (一) 消息总线(Spring Cloud Bus)

    Spring Cloud Bus 将分布式的节点用轻量的消息代理连接起来.它可以用于广播配置文件的更改或者服务之间的通讯,也可以用于监控.本文要讲述的是用Spring Cloud Bus实现通知微服务 ...

  9. SpringCloud教程 | 第八篇: 消息总线(Spring Cloud Bus)

    一.安装rabbitmq 二.pom父文件 <?xml version="1.0" encoding="UTF-8"?> <project x ...

随机推荐

  1. Java生鲜电商平台-电商促销业务分析设计与系统架构

    Java生鲜电商平台-电商促销业务分析设计与系统架构 说明:Java开源生鲜电商平台-电商促销业务分析设计与系统架构,列举的是常见的促销场景与源代码下载 左侧为享受促销的资格,常见为这三种: 首单 大 ...

  2. GALAXY OJ NOIP2019联合测试1-总结

    概要 本次比赛考的不是很好,400分的题只拿了180分...(失误失误) 题目 T1:数你太美(预期100 实际60) 题目大意: 在两个序列中找两个最小的数进行组合,使这个最小整数最小. 解析: 只 ...

  3. Docker 容器命令大全

    容器命令: 命令 描述 attach 将本地标准输入,输出和错误流转到到正在运行的容器 build 从Dockerfile构建映像 commit 根据容器的更改创建新镜像 cp 在容器和本地文件系统之 ...

  4. 智能家居-1.基于esp8266的语音控制系统(开篇)

    智能家居-1.基于esp8266的语音控制系统(开篇) 智能家居-2.基于esp8266的语音控制系统(硬件篇) 智能家居-3.基于esp8266的语音控制系统(软件篇) apache-apollo安 ...

  5. 错误记录PHP preg_match(): Compilation failed: range out of order in character class at offset 7 01_login.php</b> on line <b>13</b><br />

    <?php //响应头格式为json,编码为uft-8,注意有- header("Content-Type:application/json;charset=utf-8"); ...

  6. RDD源码分析

    RDD源码解析 一. RDD.scala - Resilient Distributed Dataset (RDD) 弹性分布式数据集 弹性: 体现在计算上面 - the basic abstract ...

  7. 如何下载windows版的kubectl.exe文件

    github上的下载链接,不能直接下载. https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.14.md#client-b ...

  8. JavaGC垃圾回收机制和常见垃圾回收算法

    Java GC是在什么时候,对什么东西,做了什么事情?” 什么位置:大部分在堆中,还有方法区!!方法区的垃圾收集主要回收两部分内容:废弃常量和无用的类,当满了之后同样触发FullGC, HotSpot ...

  9. JS高阶---函数

    [问题] [主体] 1.什么是函数? ①实现特定功能 ②多条语句的封装体 ③可以重复执行的代码块 2.为什么用函数? 提高代码的复用性,提升效率 3.如何定义函数? ①函数声明定义 ②函数表达式定义③ ...

  10. 201871010107-公海瑜《面向对象程序设计(java)》第七周学习总结

    201871010107-公海瑜<面向对象程序设计(java)>第七周学习总结             项目                       内容   这个作业属于哪个课程  ...