RabbitMQ-初识

初识RabbitMQ

以下内容,基于前辈PPT和网络资源整理汇总而来。

什么是RabbitMQ

  • RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写。
  • RabbitMQ支持多种客户端:.NET、Java、Python等。
  • RabbitMQ用于实时性、可靠性要求较高的消息传递。
  • RabbitMQ依赖消息确认、事务、持久化等保证消息的可靠传输。

2018-07-05发布最新版本3.7.7
AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。

优势

  • 高可靠性
    依赖集群部署、消息确认、事务、消息持久化等机制,保证消息的可靠传输,避免消息丢失带来的风险
  • 丰富的消息传送机制
    利用RabbitMQ提供的多种消息传送路由机制,可以实现点对点、发布订阅等多种消息传送方式
  • 消息持久化
    RabbitMQ支持消息持久化存储,消息被Consumer消费之后,才有可能删除该消息
  • 高可用性
    RabbitMQ集群提供镜像队列机制,消息在多个节点存在,避免由于单个节点故障而造成消息丢失

应用场景

  • 应用解耦
    降低不同应用系统之间的耦合,例如:充电与订单结算之间的解耦、集控离网上线与互联互通之间的解耦等
  • 流量削峰
    在遇到抢购、秒杀、优惠券下发等活动时,可能短时间内产生较大的流量,对后台系统产生较大的压力,可能会引发不良的影响。可以将流量暂存于RabbitMQ,后台系统可以按照处理能力进行消费,RabbitMQ起到流量缓冲的作用,达到流量削峰的作用
  • 发布订阅
    如分布式事件中心,一个事件可以被多个订阅者处理;HSF(High-Speed Service Framework)状态变化通知等
  • 异步处理
    消息应用中心基于消息队列技术,实现了统一的消息发送与处理。如短信通知、电站状态推送、用户注册等

消息发送流程图

在这里插入图片描述

相关概念

  • Header:Message是否被缓存、由哪个Message Queue接受、优先级是多少。
  • Message:由Header和Body组成,Header是由生产者添加的各种属性几何,Body是真正传输的数据。
  • Exchange:RabbitMQ的消息发送,并不是直接推送至队列,而是先发送至Exchange,然后由Exchange根据不同策略推送到制定的队列。RabbitMQ常用的Exchange Type有fanout、direct、topic、headers四种。
  • Queue:Queue(队列)是RabbitMQ的内部对象,用于存储消息。RabbitMQ中的消息都只能存储在Queue中,生产者生产消息并最终投递到Queue中,消费者可以从Queue中获取消息并消费。多个消费者可以订阅同一个Queue,这时Queue中的消息会被平均分摊给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理。
  • RoutingKey、BindingKey:RoutingKey是存储在消息中,BindingKey存储在MQ中。消息发送者发送消息到RabbitMQ,Exchange解析消息Header得到RoutingKey。Exchange在与多个Message Queue发生Binding后会生成一张路由表,路由表中存储着Message Queue所需消息的限制条件即Binding Key。Exchange根据BindingKey、RoutingKey、Exchange Type来确定将消息发送至某个或某些队列。
  • Connection:对于RabbitMQ而言,其实就是一个位于客户端和Broker之间的TCP连接。
  • Channel:信道,仅仅创建了客户端到Broker之间的连接后,客户端还是不能发送消息的。需要为每一个Connection创建Channel,AMQP协议规定只有通过Channel才能执行AMQP的命令。一个Connection可以包含多个Channel。之所以需要Channel,是因为TCP连接的建立和释放都是十分昂贵的,如果一个客户端每一个线程都需要与Broker交互,如果每一个线程都建立一个TCP连接,暂且不考虑TCP连接是否浪费,就算操作系统也无法承受每秒建立如此多的TCP连接。RabbitMQ建议客户端线程之间不要共用Channel,至少要保证共用Channel的线程发送消息必须是串行的,但是建议尽量共用Connection。

