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.rhkb.cn/news/364462.html

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

相关文章

HBuilder X 小白日记02-布局和网页背景颜色

html&#xff1a; 例子1&#xff1a; 整个&#xff1a; css案例&#xff1a; 1.首先右键&#xff0c;创建css文件 2.在html文件的头部分&#xff0c;引用css&#xff0c;快捷方式&#xff1a;linkTab键 <link rel"stylesheet" href" "> 3.先在css…

3.3V到5V的负电源产生电路(电荷泵电压反相器)SGM3204输出电流0.2A封装SOT23-6

前言 SGM3204 非稳压 200mA 电荷泵负电源产生电路&#xff0c;LCEDA原理图请访问资源 SGM3204电荷泵负电源产生电路 SGM3204电荷泵负电源产生电路 一般描述 SGM3204从 1.4V 至 5.5V 的输入电压范围产生非稳压负输出电压。 该器件通常由 5V 或 3.3V 的预稳压电源轨供电。由于…

Camera Raw:增强

Camera Raw 中的增强 Enhance命令基于 AI 技术提升图像的质量&#xff0c;可用于降噪、生成清晰的细节以及提高图像的分辨率。 ◆ ◆ ◆ 主要用途 1、高 ISO 图像降噪 勾选“去杂色” Denoise&#xff0c;可轻松消除使用高 ISO 设置或在低光环境下拍摄的照片中的噪点。 可以对…

MySQL之如何处理超大分页

如何处理MySQL超发分页&#xff1f; 可以使用覆盖索引解决 【点击进入】 MySQL超大分页处理 在数据量较大时&#xff0c;如果使用limit分页查询&#xff0c;在查询时&#xff0c;越往后&#xff0c;分页查询效率会越低。 示例&#xff1a; select * from user limit 900000…

小白学webgl合集-WebGL中给图片添加背景

一.实现效果 二.逻辑 为了在WebGL中给图片添加背景&#xff0c;主要的逻辑步骤包括初始化WebGL上下文、编写和编译着色器、创建和绑定缓冲区、加载和配置纹理以及绘制场景。以下是代码逻辑的详细说明&#xff1a; 1. 获取WebGL上下文 首先&#xff0c;通过获取<canvas>…

汽车电子工程师入门系列——CAN 规范系列通读

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…

互联网大厂核心知识总结PDF资料

我们要敢于追求卓越&#xff0c;也能承认自己平庸&#xff0c;不要低估3&#xff0c;5&#xff0c;10年沉淀的威力 hi 大家好&#xff0c;我是大师兄&#xff0c;大厂工作特点是需要多方面的知识和技能。这种学习和积累一般人需要一段的时间&#xff0c;不太可能一蹴而就&…

Java | Leetcode Java题解之第206题反转链表

题目&#xff1a; 题解&#xff1a; class Solution {public ListNode reverseList(ListNode head) {if (head null || head.next null) {return head;}ListNode newHead reverseList(head.next);head.next.next head;head.next null;return newHead;} }

【Qt】QMessageBox 各种对话框的默认显示效果

