RabbitMQ学习笔记

RabbitMQ简介:

        AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。

        AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。AMQP协议更多用在企业系统内,对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求还在其次。

        RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

RabbitMQ中的一些基础概念:

        了解基本概念之前,我们先对RabbitMQ的模型有一个大致了解:

        Producer:消息生产者。
        Consumer:消息消费者。
        Connection(连接):Producer 和 Consumer 通过 TCP 连接到 RabbitMQ Server。
        Channel(信道):基于 Connection 创建,数据流动都是在 Channel 中进行。
        Broker(消息代理):实际上就是消息服务器实体。
        Vhost(虚拟主机) : 虚拟主机,一个消息代理(Broker)里可以开设多个虚拟主机(Vhost),用作不同用户的权限分离。
        Exchange(交换机) : 用来发送消息的 AMQP 实体,它指定消息按什么路由规则,路由到哪个队列。
        Queue(消息队列) :是 RabbitMQ 的内部对象,用于存储消息。每个消息都会被投入到一个或多个队列。且多个消费者可以订阅同一个 Queue(这时 Queue 中的消息会被平均分摊给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理)。
        Binding(绑定) : 它的作用就是把交换机(Exchange)和队列(Queue)按照路由规则绑定起来。
        Routing Key(路由键) :消息发送给 Exchange(交换机)时,消息将拥有一个路由键(默认为空), Exchange(交换机)根据这个路由键将消息发送到匹配的队列中。
        Binding Key(绑定键):指定当前 Exchange(交换机)下,什么样的 Routing Key(路由键)会被下派到当前绑定的 Queue 中。

ConnectionFactory、Connection、Channel

        ConnectionFactory、Connection、Channel都是RabbitMQ对外提供的API中最基本的对象。

        Connection是RabbitMQ的socket链接,它封装了socket协议相关部分逻辑。

        ConnectionFactory为Connection的制造工厂。

        Channel是我们与RabbitMQ打交道的最重要的一个接口,我们大部分的业务操作是在Channel这个接口中完成的,包括定义Queue、定义Exchange、绑定Queue与Exchange、发布消息等。

Queue:

        Queue(队列)是RabbitMQ的内部对象,用于存储消息。多个消费者可以订阅同一Queue,这时Queue中的消息会被平均分摊给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理

Message acknowledgment:

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

Message durability:

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

Prefetch count:

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

Exchange:


        生产者将消息投递到Queue中,实际上这在RabbitMQ中这种事情永远都不会发生。实际的情况是,生产者将消息发送到Exchange(交换器,下图中的X),由Exchange将消息路由到一个或多个Queue中(或者丢弃)

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 Types:

        Direct:完全匹配,消息路由到那些 Routing Key 与 Binding Key 完全匹配的 Queue 中。比如 Routing Key 为 test1,则只会转发转发 test1,不会转发 test2。
        Topic:模式匹配,Exchange 会把消息发送到一个或者多个满足通配符规则的 routing-key 的 Queue。

        *号表示匹配一个 word(比如:满足 a.*.c的 routing-key 有 a.test1.c);
        #号匹配多个 word 和路径,路径之间通过 . 隔开(比如:满足 a.#.c的 routing-key 有 a.test1.test2.c);
        Fanout:忽略匹配,把所有发送到该 Exchange 的消息路由到所有与它绑定的 Queue 中。

 

direct exchange 示例代码:

        生产者配置及测试接口类:

        消费者代码:

        如果配置多个消费者监听同一个队列,会以轮询的方式对消息进行消费,而且不存在重复消费。

topic exchange 示例代码:

        生产者配置类:

        消息发送类:

        消费者类:

        因此,当调用sendTopicMessage1()方法时,控制台输出:

        两个队列中都可以接收到。

        当调用sendTopicMessage2()方法时,控制台输出:

        只有一个能接收到消息。

消息回调函数:

生产者消息回调函数

        需要现在配置文件中配置消息确认的配置。

        然后配置相关的消息确认回调函数:

        可以看到上面写了两个回调函数,一个叫 ConfirmCallback ,一个叫 RetrunCallback;

        什么情况下会触发这两个回调函数呢?

        1.消息推送到server,但是在server里找不到交换机。触发ConfirmCallback 。

        2.消息推送到server,找到交换机了,但是没找到队列。触发ConfirmCallback 和RetrunCallback。

        3.消息推送到sever,交换机和队列啥都没找到。和1很像,触发ConfirmCallback。

        4.消息推送成功。触发ConfirmCallback。

消费者消息回调函数

        消费者消息接收的确认机制主要存在三种模式:

        1.自动确认, 这也是默认的消息确认情况。  AcknowledgeMode.NONE。RabbitMQ成功将消息发出(即将消息成功写入TCP Socket)中立即认为本次投递已经被正确处理,不管消费者端是否成功处理本次投递。所以这种情况如果消费端消费逻辑抛出异常,也就是消费端没有处理成功这条消息,那么就相当于丢失了消息。一般这种情况我们都是使用try catch捕捉异常后,打印日志用于追踪数据,这样找出对应数据再做后续处理。

        2.根据情况确认。

        3.手动确认,这个比较关键,也是我们配置接收消息确认机制时,多数选择的模式。消费者收到消息后,手动调用basic.ack/basic.nack/basic.reject后,RabbitMQ收到这些消息后,才认为本次投递成功。
        basic.ack用于肯定确认 
        basic.nack用于否定确认(注意:这是AMQP 0-9-1的RabbitMQ扩展) 
        basic.reject用于否定确认,但与basic.nack相比有一个限制:一次只能拒绝单条消息 

        channel.basicReject(deliveryTag, true);  拒绝消费当前消息,如果第二参数传入true,就是将数据重新丢回队列里,那么下次还会消费这消息。设置false,就是告诉服务器,我已经知道这条消息数据了,因为一些原因拒绝它,而且服务器也把这个消息丢掉就行。 下次不想再消费这条消息了。

        channel.basicNack(deliveryTag, false, true);
        第一个参数依然是当前消息到的数据的唯一id;
        第二个参数是指是否针对多条消息;如果是true,也就是说一次性针对当前通道的消息的tagID小于当前这条消息的,都拒绝确认。
        第三个参数是指是否重新入列,也就是指不确认的消息是否重新丢回到队列里面去。

手动确认代码示例:

        参考文档:https://segmentfault.com/a/1190000022670544

                          https://blog.csdn.net/qq_35387940/article/details/100514134

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值