Exchange Type

以下 Exchange Type 的相关知识摘取自此处

  • fanout
    把所有发送到该Exchange的消息路由到所有与它绑定的Queue中。
    在这里插入图片描述
    • 生产者(P)发送到Exchange(X)的所有消息都会路由到图中的两个Queue,并最终被两个消费者(C1与C2)消费。
  • direct
    把消息路由到bindingKey与routingKey完全匹配的Queue中。
    在这里插入图片描述
    • routingKey=”error”发送消息,则会同时路由到Queue1(amqp.gen-S9b…)和Queue2(amqp.gen-Agl…)
    • routingKey=”info”或routingKey=”warning”发送消息,则只会路由到Queue2
    • 以其他routingKey发送消息,则不会路由到这两个Queue中
  • topic
    把消息路由到bindingKey与routingKey模糊匹配的Queue中。
    在这里插入图片描述
    • routingKey为一个句点号“.”分隔的字符串(被句点号“.”分隔开的每一段独立的字符串称为一个单词)
    • bindingKey与routingKey一样也是句点号“.”分隔的字符串
    • bindingKey中可以存在两种特殊字符“”与“#”,用于做模糊匹配,其中“”用于匹配一个单词,“#”用于匹配多个单词(可以是零个)
    • 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不依赖于routingKey与bindingKey的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。在绑定Queue与Exchange时指定一组键值对;当消息发送到Exchange时,RabbitMQ会取到该消息的headers(也是一个键值对的形式),对比其中的键值对是否完全匹配Queue与Exchange绑定时指定的键值对;如果完全匹配则消息会路由到该Queue,否则不会路由到该Queue。

RPC

MQ本身是基于异步的消息处理,前面的示例中所有的生产者(P)将消息发送到RabbitMQ后不会知道消费者(C)处理成功或者失败(甚至连有没有消费者来处理这条消息都不知道)。但实际的应用场景中,我们很可能需要一些同步处理,需要同步等待服务端将我的消息处理完成后再进行下一步处理。这相当于RPC(Remote Procedure Call,远程过程调用)。在RabbitMQ中也支持RPC。
在这里插入图片描述
RabbitMQ中实现RPC的机制是:
客户端发送请求(消息)时,在消息的属性(MessageProperties,在AMQP协议中定义了14中properties,这些属性会随着消息一起发送)中设置两个值replyTo(一个Queue名称,用于告诉服务器处理完成后将通知我的消息发送到这个Queue中)和correlationId(此次请求的标识号,服务器处理完成后需要将此属性返还,客户端将根据这个id了解哪条请求被成功执行了或执行失败)。

  • 服务器端收到消息并处理
  • 服务器端处理完消息后,将生成一条应答消息到replyTo指定的Queue,同时带上correlationId属性
  • 客户端之前已订阅replyTo指定的Queue,从中收到服务器的应答消息后,根据其中的correlationId属性分析哪条请求被执行了,根据执行结果进行后续业务处理

参考:RabbitMQ 实现RPC

消息确认机制

消息确认机制是RabbitMQ实现消息可靠传输的一种机制,发送者§发送消息到RabbitMQ的确认称为Confirm,消费者©从RabbitMQ消费消息的确认称为ACK。

来自公司前辈PPT

  • 生产者§发送消息到RabbitMQ,如果出现网络故障,生产者是不知道消息是否成功发送至RabbitMQ
  • 消费者©从RabbitMQ消费消息,如果出现网络故障,RabbitMQ并不知道消息是否被Consumer成功消费
  • 加入消息确认机制,生产者可以明确知道消息发送成功或失败,避免消息重复发送
  • 加入消息确认机制,RabbitMQ可以明确知道消息是否成功消费,避免消息重复消费

