zoukankan      html  css  js  c++  java
  • 消息队列RabbitMQ基础知识详解

    一: 什么是MQ?

        MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序或者模块对模块的通信方法。MQ是消费-生产者模型的一个典型的代表,一端往消息队列中不断写入消息,而另一端则可以读取队列中的消息。

        常见的消息队列有RabbitMQ和kafka。下面详细介绍一下RabbitMQ的适用场景和基本概念。

    二: 适用场景

    2.1 并发处理

    (1)串行方式:将注册信息写入数据库后,发送注册邮件,再发送注册短信,以上三个任务全部完成后才返回给客户端。 这有一个问题是,邮件,短信并不是必须的,它只是一个通知,而这种做法让客户端等待没有必要等待的东西.

    消息队列RabbitMQ基础知识详解

    (2)并行方式:将注册信息写入数据库后,发送邮件的同时,发送短信,以上三个任务完成后,返回给客户端,并行的方式能提高处理的时间。

    消息队列RabbitMQ基础知识详解

        假设三个业务节点分别使用50ms,串行方式使用时间150ms,并行使用时间100ms。虽然并发已经提高了处理时间,但是,前面说过,邮件和短信对我们正常的使用网站没有任何影响,客户端没有必要等着其发送完成才显示注册成功,因而是写入数据库后就返回.

    (3)消息队列

        引入消息队列后,把发送邮件,短信不是必须的业务逻辑异步处理

    消息队列RabbitMQ基础知识详解

        由此可以看出,引入消息队列后,用户的响应时间就等于写入数据库的时间+写入消息队列的时间(可以忽略不计),引入消息队列后处理后,响应时间是串行的3倍,是并行的2倍。

    2.2 应用解耦

        场景:双11是购物狂节,用户下单后,订单系统需要通知库存系统,传统的做法就是订单系统调用库存系统的接口.

    消息队列RabbitMQ基础知识详解

      这种做法有一个缺点:

    • 当库存系统出现故障时,订单就会失败。(这样马云将少赚好多好多钱^ ^)
    • 订单系统和库存系统高耦合.
    • 引入消息队列
    消息队列RabbitMQ基础知识详解
    • 订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功。
    • 库存系统:订阅下单的消息,获取下单消息,进行库操作。
    • 就算库存系统出现故障,消息队列也能保证消息的可靠投递,不会导致消息丢失(马云这下高兴了).

    2.3: 流量削峰

      流量削峰一般在秒杀活动中应用广泛

      场景:秒杀活动,一般会因为流量过大,导致应用挂掉,为了解决这个问题,一般在应用前端加入消息队列。

    作用:

    1.可以控制活动人数,超过此一定阀值的订单直接丢弃(我为什么秒杀一次都没有成功过呢^^)

    2.可以缓解短时间的高流量压垮应用(应用程序按自己的最大处理能力获取订单)

    消息队列RabbitMQ基础知识详解

    1.用户的请求,服务器收到之后,首先写入消息队列,加入消息队列长度超过最大值,则直接抛弃用户请求或跳转到错误页面.

    2.秒杀业务根据消息队列中的请求信息,再做后续处理.

    三: 详解

    3.1、队列、生产者、消费者

      队列是RabbitMQ的内部对象,用于存储消息。生产者(下图中的P)生产消息并投递到队列中,消费者(下图中的C)可以从队列中获取消息并消费。

    消息队列RabbitMQ基础知识详解

      多个消费者可以订阅同一个队列,这时队列中的消息会被平均分摊给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理。

    消息队列RabbitMQ基础知识详解

    3.2、Exchange、Binding

        刚才在3.1中,我们看到生产者将消息投递到队列中,实际上这在RabbitMQ中这种事情永远都不会发生。实际的情况是,生产者将消息发送到Exchange(交换器,下图中的X),再通过Binding将Exchange与Queue关联起来。

    消息队列RabbitMQ基础知识详解

    3.3、Exchange Type、Bingding key、routing key

      在绑定(Binding)Exchange与Queue的同时,一般会指定一个binding key。在绑定多个Queue到同一个Exchange的时候,这些Binding允许使用相同的binding key。

    生产者在将消息发送给Exchange的时候,一般会指定一个routing key,来指定这个消息的路由规则,生产者就可以在发送消息给Exchange时,通过指定routing key来决定消息流向哪里。

      RabbitMQ常用的Exchange Type有三种:fanout、direct、topic。

    •   fanout:把所有发送到该Exchange的消息投递到所有与它绑定的队列中。
    •   direct:把消息投递到那些binding key与routing key完全匹配的队列中。
    •   topic:将消息路由到binding key与routing key模式匹配的队列中。

    附上一张RabbitMQ的结构图:

    消息队列RabbitMQ基础知识详解

    四: 最后来具体解析一下几个问题:

    1、可以自动创建队列,也可以手动创建队列,如果自动创建队列,那么是谁负责创建队列呢?是生产者?还是消费者?

        如果队列不存在,当然消费者不会收到任何的消息。但是如果队列不存在,那么生产者发送的消息就会丢失。所以,为了数据不丢失,消费者和生产者都可以创建队列。那么如果创建一个已经存在的队列呢?那么不会有任何的影响。需要注意的是没有任何的影响,也就是说第二次创建如果参数和第一次不一样,那么该操作虽然成功,但是队列属性并不会改变。

    队列对于负载均衡的处理是完美的。对于多个消费者来说,RabbitMQ使用轮询的方式均衡的发送给不同的消费者。

    2、RabbitMQ的消息确认机制

        默认情况下,如果消息已经被某个消费者正确的接收到了,那么该消息就会被从队列中移除。当然也可以让同一个消息发送到很多的消费者。

    如果一个队列没有消费者,那么,如果这个队列有数据到达,那么这个数据会被缓存,不会被丢弃。当有消费者时,这个数据会被立即发送到这个消费者,这个数据被消费者正确收到时,这个数据就被从队列中删除。

        那么什么是正确收到呢?通过ack。每个消息都要被acknowledged(确认,ack)。我们可以显示的在程序中去ack,也可以自动的ack。如果有数据没有被ack,那么:

    RabbitMQ Server会把这个信息发送到下一个消费者。

    如果这个app有bug,忘记了ack,那么RabbitMQServer不会再发送数据给它,因为Server认为这个消费者处理能力有限。

    而且ack的机制可以起到限流的作用(Benefitto throttling):在消费者处理完成数据后发送ack,甚至在额外的延时后发送ack,将有效的均衡消费者的负载。

  • 相关阅读:
    UVA 120 Stacks of Flapjacks
    HDU 4869 Turn the pokers
    HDU 4882 ZCC Loves Codefires
    HDU 4864 Task
    HDU 4861 Couple doubi
    UVA 1600 Patrol Robot
    UVA 712 S-Trees
    2014/4/6长沙多校第六次(浙大校赛)
    UVA10905 思维考察
    HDU1498 枚举+二分图类棋盘问题(最大匹配)
  • 原文地址:https://www.cnblogs.com/fdzfd/p/9313204.html
Copyright © 2011-2022 走看看