Spring cloud-Bus (消息总线)

来源:互联网 发布:淘宝远程解锁什么原理 编辑:程序博客网 时间:2024/04/19 16:42

1、消息总线

消息总线是一种通信工具,可以在机器之间互相传输消息、文件等。消息总线扮演着一种消息路由的角色,拥有一套完备的路由机制来决定消息传输方向。发送段只需要向消息总线发出消息而不用管消息被如何转发。

Spring cloud bus 通过轻量消息代理连接各个分布的节点。管理和传播所有分布式项目中的消息,本质是利用了MQ的广播机制在分布式的系统中传播消息,目前常用的有Kafka和RabbitMQ。

下面是一个配置中心刷新配置的例子

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


2、消息代理

消息代理(Message Broker)是一种消息验证、传输、路由的架构模式。消息代理是一个中间件产品,它的核心是一个消息的路由程序,用来实现接收和分发消息,并根据设定好的消息处理流来转发给正确的应用。它包括独立的通信和消息传递协议,能够实现组织内部和组织间的网络通信。设计代理的目的就是为了能够从应用程序中传入消息,并执行一些特别的操作。

现有的消息代理开源产品:

ActiveMQ

Kafka

RabbitMQ

RocketMQ


目前Spring Cloud Bus 支持 RabbitMQ 和 Kafka,spring-cloud-starter-bus-amqp 、spring-cloud-starter-bus-kafka

3、RabbitMQ

RabbitMQ是一个由erlang开发的AMQP的开源实现。

AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。

AMQP 是一个线路协议,只要符合该数据格式的消息发送和接收组件都能相互兼容,能够轻易实现跨技术平台架构。

Github:https://github.com/rabbitmq

官网地址:http://www.rabbitmq.com

RabbitMQ基础概念:

ConnectionFactory、Connection、Channel

ConnectionFactory、Connection、Channel都是RabbitMQ对外提供的API中最基本的对象。Connection是RabbitMQ的socket链接,它封装了socket协议相关部分逻辑。ConnectionFactory为Connection的制造工厂。
Channel是我们与RabbitMQ打交道的最重要的一个接口,我们大部分的业务操作是在Channel这个接口中完成的,包括定义Queue、定义Exchange、绑定Queue与Exchange、发布消息等。

Queue

Queue(队列)是RabbitMQ的内部对象,用于存储消息。

Message acknowledgment

      在实际应用中,可能会发生消费者收到Queue中的消息,但没有处理完成就宕机(或出现其他意外)的情况,这种情况下就可能会导致消息丢失。为了避免这种情况发生,我们可以要求消费者在消费完消息后发送一个回执给RabbitMQ,RabbitMQ收到消息回执(Message acknowledgment)后才将该消息从Queue中移除。

Message durability

      如果我们希望即使在RabbitMQ服务重启的情况下,也不会丢失消息,我们可以将Queue与Message都设置为可持久化的(durable),这样可以保证绝大部分情况下我们的RabbitMQ消息不会丢失。

Prefetch count

前面我们讲到如果有多个消费者同时订阅同一个Queue中的消息,Queue中的消息会被平摊给多个消费者。这时如果每个消息的处理时间不同,就有可能会导致某些消费者一直在忙,而另外一些消费者很快就处理完手头工作并一直空闲的情况。我们可以通过设置prefetchCount来限制Queue每次发送给每个消费者的消息数,比如我们设置prefetchCount=1,则Queue每次给每个消费者发送一条消息;消费者处理完这条消息后Queue会再给该消费者发送一条消息。

Exchange

生产者将消息发送到Exchange(交换器),由Exchange将消息路由到一个或多个Queue中(或者丢弃)。

Routing key

生产者在将消息发送给Exchange的时候,一般会指定一个routing key,来指定这个消息的路由规则,而这个routing key需要与Exchange Type及binding key联合使用才能最终生效。
在Exchange Type与binding key固定的情况下(在正常使用时一般这些内容都是固定配置好的),我们的生产者就可以在发送消息给Exchange时,通过指定routing key来决定消息流向哪里

Binding

