消息总线在微服务中的应用

直连式配置中心

上一篇文章介绍了 Spring Cloud 中的分布式配置组件 Config,每个服务节点可以从Config Server 拉取外部配置信息。但是似乎还有一个悬而未决的问题,那就是当服务节点数量非常庞大的时候,我们不可能一台一台服务器挨个去手工触发刷新,这时候就需要一个可以号令武林的角色出场,由它代替我们做批量刷新的事儿。

帮派组织架构

  • 帮主:仍然是我们的 Github 服务器(后面会讲到其他存放属性文件的方式),存放所有的配置项信息
  • 传功长老:Config 组件,从 Github 那里获取资源文件,并保存一份放到本地。
  • 小弟:众多服务节点,从传功长老那里获取帮主的指令

Config Server 的工作模式

Config Server 主要有两种工作模式:

  • 效忠帮主 在这个模式下,Config Server 只会从 Github 或者数据库获取配置信息 Github 方案:如果 Github 是公共仓库,那就不需要配置用户名和密码。如果是私有仓库,要把登录用的用户名和密码写到配置文件里面,当然密码可以通过加密方式存储,然后系统启动的时候使用密钥进行解密
  • Database 方案,需要额外指定 spring.profiles.active=jdbc 切换到 db 方案,并指定数据源自立门户 帮主?什么帮主?我就是帮主,Github 被我一脚踢开,Config 组件自己说了算,直接从本地路径读取资源文件采用这种方式,需要指定spring.profiles.active=native开启功能,然后指定本地文件存储路径为了简化配置,我们的课程采用第一种模式管理配置文件,也就是 Github 公共仓库。在项目配置中非常简单,只用指定 Github 地址就可以,例如spring.cloud.config.server.git.uri=https://github.com/xxxxx/config-repo.git

在企业应用中,有时也会有多个项目共同使用一个 Github repo 的情况,这时候就需要将不同项目的资源文件放到不同目录下,使用如下配置,给你的服务指定一个独立的目录存放配置文件spring.cloud.config.server.git.search-paths=/{appName}

直连式方案的利弊

优点 :从部署结构上来讲相当简单,组件间依赖也少
缺点:可用性不能得到保障,假如 Config 节点宕机会产生较大影响。由于需要将在客户端启动的时候指定 Config 地址,即便这里使用 DNS 地址(比如域名等非 IP 形式),如果域名发生变化仍然需要在客户端重新配置 Config 地址。

配置文件动态刷新

斧头帮决定来一次整风运动,调动小弟们的积极性,要做到帮主随叫随到(是帮主叫你,不是他自己随叫随到),我们来看看怎么推广。

很简单,这个过程分 3 个步骤进行:

  1. 发送刷新请求 我们选定一个服务节点,通过 POST 请求访问节点下的/actuator/refresh 路径,这时节点会发送一个刷新请求到 Config 服务器
  2. 拉取文件 Config 服务器会访问 Github 获取最新的内容,并把配置信息文件下载到本地
  3. 获取更新内容 接着服务节点从 Config 那里拿到变更内容,并将变动的属性配置到各个类中。

在第三步骤里还有个小前提,假如一个类中有需要进行运行期替换操作的属性,那就要把@RefreshScope 注解加到这个类上,这样运行期参数修改才会在这个类上面生效。在上面那个 case "里, /actuator/refresh"就像帮主发给小弟的对讲机,只要一声令下就得前来报到。但是要使用这个对讲机还得先了解一下它的配置。

什么是 Actuator

Actuator 是一个轻巧的监控组件,通过 REST 接口的方式可以供外部调用,访问服务节点下的 "/actuator"路径可以查看当前开放的服务。

Actuator 也是一个相当贴心的组件,当你引入 Spring Cloud 的其他组件依赖到 pom 中以后(比如 Config 或 BUS),这部分组件会通过 Actuator Endpoint 将自己的核心服务提供出去(比如 Config 和 BUS 的 refresh 功能)。假如同学们访问 /actuator后只能看到 health info 这两个服务,那是因为 Actuator 的服务包含很多 "机密" 信息,为了安全考虑,默认只暴露几个无关痛痒的接口。我们可以通过改动默认配置项让它暴露指定的接口,为了方便演示,本课程中我们采用以下配置让Actuator "暴露所有服务,这样你就可以通过 /actuator"路径查看当前可用的服务了。management.endpoints.web.exposure.include=*

消息总线BUS

接下来,让我们继续 "总线式架构" 的展望,看看 Spring Cloud 中哪个组件可以担当号令武林的角色。

号令武林

武林至尊 宝刀屠龙

