Springcloud-消息总线-Bus

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

BUS- 消息总线-将消息变更发送给所有的服务节点。
在微服务架构的系统中,通常我们会使用消息代理来构建一个Topic,让所有
服务节点监听这个主题,当生产者向topic中发送变更时,这个主题产生的消息会被
所有实例消费,这就是消息总线的工作模式。也是我们熟悉的发布-订阅模型。
其实广义的消息总线不单指这种“发布-订阅”模型!也可以代指分布式服务间进行通信,
消息分发的单播模式,甚至有的公司既不使用HTTP也不用RPC来构建微服务。完全靠消息
总线来做服务调用。比如,银行老系统采用总线型架构,在不同服务结点之间做消息分发

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

总线式架构的完整流程
在这里插入图片描述
我们要关注一下白底红框那三个和BUS有关系的步骤
MQ/KAFKA:BUS是一个调用封装,它的背后还是需要依赖消息中间件来完成底层的消息
分发,实际项目中最常用的两个中间件分别是RabbitMQ和kafka。
BUS:作为对接上游应用和下游中间件系统的中间层,当接到刷新请求的时候,通知底层中间件向所有服务结点推送消息。
Refresh:类比config-center中可以通过actuator的Refresh请求刷新配置,那么对于总线式架构的ReFresh请求来说,有两个需要解决的问题:
谁来发起变更,服务结点还是由ConfigServer发起变更请求?
何时发起变更-时手工发起变更?还是每次Github改动完成后自动推送?

2.BUS简介

BUS实现:
加入我们所有的节点都订阅了topic(消息组件这个属性刷新这个topic)当你的属性发生变动的时候,只要发送一个广播消息,所有的节点都会消费消息,并且触发刷新动作。

BUS的标签:
BUS只是对消息进行了简单的封装,底层是依赖Stream(专业用来与消息中间件进行通信的组件)来广播消息。

在这里插入图片描述
BUS的两个场景:
配置变更通知;自定义消息广播;

3.BUS体系结构解析

BUS的三个角色:
消息的发布者,是一个中间件;
事件监听者,监听事件动态,各个监听消息的服务节点;
事件主体,配置变更就是事件

事件的架构:
在BUS配置刷新的事件类是RefreshRemoteApplicationEvent。在 BUS的规范下,所有事件都包含三个维度的信息:
**source:**这是一个必填信息,它可以是一个自定义并且能够被序列化反序列化的pojo对象,它包含了一个事件想要传达的信息;
Original Service 消息来源方,通常是事件发布方的机器ID,或者AppId等;
Destination Service 目标机器,Bus会根据Destination Service指定的过滤条件(比如服务名,端口等),只让指定的监听者响应事件;

消息发布者
我们所有的“事件”都是通过Bus来发布的,Bus默认提供了两个Endpoint作为消息发布者:
bus-env:在本地发布EnvironmentChangeRemoteApplicationEvent事件,表示一个远程环境变更事件。进一步查看这个事件的内容,我们发现其中包含了一个Map<String, String>属性,事件监听者接收到这个事件之后,会将事件中的Map添加到Spring环境变量中(由Spring Cloud的EnvironmentManager负责具体处理),从而达到修改环境变量的目的
bus-refresh:发布RefreshRemoteApplicationEvent事件,表示一个远程配置刷新事件,这个事件会触发@RefreshScope注解所修饰的Java类中属性的刷新(@RefreshScope修饰的类可以在运行期更改属性)
以上两个ENDpoint就是BUS通过、actuator服务对外提供出来的

消息监听者:
BUS中默认创建了两个消息监听器,分别对应上面两个消息发布的Endpoints。
在这里插入图片描述
在spring-cloud-context这个依赖中定义了大量的事件。

4.Bus的接入方式RabbitMQ & Kafka

Spring的组件一向是以一种插件式的方式提供功能,将组件自身和我们项目中的业务代码隔离,使得我们更换组件的成本可以降到最低。Spring Cloud Bus也不例外,它的底层消息组件非常容易替换,替换过程不需要对业务代码引入任何变更。Bus就像一道隔离了底层消息组件和业务应用的中间层,比如我们从RabbitMQ切换为Kafka的时候,只需要做两件事就好了:
在项目pom中替换依赖组件;
更改配置文件里的连接信息。

RabbitMQ和Kafka两种消息组件如何接入Bus
接入RabbitMQ
RabbitMQ是实现了AMQP(Advanced Message Queue Protocal)的开源消息代理软件,也是平时项目中应用最广泛的消息分发组件之一。
接入RabbitMQ的方式很简单,我们只要在项目中引入以下依赖:

