rabbitMQ的基本概念:
broker:在集群环境下 每一个rabbitMQ服务器叫 broker
exchange:交换机,消息的路由器,可以根据规则把消息路由到不同的队列
binding:绑定,把交换机和队列进行绑定
queue:队列,消息真正存储的地方
routingkey:路由键,key,交换机根据它 进行消息路由。路由的规则。
producter生产者:自己写的程序 用来发送消息
consumer消费者:自己写的程序 用来消费消息
channel通道:表示消息会话,一次消息传输走一个通道。
rabbitMQ消息模型:
简单队列
一个生产者对应一个消费者!!
work 模式
一个生产者对应多个消费者,但是一条消息只能有一个消费者获得消息!!!
轮询分发就是将消息队列中的消息,依次发送给所有消费者。一个消息只能被一个消费者获取。
发布/订阅模式
一个消费者将消息首先发送到交换器,交换器绑定到多个队列,然后被监听该队列的消费者所接收并消费。
ps:X表示交换器,在RabbitMQ中,交换器主要有四种类型:direct、fanout、topic、headers,这里的交换器是 fanout。下面我们会详细介绍这几种交换器。
两个消费者获得了同一条消息。即就是,一个消息从交换机同时发送给了两个队列中,监听这两个队列的消费者消费了这个消息;
如果没有队列绑定交换机,则消息将丢失。因为交换机没有存储能力,消息只能存储在队列中。
路由模式
生产者将消息发送到direct交换器,在绑定队列和交换器的时候有一个路由key,生产者发送的消息会指定一个路由key,那么消息只会发送到相应key相同的队列,接着监听该队列的消费者消费消息。
也就是让消费者有选择性的接收消息。
路由模式,是以路由规则为导向,引导消息存入符合规则的队列中。再由队列的消费者进行消费的。
主题模式
上面的路由模式是根据路由key进行完整的匹配(完全相等才发送消息),这里的通配符模式通俗的来讲就是模糊匹配。
符号“#”表示匹配一个或多个词,符号“*”表示匹配一个词。
与路由模式相似,但是,主题模式是一种模糊的匹配方式。
这五种工作模式,可以归为三类:
生产者,消息队列,一个消费者;
生产者,消息队列,多个消费者;
生产者,交换机,多个消息队列,多个消费者;
1、direct 如果路由键完全匹配的话,消息才会被投放到相应的队列。
2、fanout 当发送一条消息到fanout交换器上时,它会把消息投放到所有附加在此交换器上的队列。
3、topic 设置模糊的绑定方式,“*”操作符将“.”视为分隔符,匹配单个字符;“#”操作符没有分块的概念,它将任意“.”均视为关键字的匹配部分,能够匹配多个字符。
4、header headers 交换器允许匹配 AMQP 消息的 header 而非路由键,除此之外,header 交换器和 direct 交换器完全一致,但是性能却差很多,因此基本上不会用到该交换器
6种,但是 有一种叫RPC 不是rabbitMQ本身。 本身有5种。
简单模型:点对点 一对一 生产者--à队列---à消费者
工作模型:一对多 一个生产者---à队列----à多个消费者
发布订阅类型
路由: 生产者---à交换机---à多个队列---à多个消费者,每个消费者监听自己队列。
RabbititMq的作用:
消息队列在实际应用中常用的使用场景。异步处理,应用解耦,流量削锋和消息通讯四个场景
如何防止RabbitMQ消息重复消费?
保证消息幂等性。幂等性概念:一个请求,不管重复来多少次,结果是不会改变的。
解决方法:
Redis的setNX() , 做消息id去重 java版本目前不支持设置过期时间
setNx的原理:有就创建成功没有就创建不成功
RabbitMq消息的百分之百消费
设置标识字段消费成功后判断每次来消费的消息0是未消费1是已消费
如何解决消息堆压
设置消费者集群
使用广播模式统一消费使用通配符的形式,快速消费消息
实现延迟消息:
1、基于死信队列
设置过期时间(ttl)消息在队列过期之后转发到死信队列消费者监听死信队列进行消费
使用延迟插件 消息放在交换机消息过期才会进行入队lian
2、基于延迟插件
需要咱们给rabbitMQ安装一个插件。在插件库中有个小型内部数据库。发送的消息通过交换机,先把消息放到这个数据库中,时间到了再把消息取出来 向队列转发。
死信实现延迟消息和 延迟消息实现延迟消息有什么不同?
最大的不同点是 :
死信的要求时间一致,消息的过期时间要一致。队列中先进来了一个24小时的消息,后面又进来 30分过期的消息,后进来的先过期,但是它前面有消息,它就得等。
电商 正常订单 24小时过期,秒杀30分过期。
延迟插件 不存在这个问题
消息准确性保证:
产生消息丢失的原因:
1、生产者层面:
生产者生产的消息 投递到交换机,通过交换机再投递到队列。如果没投递到交换机消息容易丢失,交换机向队列转发的时候 没进入到队列,消息也容易丢失。
解决:rabbitMQ提供了 交换机应答和队列应答。消息如果投递到交换机 无论是否成功,交换机都会给个ack回执。 交换机向队列转发如果不成功了,队列给提供了应答。
2、rabbitMQ服务器层面:
消息在队列中存储,内存中,如果服务器挂了,重启之后 消息就没了。
解决:提供了持久化机制,对交换机持久化、队列持久化、队列中的消息 持久化。
3、消费者层面:
消费者在消费消息时,出问题了,业务没执行完,没有达到想要的目的,然后这个消息还出队了。
解决:消息原本是自动签收,只有消费方一监听到消息,消息就出队了。
提供了 ack手动签收。需要手动给MQ服务器一个回执,服务器拿到回执,消息才出队。
RabbitMQ解决分布式事务
分布式事务:不同的服务操作不同的数据源(库或表),保证数据一致性的问题。
解决:采用RabbitMQ消息最终一致性的解决方案,解决分布式事务问题。
分布式事务场景:
1、电商项目中的商品库和ES库数据同步问题。
2、电商项目中:支付----à订单---à库存,一系列操作,进行状态更改等。
解决方案:
RabbitMQ消息最终一致性:消费者发送消息 mq收到消息把消息写入到日志里人工处理
RabbitMQ如何保证消息的顺序性?
消息队列中的若干消息如果是对同一个数据进行操作,这些操作具有前后的关系,必须要按前后的顺序执行,举例:比如数据库对一条数据依次进行了 插入->更新->删除操作,这个顺序必须是这样,如果在同步过程中,消息的顺序变成了 删除->插入->更新,那么原本应该被删除的数据,就没有被删除,造成数据的不一致问题。
解决方案:
方案1:拆分多个队列,每个队列一个消费者,就是多一些队列而已,但是会比较麻烦点;这样也会造成吞吐量下降,可以在消费者内部采用多线程的方式取消费。
方案2:或者就一个队列但是对应一个消费者,然后这个消费者内部用内存队列做排队,然后分发给底层不同的worker消息模型来处理