生产者将信道设置成confirm模式,一旦信道进入confirm模式,所有在该信道上面发布的消息都将会被指派一个唯一的ID(从1开始),一旦消息被投递到所有匹配的队列之后,broker就会发送一个确认给生产者(包含消息的唯一ID),这就使得生产者知道消息已经正确到达目的队列了,如果消息和队列是可持久化的,那么确认消息会在将消息写入磁盘之后发出,broker回传给生产者的确认消息中delivery-tag域包含了确认消息的序列号,此外broker也可以设置basic.ack的multiple域,表示到这个序列号之前的所有消息都已经得到了处理;
confirm模式最大的好处在于他是异步的,一旦发布一条消息,生产者应用程序就可以在等信道返回确认的同时继续发送下一条消息,当消息最终得到确认之后,生产者应用便可以通过回调方法来处理该确认消息,如果RabbitMQ因为自身内部错误导致消息丢失,就会发送一条nack消息,生产者应用程序同样可以在回调方法中处理该nack消息;
参考:RabbitMQ 消息发送确认 与 消息接收确认(ACK)

镜像队列

  • 镜像队列是RabbitMQ实现高可用的一种方案,消息实体会主动在镜像节点间同步。

    • 优点:队列中的消息每个节点都会存在一份 copy, 在单个节点失效的情况下,整个MQ集群仍旧可以提供服务。
    • 缺点:降低系统性能,如果镜像队列过多,镜像队列同步会占用较大网络带宽。
  • 镜像队列选举机制:镜像队列内部实现一套选举算法。

    • 镜像队列有主从之分,一个主节点(master),0个或多个从节点(slave),队列 中的消息以 master 为主。
    • 若master节点失效,则镜像队列会自动选举出一个节点(slave中消息队列最长者,最早启动的节点)作为master,作为消息消费的基准参考。
    • 若 slave 节点失效,镜像队列集群中其他节点的状态无需改变。

Virtual Host

  • RabbitMQ权限管理依赖Virtual Host(虚拟消息服务器),每个Virtual Host相当于一个单独的RabbitMQ服务器。
  • 每个Virtual Host之间是隔离的,Exchange、Queue、message都不能互通。
  • Virtual Host是一个虚拟概念,类似于权限控制组,一个Virtual Host里面可以有若干个Exchange和Queue,但是权限控制的最小粒度是Virtual Host。
  • RabbitMQ提供默认的Virtual Host,名称是 / (斜线)。发送消息未指定具体的Virtual Host,消息会发送到默认的Virtual Host。

事务

  • 事务是RabbitMQ实现消息可靠传输的另一种形式,和数据库事务一样,RabbitMQ事务可以提交或回滚。
  • RabbitMQ中与事务机制有关的方法有三个,分别是Channel里面的txSelect(),txCommit()以及txRollback()。
    • txSelect用于将当前Channel设置成是transaction模式
    • txCommit用于提交事务
    • txRollback用于回滚事务
    • 在通过txSelect开启事务之后,可以发布消息到RabbitMQ
    • 如果txCommit提交成功,则消息一定是到达broker了
    • 如果在txCommit执行之前RabbitMQ异常奔溃或者由于其他原因抛出异常,可以通过txRollback回滚事务
  • 使用事务会严重降低RabbitMQ的性能。如果要保证消息可靠传输,优先采用消息确认机制。
  • 消息确认和事务不可同时使用。

目前我接触到的实际应用

  • 消息应用中心基于RabbitMQ等消息队列技术,实现基于任务的异步处理。邮件发送、短信通知、用户注册等作为任务运行在消息应用中心
  • 分布式事件中心基于RabbitMQ发布订阅机制,实现事件的分发、处理。如系统用户同步、Redis数据同步等
  • HSF状态通知基于RabbitMQ发布订阅机制,实现HSF状态的互相感知
  • 配置热部署基于RabbitMQ发布订阅机制,实现配置值的实时更新
  • 补丁工具基于RabbitMQ发布订阅机制,实现运维助手的自更新及补丁安装

createtime:2018-11-20

猜你喜欢

转载自blog.csdn.net/long870294701/article/details/84311310