12. 消息 消息总线 Bus

简介

在微服务架构中,我们通常会使用轻量级的消息代理来构建一个共用的消息主题让系统中所有微服务实例都连接,由于该主题中产生的消息会被所有实例监听和消费,所以我们称它为消息总线。在总线上的各个实例都可以方便的广播一些需要让其他连接在该主题上的实例都知道的消息,例如配置信息的变更或者其他一些管理操作。

消息代理(Message Broker)是一种消息验证、传输、路由的架构模式。它在应用程序之间进行通信调度并最小化应用之间的依赖,使得应用程序可以高效地解耦通信过程。

消息代理是一个中间件产品,它的核心是一个消息的路由程序,用来实现接收和分发消息,并根据设定好的消息处理流来转发给正确的应用。它包括独立的通信和消息传递协议,可以在组织内部和组织之间进行通信。设计代理的目的就是为了能够从应用程序中传入消息,并执行一些特别的操作。
在这里插入图片描述
Config Server使用了Spring Cloud Bus后会对外提供一个HTTP接口叫做/bus-refresh,访问这个接口就会将最新的信息发送到Mq。那么谁访问这个接口呢,既然期望的是Git文件变更就发送消息 那么当然是由Git访问更加合适了。

什么时候用cloud bus

spring cloud bus在整个后端服务中起到联通的作用,联通后端的多台服务器。我们为什么需要他做联通呢?

后端服务器一般都做了集群化,很多台服务器,而且在大促活动期经常发生服务的扩容、缩容、上线、下线。这样,后端服务器的数量、IP就会变来变去,如果我们想进行一些线上的管理和维护工作,就需要维护服务器的IP。

比如我们需要更新配置、比如我们需要同时失效所有服务器上的某个缓存,都需要向所有的相关服务器发送命令,也就是调用一个接口。

你可能会说,我们一般会采用zookeeper的方式,统一存储服务器的ip地址,需要的时候,向对应服务器发送命令。这是一个方案,但是他的解耦性、灵活性、实时性相比消息总线都差那么一点。

总的来说,就是在我们需要把一个操作散发到所有后端相关服务器的时候,就可以选择使用cloud bus了。

开发步骤

手动刷新

1.Config服务-添加Bus的依赖

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

2.pom文件添加RabbitMq的配置

rabbitmq:
    host: localhost
    port: 5672
    username: admin
    password: 123456

3.启动配置,查看RabbitMq的Web页面,其中有Bus的队列
在这里插入图片描述
4.Order服务(Config的客户端)-同样引入依赖,pom文件配置RabbitMq,启动后RabbitMq多了一个队列
在这里插入图片描述5.之前有写过接口可以访问Git配置文件的env属性,首先访问是dev,git中配置文件修改为dev2后访问还是dev
在这里插入图片描述在这里插入图片描述
原因是之前说的需要访问下Config的/bus-refresh,但是Config是没这个接口的,所以需要在Config Server 的 pom文件中配置将这个接口暴露出来

# 允许/actuator/bus-refresh接口被外部调用
management:
  endpoints:
    web:
      exposure:
        include: "*"

6.然后在order服务 Controller上面添加@RefreshScope注解,@RefreshScope就是刷新范围,env的值是直接在这个Controller获取的,所以要刷新这个Controller

7.先访问Config Server的/actuator/bus-refresh接口去刷新配置(post),可以看到RabbitMq Config队列有了一条消息
在这里插入图片描述
重新访问 值发生改变
在这里插入图片描述
8.如果此时有两个Config Client 服务,而我们只想让其中一个Client刷新,那么需要在这个Client中配置:

spring.application.name=order
eureka.instance.instance-id=${spring.application.name}:${server.port}

然后在请求/bus/refresh时,后面添加参数/bus/refresh?destination=order:8081

配置自动刷新
1.首先配置Git Webhooks,其中URL必须是外网可以访问的,可以使用natapp.cn下载内网穿透工具
在这里插入图片描述
2.修改git文件就会访问Config Server的/actuator/bus-refresh接口,然后就刷新Order值发生修改。

但是呢,这个自动配置有个坑,就是在访问Config Server的/actuator/bus-refresh接口时候是会报400,原因:
因为GitHub在进行post请求的同时默认会在body加上一串载荷(payload)

{
  "ref": "refs/heads/master",
  "before": "c34de85d9488373f09b0d7a32c03c1cc43039bfa",
  "after": "7f31e5860beb93f81376bd788c46906211b0b394",
  "created": false,
  "deleted": false,
  "forced": false,
  "base_ref": null,
  "compare": "https://github.com/Tinysakura/practice-config-repo/compare/c34de85d9488...7f31e5860beb",
  .........
}

于是我们的spring boot因为无法正常反序列化这串载荷而报了400错误:

Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.lang.String` out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_ARRAY token

解决方法就是修改body

public class ConfigRequestWrapper extends HttpServletRequestWrapper{

    public ConfigRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        byte[] bytes = new byte[0];
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);

        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return byteArrayInputStream.read() == -1 ? true:false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }

            @Override
            public int read() throws IOException {
                return byteArrayInputStream.read();
            }
        };
    }

}
@Component
public class ConfigFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse)servletResponse;

        String url = new String(httpServletRequest.getRequestURI());

        //只过滤/actuator/bus-refresh请求
        if (!url.endsWith("/bus-refresh")) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        //获取原始的body
        String body = ReadAsChars(httpServletRequest);


        //使用HttpServletRequest包装原始请求达到修改post请求中body内容的目的
        ConfigRequestWrapper requestWrapper = new ConfigRequestWrapper(httpServletRequest);

        filterChain.doFilter(requestWrapper, servletResponse);

    }


    /**
     * 获取request中的Body
     * @param request
     * @return
     */
    public String ReadAsChars(HttpServletRequest request)
    {

        BufferedReader br = null;
        StringBuilder sb = new StringBuilder("");
        try
        {
            br = request.getReader();
            String str;
            while ((str = br.readLine()) != null)
            {
                sb.append(str);
            }
            br.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != br)
            {
                try
                {
                    br.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Spring Cloud Bus是一个用于在分布式系统中传播状态变化的消息总线。它基于Spring Cloud Stream和Spring Cloud Config构建,可以将消息广播到整个系统中的所有服务实例。通过使用Spring Cloud Bus,可以实现配置的动态刷新、事件的传播和集群中的状态同步。 下面是使用Spring Cloud Bus自定义消息总线的步骤: 1. 添加依赖:在项目的pom.xml文件中添加Spring Cloud Bus的依赖: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency> ``` 2. 配置消息代理:在应用的配置文件中配置消息代理,例如使用RabbitMQ作为消息代理: ```yaml spring: rabbitmq: host: localhost port: 5672 username: guest password: guest ``` 3. 发送自定义消息:在需要发送自定义消息的地方,使用Spring Cloud Bus提供的API发送消息。例如,可以使用`/actuator/bus-refresh`端点发送刷新配置的消息: ```shell curl -X POST http://localhost:8080/actuator/bus-refresh ``` 4. 接收自定义消息:在需要接收自定义消息的地方,使用Spring Cloud Bus提供的注解和监听器来接收消息。例如,可以使用`@RefreshScope`注解来刷新配置: ```java @RefreshScope @RestController public class ConfigController { // ... } ``` 通过以上步骤,您可以使用Spring Cloud Bus自定义消息总线来实现配置的动态刷新、事件的传播和集群中的状态同步。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值