RabbitMQ中通过Binding将Exchange与Queue关联起来,这样RabbitMQ就知道如何正确地将消息路由到指定的Queue了。

Binding key

在绑定(Binding)Exchange与Queue的同时,一般会指定一个binding key;生产者将消息发送给Exchange时,一般会指定一个routing key;当binding key与routing key相匹配时,消息将会被路由到对应的Queue中。
在绑定多个Queue到同一个Exchange的时候,这些Binding允许使用相同的binding key。 binding key 并不是在所有情况下都生效,它依赖于Exchange Type,比如fanout类型的Exchange就会无视binding key,而是将消息路由到所有绑定到该Exchange的Queue。

Exchange Type

RabbitMQ常用的Exchange Type有fanout、direct、topic、headers这四种。

fanout

fanout类型的Exchange会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中。

direct

direct类型的Exchange会把消息路由到那些binding key与routing key完全匹配的Queue中。

topic

direct类型的Exchange路由规则是完全匹配binding key与routing key,但这种严格的匹配方式在很多情况下不能满足实际业务需求。topic类型的Exchange在匹配规则上进行了扩展,它与direct类型的Exchage相似,也是将消息路由到binding key与routing key相匹配的Queue中。

      1. routing key为一个句点号“. ”分隔的字符串(我们将被句点号“. ”分隔开的每一段独立的字符串称为一个单词),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”
      2. binding key与routing key一样也是句点号“. ”分隔的字符串
      3. binding key中可以存在两种特殊字符“*”与“#”,用于做模糊匹配,其中“*”用于匹配一个单词,“#”用于匹配多个单词(可以是零个)

routingKey=”quick.orange.rabbit”的消息会同时路由到Q1与Q2,routingKey=”lazy.orange.fox”的消息会路由到Q1,routingKey=”lazy.brown.fox”的消息会路由到Q2,routingKey=”lazy.pink.rabbit”的消息会路由到Q2(只会投递给Q2一次,虽然这个routingKey与Q2的两个bindingKey都匹配);routingKey=”quick.brown.fox”、routingKey=”orange”、routingKey=”quick.orange.male.rabbit”的消息将会被丢弃,因为它们没有匹配任何bindingKey。

headers

headers类型的Exchange不依赖于routing key与binding key的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。
在绑定Queue与Exchange时指定一组键值对;当消息发送到Exchange时,RabbitMQ会取到该消息的headers(也是一个键值对的形式),对比其中的键值对是否完全匹配Queue与Exchange绑定时指定的键值对;如果完全匹配则消息会路由到该Queue,否则不会路由到该Queue。

RPC

MQ本身是基于异步的消息处理,前面的示例中所有的生产者(P)将消息发送到RabbitMQ后不会知道消费者(C)处理成功或者失败(甚至连有没有消费者来处理这条消息都不知道)。
但实际的应用场景中,我们很可能需要一些同步处理,需要同步等待服务端将我的消息处理完成后再进行下一步处理。这相当于RPC(Remote Procedure Call,远程过程调用)。在RabbitMQ中也支持RPC。

      1. 客户端发送请求(消息)时,在消息的属性(MessageProperties,在AMQP协议中定义了14中properties,这些属性会随着消息一起发送)中设置两个值replyTo(一个Queue名称,用于告诉服务器处理完成后将通知我的消息发送到这个Queue中)和correlationId(此次请求的标识号,服务器处理完成后需要将此属性返还,客户端将根据这个id了解哪条请求被成功执行了或执行失败)
      2. 服务器端收到消息并处理
      3. 服务器端处理完消息后,将生成一条应答消息到replyTo指定的Queue,同时带上correlationId属性
      4. 客户端之前已订阅replyTo指定的Queue,从中收到服务器的应答消息后,根据其中的correlationId属性分析哪条请求被执行了,根据执行结果进行后续业务处理

4、spring boot整合RabbitMQ

4.1、添加依赖spring-boot-starter-amqp


pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>


4.2、在配置文件中增加关于RabbitMQ的连接和用户信息


application.properties
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=springcloud
spring.rabbitmq.password=123456