号令武林 莫敢不从

BUS- 消息总线,从这个 "总" 字就可以看出身份地位不一般,它代理了这个号令武林的角色,将消息变更发送给所有的服务节点。

在微服务架构的系统中,通常我们会使用消息代理来构建一个 Topic,让所有服务节点监听这个主题,当生产者向 Topic 中发送变更的时候,这个主题产生的消息会被所有实例所消费,这就是消息总线的工作模式,也就是我们熟悉的 "发布- 订阅" 模型。

其实广义的消息总线不单指代这种 "发布- 订阅" 的模式,也可以代指分布式服务间进行通信、消息分发的 单播 模式,甚至有的公司既不使用 HTTP 也不用 RPC 来构建微服务,完全靠消息总线来做服务调用。比如银行的一些老系统就是采用总线型架构,在不同服务节点之间做消息分发。

Spring Cloud BUS 的职责范围就相对小了很多,因为还有一个 Stream 组件代理了大部分的消息中间件通信服务,因此 BUS " "在实际应用中大多是为了应对 消息广播 的场景,比如和 Config 一同搭配使用推送配置信息。

我们先来看下官网对 BUS 定位的描述:

Spring Cloud Bus links nodes of a distributed system with a lightweight message

broker. This can then be used to broadcast state changes (e.g. configuration

changes) or other management instructions.

不同于其他 Spring Cloud 组件洋洋洒洒的大篇功能描述,Spring 官网对 BUS 的应用场景

寥寥数笔,总结一下它的应用范围就是:广播状态更改,例如配置变更或者其他的管理指

令。

总线式架构的完整流程

下面我们揭开总线式架构的完整面纱:

白底红框那三个和 BUS 有关系的步骤:

  • MQ/Kafka BUS 是一个调用封装,它背后还是需要依赖消息中间件来完成底层的消息分发,实际项目中最常用的两个中间件分别是 RabbitMQKafka
  • BUS 作为对接上游应用和下游中间件系统的中间层,当接到刷新请求的时候,通知底层中间件向所有服务节点推送消息
  • Refresh Config 章节中我们通过 Refresh 请求来刷新配置,那么对于总线式架构的Refresh 请求来说,有两个需要解决的问题:谁来发起变更 - 是由服务节点,还是由 Config Server 发起变更请求?

小结

本文带大家了解了 BUS + Config 结合的总线式消息推送模型,后续我们将继续对 BUS 展

开深入的学习。

BUS 底层依赖了 Stream 来广播消息,真正实现与消息代理进行交互的实际上是 Stream,它才是站在 BUS 背后的男人。

学习 Tips:Spring Cloud 各个组件之间常有相互依赖的关系,比如 Feign 和 Ribbon 还有Hystrix 搭配,BUS 和 Stream,Config 和 BUS,整个 Spring Cloud 各组件配合的天衣无缝浑然一体,秉承了 Spring " "家族 全家桶 式的设计思想。回想过去十多年来层出不穷的开源框架,能走到今天依然在 Java 企业级开发领域呼风唤雨的也只有 Spring 了,从最初的IOC+AOP,到 MVC+全家桶组件库,再到 SpringBoot,现在又是 SpringCloud,Spring一直是 Java 领域的弄潮儿,这种生命力和创新精神真的是相当厉害。

本文已收录至我的个人网站:程序员波特,主要记录Java相关技术系列教程,共享电子书、Java学习路线、视频教程、简历模板和面试题等学习资源,让想要学习的你,不再迷茫。

相关推荐
fanly113 天前
Surging AI Agent 完整产品介绍
微服务·microservice
吃饱了得干活5 天前
Spring Cloud Gateway 微服务网关:路由、断言、过滤器
java·spring cloud
蝎子莱莱爱打怪9 天前
XZLL-IM干货系列 04|Netty 长连接实战:Pipeline 怎么排、心跳怎么跳、连接怎么管
后端·微服务·面试
SamDeepThinking10 天前
Java微服务练习方式
java·后端·微服务
米丘13 天前
微前端之 Web Components 完全指南
微服务·html
霸道流氓气质16 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
慧一居士16 天前
Feign的GET请求如何传递对象参数?
java·spring cloud
我登哥MVP16 天前
SpringCloud Alibaba 核心组件解析:服务链路追踪
java·spring boot·后端·spring·spring cloud·java-ee·maven
慧一居士16 天前
SpringCloud 微服务Feigin 用的完整调用端和被调用的示例
java·spring cloud
霸道流氓气质16 天前
Spring Boot 微服务性能优化完全指南
spring boot·微服务·性能优化