消息队列的主要功能:流量削峰、

       如果订单系统最多能处理一万次订单,这个处理能力应付正常时段的下单时绰绰有余,正常时段我们下单一秒后就能返回结果。但是在高峰期,如果有两万次下单操作系统是处理不了的,只能限制订单超过一万后不允许用户下单。使用消息队列做缓冲,我们可以取消这个限制,把一秒内下的订单分散成一段时间来处理,这时有些用户可能在下单十几秒后才能收到下单成功的操作,但是比不能下单的体验要好。

应用解耦:

消息队列可以直接调用后端数据吗 消息队列支持多少数据_spring

异步处理:

消息队列可以直接调用后端数据吗 消息队列支持多少数据_spring_02

 常用的消息队列:

 kafka:通常是大数据的处理

RocketMQ: 非常靠谱,一般是金融级别的无法

rabbitMq: 当前最主流的消息中间件之一。结合erlang语言本身的并发优势,性能好时效性微秒级,社区活跃度也比较高,管理界面用起来十分方便,如果你的数据量没有那么大,中小型公司优先选择功能比较完备的RabbitMQ;

四大核心概念:

生产者
交换机:一方面它接收来自生产者的消息,另一方面它将消息推送到队列中。交换机必须确切知道如何处理它接收到的消息,是将这些消息推送到特定队列还是推送到多个队列,亦或者是把消息丢弃,这个得有交换机类型决定
队列:队列是RabbitMQ内部使用的一种数据结构,尽管消息流经RabbitMQ和应用程序,但它们只能存储在队列中。队列仅受主机的内存和磁盘限制的约束,本质上是一个大的消息缓冲区
消费者
Downloading and Installing RabbitMQ — RabbitMQ

安装

拉取镜像:

docker pull rabbitmq:3.8.12-management-alpine

启动:

docker run -d --hostname rabbit_host1 --name xd_rabbit -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=password -p 15672:15672 -p 5672:5672 rabbitmq:3.8.12-management-alpine

消息队列可以直接调用后端数据吗 消息队列支持多少数据_消息队列_03

消息队列可以直接调用后端数据吗 消息队列支持多少数据_消息队列_04

  

消息队列可以直接调用后端数据吗 消息队列支持多少数据_消息队列可以直接调用后端数据吗_05

浏览器访问:       ip:15672

 rabbitMQ 的基本概念

 1、TTL  存活时间

time to live 消息存活时间,如果在存活时间内没有被消费,就会被清除

2、RabbitMQ 支持两种ttl

   单独消息进行ttl配置

  整个队列进行配置ttl(居多)

3、什么是死信队列

     没有被及时消费的消息存放的队列

4、死信交换机

     当消息成为死信后,会被重新发送到另一个交换机,这个交换机就是死信交换机

                 

消息队列可以直接调用后端数据吗 消息队列支持多少数据_java_06

消息有哪几种情况会成为死信:

1、消费者拒收消息(basic.reject/basic.nack),并且没有重新入队requeue = false;

2、消息在队列中未被消费,且超过队列或者消息本身的过期时间TTL

3、队列的消息长度达到极限

注意,消息成为死信后,如果该队列绑定了死信交换机,则消息会被死信交换机重新路由到死信队列。

延迟队列:

一种带有延迟功能的消息队列,producer 将消息发送到消息队列的服务端后,但是并不希望这条消息被立马投递,而是推迟到在当前时间点之后的某一个时间投递到消费者,该消息即定时消息;

 rocketMQ 自带延迟队列的功能,但是rabbitMQ 没有,通过死信队列实现延迟功能

如下:消费者直接监听死信队列;

消息队列可以直接调用后端数据吗 消息队列支持多少数据_消息队列_07

 使用RabbitMQ

1、导入依赖

<!--消息队列-->
        <dependency>
             <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

 2、各个项目中添加配置(spring 下的配置)

# 消息队列
  rabbitmq:
    host: 47.100.54.149
    port: 5672
    virtual-host: /
    username: admin
    password: password
    # 开启手动确认消息
    listener:
      simple:
        acknowledge-mode: manual

3、建立配置文件以及配置类

mqconfig:
  # 延迟队列,不能被监听消费
  coupon_release_delay_queue: coupon.release.delay.queue
  # 延迟队列的消息过期后转发的队列
  coupon_release_queue: coupon.release.queue
  # 交换机
  coupon_event_exchange: coupon.event.exchange
  # 进入延迟队列的路由key
  coupon_release_delay_routing_key: coupon.release.delay.routing.key
  # 消息过期,进入释放死信队列的key
  coupon_release_routing_key: coupon.release.routing.key
  # 消息过期的时间,毫秒
  ttl: 15000
@Configuration
@Data
public class RabbitMqconfig {

    /**
     * 交换机
     */
    @Value("${mqconfig.coupon_event_exchange}")
    private String eventExchange;

    /**
     * 第一个队列  延迟队伍
     */
    @Value("${mqconfig.coupon_release_delay_queue}")
    private String couponReleaseDelayQueue;

    /**
        * 第一个队列的路由key
        * 进入队列的路由key
    */
    @Value("${mqconfig.coupon_release_delay_routing_key}")
    private String couponReleaseDelayRoutingKey;

    /**
         * 第二个队列,被监听恢复库存的队伍
    */
    @Value("${mqconfig.coupon_release_queue}")
    private String couponReleaseQueue;

    /**
     * 第二个队列的路由key
     * 即进入死信队列的路由key
     */

    @Value("${mqconfig.coupon_release_routing_key}")
    private String couponReleaseRoutingKey;

    /**
     * 过期时间
     */
    @Value("${mqconfig.ttl}")
    private Integer ttl;

    /**
     * 消息转换器
     * @return
     */
    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }

    /**
     * 定义交换机
     * Topic 类型,也可以是direct路由
     * 一般一个微服务一个交换机
     * @return
     */
    @Bean
    public Exchange couponEventExchange(){
        return new TopicExchange(eventExchange,true,false);
    }

    /**
     * 延迟队列
     */
    @Bean
    public Queue couponReleaseDelayQueue(){
        Map<String,Object> args = new HashMap<>();
        args.put("x-message-ttl",ttl);
        args.put("x-dead-letter-routing-key",couponReleaseRoutingKey);
        args.put("x-dead-letter-exchange",eventExchange);

        return new Queue(couponReleaseDelayQueue,true,false,false,args);
    }
    /**
     * 死信队列
     */
     @Bean
    public Queue coupponReleaseQueue(){
         return new Queue(couponReleaseQueue,true,false,false);

     }

    /**
     * 死信队列绑定关系建立
     * 建立队列与交换机的绑定
     * @return
     */
    @Bean
    public Binding couponReaseBinding(){
        return new Binding(couponReleaseQueue,Binding.DestinationType.QUEUE,eventExchange,couponReleaseRoutingKey,null);
     }

    /**
     * 第一个队列即延迟队列的绑定关系建立
     * 建立队列与交换机的绑定
     * @return
     */
    @Bean
    public Binding couponReaseDelayBinding(){
        return new Binding(couponReleaseDelayQueue,Binding.DestinationType.QUEUE,eventExchange,couponReleaseDelayRoutingKey,null);
    }
}
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class MQtest {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void sendDelayMsg(){
        // 发送消息,有三个参数,分别是交换机、路由key 消息体
        rabbitTemplate.convertAndSend("coupon.event.exchange","coupon.release.delay.routing.key","this is a coupon ");
    }
}