org.springframework.cloud
spring-cloud-starter-bus-amqp

点进去发现,它还依赖于spring-cloud-starter-stream-rabbit。
也就是说stream组件是被真正用来发送广播消息到RabbitMQ,
BUS只是帮我们封装了整个消息的发布和监听动作!
项目所需要的具体的配置:
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest

接入Kafka;
要使用kafka来实现消息代理,只需要把上一步中引入spring-cloud-starter-bus-amqp
依赖替换成spring-cloud-starter-bus-kafka依赖

org.springframework.cloud
spring-cloud-starter-bus-kafka

如果大家的Kafka和ZooKeeper都运行在本地,并且采用了默认配置,那么不需要做任何额外的配置,就可以直接使用。但是在生产环境中往往Kafka和ZooKeeper会部署在不同的环境,所以就需要做一些额外配置:
spring.cloud.stream.kafka.binder.brokers Kafka服务节点(默认localhost)
spring.cloud.stream.kafka.binder.defaultBrokerPort Kafka端口(默认9092)
spring.cloud.stream.kafka.binder.zkNodes ZooKeeper服务节点(默认localhost)
zspring.cloud.stream.kafka.binder.defaultZkPort ZooKeeper端口(默认2181)

5.部分关键源码:

内置事件的架构RefreshRemoteApplicationEvent
刷新事件的发送端-RefreshBusEndpoint

开端:RefreshRemoteApplicationEvent

