(一)认识RabbitMQ

  RabbitMQ介绍    

安装RabbitMQ:https://blog.csdn.net/ycj_xiyang/article/details/79926586

    RabbitMQ是流行的开源消息队列系统,用erlang语言开发。

    RabbitMQ是AMQP(高级消息队列协议)的标准实现,最初起源于金融系统,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

    RabbitMQ只要是为了实现系统之间的双向解耦而实现的。当生产者大量产生数据时,消费者无法快速消费,那么需要一个中间层,保存这个数据。

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

相关概念

    通常我们谈到消息队列服务,会有三个概念:发消息者、队列、收消息者,RabbitMQ在这个基本概念上,多了一层抽象,在发消息者和队列之间,加入了交换器(Exchange)。这样发消息者和队列就没有直接联系,转而变成发消息者把消息给交换器,交换器根据调度策略再把消息再给队列。

        

    ● 左侧Producer代表生产者,也就是往RabbitMQ发消息的程序。

    ● 中间即是RabbitMq Server,其中包括了交换机和队列。

    ● 右侧Consumer代表消费者,也就是往RabbitMQ拿消息的程序。

Routing Key、Binding Key、Exchange Type 的关系

         

投递过程

    消息队列得使用过程大概如下:

    1:客户端连接到消息队列服务器,打开一个channel

    2:客户端声明一个exchange,并设置相关属性

    3:客户端声明一个queue,并设置相关属性

    4:客户端使用routing key,在exchange和queue之间建立好绑定关系

    5:客户端投递消息到exchange

    6:客户端从指定得queue中消费信息

几个概念明:

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

    Broker:消息队列服务器实体。

    Vhost:虚拟主机,一个虚拟主机持有一组交换机、队列和绑定。为什么需要多个虚拟主机呢?

                在RabbitMQ中,用户能在虚拟主机的粒度进行权限控制。因此,如果需要禁止A组访问B组的交换机/队列/绑定 ,

                必须为A和B分别创建一个虚拟主机。每一个RabbitMQ服务器都有一个默认的虚拟主机“/”。

    Exchange:交换机,用于转发消息,但是它不会做存储,如果没有Queue bind到Exchange的话,它会直接丢弃掉Producer发送过来的消息。

    RoutingKey:路由键;消息到交换机的时候,交换机会转发到对应的队列中,那么究竟转发到那个队 列,就要根据该路由键。RabbitMQ为routing key设定的长度限制为255 bytes。

    Queue:消息队列载体,是RabbitMQ的内部对象 用于存储消息,每个消息都会被投入到一个或多个队列。

    Binding:绑定,它的作用就是把Exchange和queue按照路由规则绑定起来,是多对多的关系。

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

    Producer:消息生产者,就是投递消息的程序。

    Consumer:消息消费者,就是接受消息的程序。  

    Channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。

    Message acknowledgment:在实际应用中,可能会发生消费者收到Queue中的消息,但没有处理完成就宕机(或出现其他意外)的情况,这种情况下就可能会导致消息丢失。为了避免这种情况发生,我们可以要求消费者在消费完消息后发送一个回执给RabbitMQ,RabbitMQ收到消息回执(Message acknowledgment)后才将该消息从Queue中移除;如果RabbitMQ没有收到回执并检测到消费者的RabbitMQ连接断开,则RabbitMQ会将该消息发送给其他消费者(如果存在多个消费者)进行处理。这里不存在timeout概念,一个消费者处理消息时间再长也不会导致该消息被发送给其他消费者,除非它的RabbitMQ连接断开。 这里会产生另外一个问题,如果我们的开发人员在处理完业务逻辑后,忘记发送回执给RabbitMQ,这将会导致严重的bug——Queue中堆积的消息会越来越多;消费者重启后会重复消费这些消息并重复执行业务逻辑…

另外pub message是没有ack的。

    Message durability:如果我们希望即使在RabbitMQ服务重启的情况下,也不会丢失消息,我们可以将Queue与Message都设置为可持久化的(durable),这样可以保证绝大部分情况下我们的RabbitMQ消息不会丢失。但依然解决不了小概率丢失事件的发生(比如RabbitMQ服务器已经接收到生产者的消息,但还没来得及持久化该消息时RabbitMQ服务器就断电了),如果我们需要对这种小概率事件也要管理起来,那么我们要用到事务。由于这里仅为RabbitMQ的简单介绍,所以这里将不讲解RabbitMQ相关的事务。

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

                                

详解:

    交换机(Exchange)

    交换机的功能主要是接收消息并且转发到绑定的队列,交换机不存储消息,在启用ack模式后,交换机找不到队列会返回误。

交换机有四种类型:Direct,topic,Headers and Fanout。

    ● Direct:direct类型的行为是“先匹配,再投送”。即在绑定时设定一个routing_key,消息的routing_key匹配时,才会被                     交换器投送到绑定的队列中去。

    ● Topic:按规则转发消息(最灵活)

    ● Headers:设置header attribute 参数类型的交换机

    ● Fanout:转发消息到所有绑定队列

Direct Exchange

    Direct Exchange是RabbitMQ默认的交换机模式,也是最简单的模式,根据key全文匹配去寻找队列。

                                            

第一个X-Q1就有一个binding key,名字为orange;第二个X-Q2就有2个binding key,名字为black和green。当消息中的路由键和这个binding key 对应上的时候,那么就知道了该消息去到哪一个队列中。

Ps:为什么X到Q2要有black,green,2个binding key呢,一个不就行了吗?-这个主要是因为可能有其他的队列如Q3,而Q3只接受black的信息,而Q2不仅接受black的信息,还接受green的信息。

Topic Exchange

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

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

                                        2014-2-21 9-57-37 

以上图中的配置为例,routingKey=”quick.orange.rabbit”的消息会同时路由到Q1与Q2,routingKey=”lazy.orange.fox”的消息会路由到Q1与Q2,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 Exchange

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

Fan'ou't Exchange

    fanout类型的Exchange路由规则非常简单,他会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中。

                                                

上图中,生产者(P)发送到Exchange(X)的所有消息都会路由到图中的两个Queue,并最终被两个消费者(C1与C2)消费。

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 选型和对比

    1:从社区活跃度

按照目前网络上的资料,RabbitMQ、ActiveMQ、ZeroMQ三者中,综合来看,RabbitMQ是首选。

      2:持久化消息比较

ZeroMQ不支持,ActiveMQ和RabbitMQ都支持。持久化消息主要是指我们机器在不可抗力因素等情况下挂掉了,消息不会丢失的机制。

      3:综合技术实现

可靠性、灵活的路由、集群、事务、高可用的队列、消息排序、问题追踪、可视化管理工具。插件系统等等。

RabbitMQ/Kafka最好,ActiveMQ次之,ZeroMQ最差。当然ZeroMQ也可以做到,不过自己必须手动写代码实现,代码量不小。尤其是可靠性中的:持久性、投递确认、发布者证实和高可用性。

      4:高并发

毋庸置疑,RabbitMQ最高,原因是它的实现语言是天生具备高并发高可用的erlang语言。

      5:比较关注的比较,RabbitMQ和Kafka

RabbitMQ比Kafka成熟,在可用性上,稳定性上,可靠性上,RabbitMQ胜于Kafka(理论上)。

另外,Kafka的定位主要在日志等方面,因为kafka设计的初衷就是处理日志的,可以看做是一个日志(消息)系统一个重要组件,针对性很强,所以如果业务方面还是建议选择RabbitMQ。

而且Kafka的性能(吞吐量、TPS)比RabbitMQ要高出来很多。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值