4.3、创建消息生产者和消费者


Sender
@Component
public class Sender {
 
    @Autowired
    private AmqpTemplate rabbitTemplate;
 
    public void send() {
        String context = "hello " new Date();
        System.out.println("Sender : " + context);
        this.rabbitTemplate.convertAndSend("hello", context);
    }
 
}



Receiver
@Component
@RabbitListener(queues = "hello")
public class Receiver {
 
    @RabbitHandler
    public void process(String hello) {
        System.out.println("Receiver : " + hello);
    }
 
}


4.4、创建配置类,进行队列、交换器、路由的配置


@Configuration
public class RabbitConfig {
 
    @Bean
    public Queue helloQueue() {
        return new Queue("hello");
    }
 
}

4.5、在原有的CarController方法中生产消息

@RequestMapping(value = "/car", method = RequestMethod.GET)
public String hello() {
    logger.info("car " + carNo);
    sender.send();
    return "car " + carNo;
}

5、Spring Cloud Bus整合RabbitMQ

5.1、将spring-boot-starter-amqp 改为 spring-cloud-starter-bus-amqp

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

5.2、使用@RefreshScope 注解刷新范围

@RefreshScope
@RestController
public class CarController {
 
    @Value("${car.no}")
    private String carNo;
 
    private final Logger logger = Logger.getLogger(getClass());
 
    @RequestMapping(value = "/car", method = RequestMethod.GET)
    public String hello() {
        logger.info("car " + carNo);
        return "car " + carNo;
    }
 
    @RequestMapping(value = "/car", method = RequestMethod.POST)
    public String hello(@RequestBody Car car) {
        logger.info("car " + carNo);
        return "car " + carNo;
    }
 
}


5.3、通过指定profile 启动两个服务,端口分别为8081、8082,–spring.profiles.active=test1 --spring.profiles.active=test1 

默认配置

car.no=rabbit 

启动之后访问http://127.0.0.1:8081/car 、http://127.0.0.1:8082/car  返回 car rabbit

默认 spring cloud bus 会创建默认的 Exchange,类型为topic

并绑定默认的queue

5.4、使用post 请求http://127.0.0.1:8081/bus/env?car.no=777777 ,更新car.no 为777777;

         

        使用post请求http://127.0.0.1:8081/bus/refresh 刷新配置,

再访问http://127.0.0.1:8081/car 、http://127.0.0.1:8082/car,返回 car 777777

         

    

6、DEMO源码

cloudbus.rar


参考:http://cloud.spring.io/

http://www.cnblogs.com/ityouknow/p/6931958.html

http://blog.didispace.com/springcloud7/

阅读全文
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 速腾油箱盖打不开怎么办 奥迪a6油箱盖打不开怎么办 苹果手提虚拟机黑屏怎么办 mac系统桌面变大怎么办 删除文件要权限怎么办 页面载入错误了怎么办 手机打不开excel表格怎么办 皇室战争闪退怎么办 苹果老是闪退怎么办 黑苹果开机黑屏怎么办 MAC磁盘删了怎么办 mac磁盘被锁定怎么办 bt5读不到网卡怎么办 笔记本电脑cpu温度过高怎么办 笔记本cpu温度过高怎么办 联想系统崩溃了怎么办 办公软件用不了怎么办 win10设置闪退怎么办 手机浏览器版本低怎么办 wps界面动不了怎么办 手机设置删了怎么办 苹果手机设置不见了怎么办 笔记本电脑键盘不好使怎么办 网咖怎么办临时卡 cydia添加雷锋源失败怎么办 电脑mac已锁定怎么办 苹果home键发热怎么办 苹果软件消失了怎么办 苹果键盘消失了怎么办 苹果图标消失了怎么办 超账户授权有误怎么办 华为账号码被盗怎么办 华为无法截屏怎么办 华为账号密码忘怎么办 华为忘记激活码怎么办 云充吧登录不上怎么办 充电器插头太松怎么办 充电器接口掉了怎么办 华为p9手机发烫怎么办 华为mate8不快充怎么办 小米6x充不进电怎么办