当初我学RabbitMQ的时候,第一韶光就上GitHub找相应的教程,但是令我很失落望的是没有找到,Spring,Mybatis之类的教程很多,而RabbitMQ的教程险些找不到,看的最多的便是朱小厮大佬的博客。后来想着索性自己总结一下吧,有不恰当的地方欢迎小伙伴指出。
这篇文章紧张是对着我在GitHub上的源码阐明的,因此本文并没有太多的源码。写了挺永劫光的,为了防止迷路,欢迎大家star和fork
github地址:https://github.com/erlieStar/rabbitmq-examples

序言
我们先来看一下一条在RabbitMQ中的流转过程
图示的紧张流程如下
生产者发送的时候指定RoutingKey,然后被发送到ExchangeExchange根据一些列规则将路由到指定的行列步队中消费者从行列步队中消费全体流程紧张就4个参与者message,exchange,queue,consumer,我们就来认识一下这4个参与者
Message可以设置一些列属性,每种属性的浸染可以参考《深入RabbitMQ》一书
Exchange吸收,并根据路由键转发到所绑定的行列步队,常用的属性如下
我们最常利用的便是type属性,下面就详细阐明type属性
Fanout Exchange
发送到该交流机的都会路由到与该交流机绑定的所有行列步队上,可以用来做广播
不处理路由键,只须要大略的将行列步队绑定到交流机上
Fanout交流机转发是最快的
Direct Exchage把路由到BindingKey和RoutingKey完备匹配的行列步队中
Topic Exchange前面说到,direct类型的交流器路由规则是完备匹配RoutingKey和BindingKey。topic和direct类似,也是将发送到RoutingKey和BindingKey相匹配的行列步队中,只不过可以模糊匹配。
RoutinKey为一个被“.”号分割的字符串(如com.rabbitmq.client)BindingKey和RoutingKey也是“.”号分割的字符串BindKey中可以存在两种分外字符串“”和“#”,用于做模糊匹配,个中“”用于匹配不多不少一个词,“#”用于匹配多个单词(包含0个,1个)如果现在有2个RoutingKey为java.lang和java.util.concurrent的,java.lang会被路由到Consumer1和Consumer2,java.util.concurrent会被路由到Consumer2。
Headers Exchange
headers类型的交流器不依赖于路由键的匹配规则来路由,而是根据发送内容中的headers属性进行匹配。headers类型的交流器性能差,不实用,基本上不会利用。
Queue行列步队的常见属性如下
arguments中可以设置的行列步队的常见参数如下
rabbitmq-api(rabbitmq api的利用)chapter_1: 快速开始,手写一个RabbitMQ的生产者和消费者chapter_2: 演示了各种exchange的利用来回顾一下上面说的各种exchange机器路由规则
chapter_3: 拉取消息的得到办法有2种
拉取消息(get message)推送(consume message)那我们该当拉取消息还是推送?get是一个轮询模型,而consumer是一个推送模型。get模型会导致每条都会产生与RabbitMQ同步通信的开销,这一个要求由发送要求帧的客户端运用程序和发送应答的RabbitMQ组成。以是推送,避免拉取
chapter_4: 手动ack的确认办法有2种
自动确认(autoAck=true)手动确认(autoAck=false)消费者在消费的时候,可以指定autoAck参数
String basicConsume(String queue, boolean autoAck, Consumer callback)
autoAck=false: RabbitMQ会等待消费者显示回答确认后才从内存(或者磁盘)中移出
autoAck=true: RabbitMQ会自动把发送出去的置为确认,然后从内存(或者磁盘)中删除,而不管消费者是否真正的消费了这些
手动确认的方法如下,有2个参数
basicAck(long deliveryTag, boolean multiple)
deliveryTag: 用来标识信道中投递的。RabbitMQ 推送给Consumer时,会附带一个deliveryTag,以便Consumer可以在确认时见告RabbitMQ到底是哪条被确认了。RabbitMQ担保在每个信道中,每条的deliveryTag从1开始递增
multiple=true: id<=deliveryTag的,都会被确认
myltiple=false: id=deliveryTag的,都会被确认
一贯不确认会发生啥?
如果行列步队中的发送到消费者后,消费者不对进行确认,那么会一贯留在行列步队中,直到确认才会删除。如果发送到A消费者的一贯不确认,只有等到A消费者与rabbitmq的连接中断,rabbitmq才会考虑将A消费者未确认的重新投递给另一个消费者
chapter_5: 谢绝的两种办法确认只有一种方法
basicAck(long deliveryTag, boolean multiple)而谢绝有两种办法
basicNack(long deliveryTag, boolean multiple, boolean requeue)basicReject(long deliveryTag, boolean requeue)basicNack和basicReject的差异只有一个,basicNack支持批量谢绝
deliveryTag和multiple参数前面已经说过。
requeue=true: 会被再次发送到行列步队中
requeue=false: 会被直接丢失
chapter_6: 失落败关照
chapter_6到chapter_10紧张简述了发布时的权衡
我们最常用的便是失落败关照和发布者确认当不能被路由到某个queue时,我们如何获取到不能精确路由的呢?
在发送时设置mandatory为true生产者可以通过调用channel.addReturnListener来添加ReturnListener监听器获取没有被路由到行列步队中的mandatory是channel.basicPublish()方法中的参数
mandatory=true: 交流器无法根据路由键找到一个符合条件的行列步队,那么RabbitMQ会调用Basic.Return命令将返回给生产者
mandatory=false: 涌现上述环境,则直接被丢弃
chapter_7: 发布者确认当被发送后,到底有没有到达exchange呢?默认情形下生产者是不知道有没有到达exchange
RabbitMQ针对这个问题,供应了两种办理办法
事务(后面会讲到)发布者确认(publisher confirm)而发布者确认有三种编程办法
普通confirm模式:每发送一条后,调用waitForConfirms()方法,等待做事器端confirm。实际上是一种串行confirm了。批量confirm模式:每发送一批后,调用waitForConfirms()方法,等待做事器端confirm。异步confirm模式:供应一个回调方法,做事端confirm了一条或者多条后Client端会回调这个方法。异步confirm模式的性能最高,因此常常利用,我想把这个分享的细一下
channel.addConfirmListener(new ConfirmListener() { @Override public void handleAck(long deliveryTag, boolean multiple) throws IOException { log.info("handleAck, deliveryTag: {}, multiple: {}", deliveryTag, multiple); } @Override public void handleNack(long deliveryTag, boolean multiple) throws IOException { log.info("handleNack, deliveryTag: {}, multiple: {}", deliveryTag, multiple); }});
写过异步confirm代码的小伙伴该当对这段代码不陌生,可以看到这里也有deliveryTag和multiple。但是我要说的是这里的deliveryTag和multiple和的ack没有一点关系。
confirmListener中的ack: rabbitmq掌握的,用来确认是否到达exchange
的ack: 上面说到可以自动确认,也可以手动确认,用来确认queue中的是否被consumer消费
chapter_8: 备用交流器生产者在发送的时候如果不设置 mandatory 参数那么在未被路由到queue的情形下将会丢失,如果设置了 mandatory 参数,那么须要添加 ReturnListener 的编程逻辑,生产者的代码将变得繁芜。如果既不想繁芜化生产者的编程逻辑,又不想丢失,那么可以利用备用交流器,这样可以将未被路由到queue的存储在RabbitMQ 中,在须要的时候去处理这些
chapter_9: 事务RabbitMQ中与事务机制干系的方法有3个
成功被发送到RabbitMQ的exchange上,事务才能提交成功,否则便可在捕获非常之后进行事务回滚,与此同时可以进行重发由于事务会榨干RabbitMQ的性能,以是一样平常利用发布者确认代替事务
chapter_10: 持久化做持久化,只须要将属性的delivery-mode设置为2即可
RabbitMQ给我们封装了这个属性,即MessageProperties.PERSISTENT_TEXT_PLAIN,详细利用可以参考github的代码
当我们想做的持久化时,最好同时设置行列步队和的持久化,由于只设置行列步队的持久化,重启之后会丢失。只设置行列步队的持久化,重启后行列步队消逝,继而也丢失
chapter_11: 去世信行列步队DLX,全称为Dead-Letter-Exchange,称之为去世信交流器。当一个在行列步队中变成去世信(dead message)之后,它能被重新发送到另一个交流器中,这个交流器便是DLX,绑定DLX的行列步队就称之为去世信行列步队。DLX也是一个正常的交流器,和一样平常的交流器没有差异,实际上便是设置某个行列步队的属性
变成去世信一样平常是由于以下几种情形
被谢绝(Basic.Reject/Basic.Nack)且不重新投递(requeue=false)过期行列步队达到最大长度去世信交流器和备用交流器的差异
备用交流器: 1.无法路由时转到备用交流器 2.备用交流器是在声明主交流器的时候定义的
去世信交流器: 1.已经到达行列步队,但是被消费者谢绝等的会转到去世信交流器。2.去世信交流器是在声明行列步队的时候定义的
chapter_12: 流量掌握(做事质量担保)qos即做事端限流,qos对付拉模式的消费办法无效
利用qos只要进行如下2个步骤即可
autoAck设置为false(autoAck=true的时候不生效)调用basicConsume方法前先调用basicQos方法,这个方法有3个参数basicQos(int prefetchSize, int prefetchCount, boolean global)
为什么要利用qos?
提高做事稳定性。假设消费端有一段韶光不可用,导致行列步队中有上万条未处理的,如果开启客户端,巨量的推送过来,可能会导致消费端变卡,也有可能直接不可用,以是做事端限流很主要提高吞吐量。当行列步队有多个消费者时,行列步队收到的以轮询的办法发送给消费者。但由于机器性能等的缘故原由,每个消费者的消费能力不一样,这就会导致一些消费者处理完了消费的,而另一些则还堆积了一些,会造成整体运用吞吐量的低落springboot-rabbitmq(springboot整合rabbitmq)未完待续