1. 函数原型 void about(QWidget *parent, const QString &title, const QString &text)void aboutQt(QWidget *parent, const QString &title QString())QMessageBox::StandardButton critical(QWidget *parent, const QString &title, const QString &…

ONLYOFFICE 8.1版本桌面编辑器测评:重塑办公效率的巅峰之作

在数字化办公日益普及的今天&#xff0c;一款高效、便捷且功能强大的桌面编辑器成为了职场人士不可或缺的工具。ONLYOFFICE 8.1版本桌面编辑器凭借其卓越的性能和丰富的功能&#xff0c;成功吸引了众多用户的目光。今天&#xff0c;我们将对ONLYOFFICE 8.1版本桌面编辑器进行全…

v0.9.6 开源跨平台个人知识管理工具 TidGi-Desktop

在这个信息爆炸的时代&#xff0c;知识管理变得尤为重要。太记(TidGi)&#xff0c;一款基于太微(TiddlyWiki)的知识管理桌面应用&#xff0c;正是为了满足人们对信息整理、知识管理和个人隐私保护的需求而设计的。它不仅能够帮助用户高效地管理和整理信息&#xff0c;还能够自动…

C语言 | Leetcode C语言题解之第205题同构字符串

题目&#xff1a; 题解&#xff1a; struct HashTable {char key;char val;UT_hash_handle hh; };bool isIsomorphic(char* s, char* t) {struct HashTable* s2t NULL;struct HashTable* t2s NULL;int len strlen(s);for (int i 0; i < len; i) {char x s[i], y t[i]…

ElementUI的基本搭建

目录 1&#xff0c;首先在控制终端中输入下面代码&#xff1a;npm i element-ui -S 安装element UI 2&#xff0c;构架登录页面&#xff0c;login.vue​编辑 3&#xff0c;在官网获取对应所需的代码直接复制粘贴到对应位置 4&#xff0c;在继续完善&#xff0c;从官网添加…

“论软件系统架构评估”写作框架,软考高级论文,系统架构设计师论文

论文真题 对于软件系统&#xff0c;尤其是大规模的复杂软件系统来说&#xff0c;软件的系统架构对于确保最终系统的质量具有十分重要的意义&#xff0c;不恰当的系统架构将给项目开发带来高昂的代价和难以避免的灾难。对一个系统架构进行评估&#xff0c;是为了:分析现有架构存…

定时触发-uniapp + uniCloud 订阅消息实战教程(三)

上一节已经对云函数有了一定的了解,但是,为了发送订阅消息,只会云函数还是差了那么一点意思,所以接下来的这一节,将带领大家熟悉一下定时触发。 熟悉定时触发 如果云函数需要定时/定期执行,即定时触发,您可以使用云函数定时触发器。已配置定时触发器的云函数,会在相应…

基于C语言的Jacobi迭代和Gauss-Seidel迭代的方程组求解实现

文章目录 Jacobi迭代方法介绍Gauss-Seidel迭代方法介绍具体代码实现示例题目实现效果 Jacobi迭代方法介绍 Jacobi迭代法是一种简单的迭代求解方法&#xff0c;适用于严格对角占优矩阵。其基本思想是利用当前迭代步的已知解来更新下一个迭代步的解。在C语言实现中&#xff0c;我…

什么是入侵检测系统:综合指南

在网络安全领域&#xff0c;入侵检测系统 (IDS) 长期以来一直是防御威胁的基石。但由于技术在不断发展&#xff0c;绕过它们的技术也在不断发展&#xff0c;因此评估它们是否足以保护系统是至关重要的。 在这篇综合指南中会深入探讨了 IDS 的复杂性&#xff0c;彻底了解了其功…

策略模式(Strategy Pattern)

策略模式 &#xff08;Strategy Pattern&#xff09; 定义 它是将定义的算法家族、分别封装起来&#xff0c;让它们之间可以相互替换&#xff0c;从而让算法的变化不会影响到使用算法的用户。 可以避免多重分支的 if-else、switch语句。 属于行为型模式。 适用场景 如果系…

Redis-在springboot环境下执行lua脚本

文章目录 1、什么lua2、创建SpringBoot工程3、引入相关依赖4、创建LUA脚本5、创建配置类6、创建启动类7、创建测试类 1、什么lua “Lua”的英文全称是“Lightweight Userdata Abstraction Layer”&#xff0c;意思是“轻量级用户数据抽象层”。 2、创建SpringBoot工程 3、引入相…

.net core 的 winform 的 浏览器控件 WebView2

在.NET Core WinForms应用程序中&#xff0c;没有直接的“浏览器控件”&#xff0c;因为WinForms不支持像WebBrowser控件那样的功能。但是&#xff0c;你可以使用WebView2控件&#xff0c;它是一个基于Chromium的浏览器内核&#xff0c;可以在WinForms应用程序中嵌入Web内容。 …