public class RefreshRemoteApplicationEvent extends RemoteApplicationEvent {@SuppressWarnings("unused")private RefreshRemoteApplicationEvent() {// for serializers}public RefreshRemoteApplicationEvent(Object source, String originService,String destinationService) {super(source, originService, destinationService);}

查看find usage:有两个大类:RefreshBusEndpoint以及RefreshListener类。
一个是起点RefreshBusEndpoint,一个是终点RefreshListener。
关注起点:RefreshBusEndpoint

@Endpoint(id = "bus-refresh") // TODO: document new id
public class RefreshBusEndpoint extends AbstractBusEndpoint {public RefreshBusEndpoint(ApplicationEventPublisher context, String id) {super(context, id);}@WriteOperationpublic void busRefreshWithDestination(@Selector String destination) { // TODO:// document// destinationpublish(new RefreshRemoteApplicationEvent(this, getInstanceId(), destination));}@WriteOperationpublic void busRefresh() {publish(new RefreshRemoteApplicationEvent(this, getInstanceId(), null));}}

关注到主类的super方法,就是到了RemoteApplicationEvent类

protected RemoteApplicationEvent(Object source, String originService,String destinationService) {super(source);this.originService = originService;if (destinationService == null) {destinationService = "**";}// If the destinationService is not already a wildcard, match everything that// follows// if there at most two path elements, and last element is not a global wildcard// alreadyif (!"**".equals(destinationService)) {if (StringUtils.countOccurrencesOf(destinationService, ":") <= 1&& !StringUtils.endsWithIgnoreCase(destinationService, ":**")) {// All instances of the destination unless specifically requesteddestinationService = destinationService + ":**";}}this.destinationService = destinationService;this.id = UUID.randomUUID().toString();
}

本人进行测试的接口是:
测试的接口是:localhost:60002/actuator/bus-refresh
在这里插入图片描述

研究了发现对于RemoteApplicationEvent就是确定destination!

在RefreshBusEndpoint中,将contex存放在ApplicationEventPublisher里。
这就是ApplicationEventPublisher,用来发布上下文消息的!

接下来到了AbstractApplicationContext中

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {Assert.notNull(event, "Event must not be null");// Decorate event as an ApplicationEvent if necessaryApplicationEvent applicationEvent;if (event instanceof ApplicationEvent) {applicationEvent = (ApplicationEvent) event;}else {applicationEvent = new PayloadApplicationEvent<>(this, event);if (eventType == null) {eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();}}// Multicast right now if possible - or lazily once the multicaster is initializedif (this.earlyApplicationEvents != null) {this.earlyApplicationEvents.add(applicationEvent);}else {getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);}// Publish event via parent context as well...if (this.parent != null) {if (this.parent instanceof AbstractApplicationContext) {((AbstractApplicationContext) this.parent).publishEvent(event, eventType);}else {this.parent.publishEvent(event);}}
}

整个过程是事件驱动,编程解耦!

6.如何实现自动推送?Git WebHook

问题:由谁来发起状态的变更请求?
如何通过GitHub的Webhook机制实现自动推送!

Webhook?Git的一种机制,可以用于自动化的构建。
当每次提交代码到Git以后,会触发Webhook执行一段程序,来完成预定义的操作。比如说让钩子通知CI/CD系统从Github拉取最新代码开始执行构建过程或者执行其他操作!

Webhook三步走:
设置encrypt.key;
将上一步中的key添加到Github仓库设置中;
设置Webhook url;
设置encrypt.key,类似属性加解密方式,只需要在application.yml中设置一个key就好!
encrypt:
key: yourKey

自动推送需要注意的问题
无法测试:改动只要一提交就被推送到所有机器,假如不小心修改错了属性,那所有服务器就要团灭了
定点推送:尽管Bus支持在URL中添加目标范围,定向推送到指定机器,但毕竟URL在Webhook里面是写死的,不方便我们根据实际情况做定点推送

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

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

相关文章

多线程引发的安全问题

前言&#x1f440;~ 上一章我们介绍了线程的一些基础知识点&#xff0c;例如创建线程、查看线程、中断线程、等待线程等知识点&#xff0c;今天我们讲解多线程下引发的安全问题 线程安全&#xff08;最复杂也最重要&#xff09; 产生线程安全问题的原因 锁&#xff08;重要…

Hive笔记-6

6.2.8 聚合函数 1) 语法 count(*)&#xff0c;表示统计所有行数&#xff0c;包含null值&#xff1b; count(某列)&#xff0c;表示该列一共有多少行&#xff0c;不包含null值&#xff1b; max()&#xff0c;求最大值&#xff0c;不包含null&#xff0c;除非所有值都是null&a…

不同node版本的切换及其指定版本vue-cli脚手架下载

目录 一.清空本地已安装node.js版本 二.装nvm管理工具 三.安装指定node版本 四.使用nvm命令切换或删除指定node版本 五.在指定node版本下下载指定vue-cli脚手架 一.清空本地已安装node.js版本 1.按健winR弹出窗口&#xff0c;键盘输入cmd&#xff0c;然后敲回车。 2.输入…

win11 + ubuntu linux双系统:开机直接进入windows修复

https://zhuanlan.zhihu.com/p/666702893 这种 双系统直接进入win 的问题&#xff0c;应该属于引导坏了&#xff0c;即grub坏了。 原因&#xff1a;笔记本送修了&#xff0c;没拆掉硬盘&#xff0c;可能引导被售后搞坏了。 在win-磁盘管理中查看分区&#xff0c;linux的分区…

《SpringBoot+Vue》Chapter04 SpringBoot整合Web开发

返回JSON数据 默认实现 依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>在springboot web依赖中加入了jackson-databind作为JSON处理器 创建一个实体类对象…

学编程容易遇到的误区,请提前规避

随着互联网行业的蓬勃发展和编程技术的普及&#xff0c;越来越多的人开始对编程感兴趣。然而&#xff0c;编程学习并非一蹴而就&#xff0c;新手入门时常常会陷入误区&#xff0c;影响学习状态效率。 今天&#xff0c;我们来一起揭开编程学习常见的五大误区&#xff0c;希望能…

【融合ChatGPT等AI模型】Python-GEE遥感云大数据分析、管理与可视化及多领域案例应用

随着航空、航天、近地空间遥感平台的持续发展&#xff0c;遥感技术近年来取得显著进步。遥感数据的空间、时间、光谱分辨率及数据量均大幅提升&#xff0c;呈现出大数据特征。这为相关研究带来了新机遇&#xff0c;但同时也带来巨大挑战。传统的工作站和服务器已无法满足大区域…

如何激活typora

话不多说&#xff0c;直接上流程。 1、先下载最新的typora安装包&#xff0c;并安装成功。 Typora的安装 &#xff08;1&#xff09;官网下载&#xff1a;https://typora.xnxxxk.cn/index.html?qhclickid777dd93d58082a46 2、下载百度云我上传的两个exe&#xff0c;不大&…

嵌入式实验---实验五 串口数据接收实验

一、实验目的 1、掌握STM32F103串口数据接收程序设计流程&#xff1b; 2、熟悉STM32固件库的基本使用。 二、实验原理 1、STM32F103R6能通过查询中断方式接收数据&#xff0c;每接收到一个字节&#xff0c;立即向对方发送一个相同内容的字节&#xff0c;并把该字节的十六进…

Dahlia Hart: Stylized Casual Character(休闲角色模型)

此包包含两个发型和两个服装&#xff0c;每个都有多种颜色选择。每个发型都适合与物理资源一起使用&#xff0c;并包含各种表情和音素混合形状。 下载&#xff1a;​​Unity资源商店链接资源下载链接 效果图&#xff1a;

【机器学习】大模型训练的深入探讨——Fine-tuning技术阐述与Dify平台介绍

目录 引言 Fine-tuning技术的原理阐 预训练模型 迁移学习 模型初始化 模型微调 超参数调整 任务设计 数学模型公式 Dify平台介绍 Dify部署 创建AI 接入大模型api 选择知识库 个人主页链接&#xff1a;东洛的克莱斯韦克-CSDN博客 引言 Fine-tuning技术允许用户根…

数据分析-常用模型-RFM模型

一、RFM模型的底层逻辑 漏斗模型中&#xff0c;大部分业务都是按流程推进&#xff0c;可以做漏斗分析。但是&#xff0c;大家有没有想过一个问题&#xff1a; 如果没有转化过程记录&#xff0c;该怎么办&#xff1f;如果用户行为频率很高&#xff0c;有几十个漏斗&#xff0c…

[数据库]索引机制

目录 索引机制 索引的类型 索引使用 哪些适合添加索引 ​编辑 索引机制 当没有索引的时候, 如下示例,在找到id等于1的时候, 仍然会往下继续查找, 进行全表扫描, 因为它认为下面也有可能还会有1 加上索引之后进行二叉树查找, 找到1之后, 发现1的左边没有了, 右边也没有了就停…

【项目实战】Android Studio简单实现图书馆借阅管理系统

希望文章能给到你启发和灵感&#xff5e; 点赞收藏关注 支持一下吧&#xff5e; 阅读指南 序幕一、基础环境说明1.1 硬件环境1.2 软件环境 二、整体设计2.1 数据库逻辑处理&#xff1a;2.2 登录/注册模块2.3 功能界面初始化&#xff1a;2.4 图书管理模块2.5 图书租借服务2.6 读…

钡铼BL104智慧环保多个485采集转MQTT无线传输

PLC物联网关BL104是一款专为工业环境设计的先进协议转换网关&#xff0c;其集成了钡铼智能技术和环保多个485采集转MQTT无线传输功能&#xff0c;为工业控制系统提供了高效的数据采集、传输和管理解决方案。 技术规格与功能特点 PLC物联网关BL104采用钡铼智能技术&#xff0c…

一招教你用python代码给朋友写一个爱心代码

有人问我马上要跟女朋友一周年了&#xff0c;能不能用代码给他写一个爱心代码呢&#xff1f;那算你问对人了&#xff0c;来上才艺 可以使用Python的turtle模块来绘制一个爱心形状。下面是一个简单的示例代码&#xff0c;我将详细解释每一步&#xff1a; import turtle # 创建一…

回溯法基本思想-01背包、N皇后回溯法图解

基本思想&#xff1a; ​ 回溯法是一种系统地搜索问题解空间的算法&#xff0c;常用于解决组合优化和约束满足问题。其核心思想是利用深度优先搜索逐步构建可能的解&#xff0c;同时在搜索过程中进行剪枝操作&#xff0c;以排除那些无法满足问题约束或不能产生最优解的分支&am…

js修改scss变量

style.scss $color : var(--color,#ccc); // 默认值 #ccc .color{background: $color; } 定义了一个scss变量&#xff08;$color&#xff09;&#xff0c;用普通的css变量&#xff08;--color&#xff09;给他赋值&#xff0c;这里需要一个默认值&#xff0c;此时css变量(--co…

数据结构复习指南

数据结构复习指南 本文中列举了数据结构期末考试可能存在的考点 绪论 数据的基本单位 数据元素是数据的基本单位 数据项 数据项是组成数据的、有独立含义的、不可分割的最小单位。 数据对象 数据对象是性质相同的数据元素的集合&#xff0c;是数据的一个子集。 数据结…

如何借助ai(文心一言)获取tushare的数据

1. 准备工作 确保已安装python &#xff0c;安装Tushare库 和文心一言的地址&#xff08;文心一言&#xff09;&#xff1a; 注册Tushare账号并获取Token&#xff1a;在Tushare官方网站注册账号&#xff0c;并获取个人Token。如下 tushare地址&#xff1a;&#xff08;点击即…