消息中间件的作用:(1)异步处理 (2)应用解耦 (3)流量削峰
消息中间件的缺点:引入了新的东西,也就增加了新的故障点。比如消息中间件挂了,影响系统的可用性。
两种框架:JMS和AMQP
最大的区别是JMS是是java api,对跨平台的支持较差,但在纯java技术栈内首选。
AMQP是跨平台的,序列化方式选json,不管你是java,php,C/C++,python,都能处理
RabbitMQ实现的事AMQP协议
核心概念
Message 消息。消息不具名,由消息头和消息体组成。消息头包括routing-key(路由键)等,消息体即业务消息
Publisher 生产者,发送消息的一方
Exchange 交换机,类似网络中的交换机,通过一些规则将消息路由到指定的地方,有direct、fanout、topic、header四种类型
Queue 消息队列 用来保存消息直至被消费者消费,是消息的容器。一个消息可以被发送到一个或多个消息队列
Binding 绑定关系 定义Exchange和Queue(也可能还是Exchange )之间的路由关系。
Consumer 消费者,即从队列中取出消息进行处理的一方
Connection 网络连接 比如一个TCP长连接
Channel TCP长连接建立后再里面开辟虚拟信道,通过虚拟信道传递消息,避免频繁创建连接
Virtual Host 表示一批交换机、队列、绑定关系,一个RabbitMQ的server中可以有多个Virtual Host,它们之间是相互隔离的。默认为/
Broker 表示消息队列服务器实体
Exchange类型:
Exchange分发消息时根据类型的不同分发策略有区别,目前共四种类型:direct、 fanout、topic、headers 。headers 匹配 AMQP 消息的 header 而不是路由键, headers 交换器和 direct 交换器完全一致,但性能差很多,目前几乎用不到了,所以直接 看另外三种类型
Direct Exchange:消息中的路由键(routing key)如果和 Binding 中的 binding key 一致, 交换器 就将消息发到对应的队列中。路由键与队 列名完全匹配,如果一个队列绑定到交换 机要求路由键为“dog”,则只转发 routing key 标记为“dog”的消息,不会转发 “dog.puppy”,也不会转发“dog.guard” 等等。它是完全匹配、单播的模式。
Fanout Exchange:每个发到 fanout 类型交换器的消息都 会分到所有绑定的队列上去。fanout 交 换器不处理路由键,只是简单的将队列 绑定到交换器上,每个发送到交换器的 消息都会被转发到与该交换器绑定的所 有队列上。很像子网广播,每台子网内 的主机都获得了一份复制的消息。 fanout 类型转发消息是最快的
Topic Exchange:topic 交换器通过模式匹配分配消息的 路由键属性,将路由键和某个模式进行 匹配,此时队列需要绑定到一个模式上。 它将路由键和绑定键的字符串切分成单 词,这些单词之间用点隔开。它同样也 会识别两个通配符:符号“#”和符号 “*”。#匹配0个或多个单词,*匹配一 个单词。
如何保证消息的可靠传递:
(1)从生产者到broker :消息成功到达会调用confirmCallback 确认模式
(2)从Exchange到Queue:returnCallback 未投递到 queue,会调用returnCallBack()方法
(3)消费端开始手动确认
增加配置:spring.rabbitmq.listener.simple.acknowledge-mode: manual #如果是auto则自动确认
代码中手动确认。成功消费则basicAck,失败则basicReject
basicReject和basicNack的区别:
basicReject:
- 只能拒绝单条消息。
- 当使用
basicReject
方法拒绝消息时,可以通过设置第二个参数requeue
来决定是否将消息重新放入队列。如果设置为true
,则消息会被重新放入队列;如果设置为false
,则消息可能会被丢弃或发送到私信路由。
basicNack:
- 可以批量拒绝多条消息。
basicNack
方法允许您不确认多条消息,通过设置第二个参数multiple
来决定是否应用于多条消息,而第三个参数requeue
则决定是否将消息重新放入队列。- 与
basicReject
相比,basicNack
提供了更灵活的方式来处理多条消息,尤其是在需要批量处理或拒绝消息时 - 死信Exchange。
multiple为true表示批量确认,即确认此消息的tag号及其之前的所有消息,有的想TCP通信中的确认。如果multiple为false,则表示只确认当前这一条消息
同时为了保证机器断点消息也不丢失,queue 和 exchange 应设置为durable,message 具有 persistent 属性。
死信:因为队列装不下了、超时、或者手动reject并且requeue设置为false,都会导致消息变成死信。队列如果没有设置对应的死信路由,则直接丢弃;否则就发给死信路由。
死信路由Dead Letter Exchange其实就是一种普通的exchange,和创建其他 exchange没有两样。只是在某一个设置Dead Letter Exchange的队列中有 消息过期了,会自动触发消息的转发,发送到Dead Letter Exchange中去。
常见问题
一、消息丢失
为了保证可靠传输,除了上述的消息确认机制外,还需做好容错方法(try-catch),因为网络波动等原因直接在发送端就没能发送消息是常有的情况,这时候需要有重试机制。如果网络长时间不通,可以将发送失败的消息直接写入数据库,然后定期扫描对应表进行处理。
二、消息重复
(1)消费接口做好幂等性
(2)防重表:比如要发一个订单创建消息,发送前先往一个防重表中插入订单编号,并且表约束设置了订单编号为唯一索引,如果插入成功,则发送消息;如果插入失败,捕获唯一索引异常,直接返回成功。当然这里要考虑如果插入了防重表,但消息没发送成功呢?所以一定要加上事务,并且在没发送成功时确保抛出异常,以保证数据库回滚。
(3)消息头中有个redelivered字段,可以获取来辅助判断
三、消息积压
(1)上线更多的消息者
(2)先取出来放到数据库中,后面慢慢消费
标签:交换器,复习,Exchange,队列,绑定,RabbitMQ,消息,路由 From: https://blog.csdn.net/m0_63246220/article/details/140447393