死信队列
DLX,全称为Dead-Letter-Exchange,可以称之为死信交换器,也有人称之为死信邮箱。当消息在一个队列中变成死信(deadmessage)之后,它能被重新被发送到另一个交换器中,这个交换器就是DLX,绑定DLX的队列就称之为死信队列。
消息变成死信一般是由于以下几种情况:
- 消息被拒绝(Basic.Reject/Basic.Nack),井且设置requeue参数为false;
- 消息过期; (队列过期被删除不属于死信)
- 队列达到最大长度。
DLX也是一个正常的交换器,和一般的交换器没有区别,它能在任何的队列上被指定。
实现延迟任务
DelayQueue
优点:实现简单、性能很好;
缺点:异常恢复困难、分布式/集群实现困难。
Redis sortedSet
优点:解耦、异常恢复、扩展性强、支持分布式/集群环境;
缺点:增加Redis维护、占用宽带、业务异常处理;
RabbitMQ TTL+DLX
优点:解耦、异常恢复、扩展性强、支持分布式/集群环境;
缺点:增加RabbitMQ维护、占用宽带;
RabbitMQ的RPC实现
客户端发送请求消息,服务端回复响应的消息。为了接收响应的消息,我们需要在请求消息中发送一个回调队列,可以使用默认的队列。
replyTo:通常用来设置一个回调队列,用于客户端获取响应信息。
correlationId:用来关联请求(request)和其调用RPC之后的回复(response),保证请求与响应是对应的。
持久化
将交换器、队列和消息都设置为持久化之后,就能保证数据一定不会丢失吗?
数据丢失的情况:
- 设置autoAck参数为true,当消费者接收到相关消息,还没来得及处理时,消费者宕机了;
解决方案:autoAck设置为false,消费者正确处理完消息后再通知服务端删除消息。 - 在持久化的消息正确存入RabbitMQ之后,还有一段时间(很短)才能存入磁盘。RabbitMQ并不会将每条消息都进行同步存盘处理,可能只是保存到操作系统缓存之中,而不是物理磁盘。如果这个时间点,RabbitMQ服务器出现宕机等异常情况,那么消息将丢失。
解决方案:发送端确认机制。
发送方确认机制
RabbitMQ事务
channel.txSelect() 用于将当前信道设置成事务模式;
channel.txCommit() 用于提交事务;
channel.txRollback() 用于事务回滚。
事务,保证Product发送消息的业务操作完全正确执行后,发送到RabbitMQ的数据才是有效的。
发送方确认
AMQP协议层提供了事务机制来保障生产者发送的消息真正达到了RabbitMQ,但采用事务机制实现将严重影响RabbitMQ的消息吞吐量,RabbitMQ引入了另一种轻量级方式——发送方确认(publisher confirm)机制。
发送方确认机制实现方式:
生产者调用channel.confirmSelect()方法(Confirm.Select命令)将信道设置为发送方确认模式。
确认消息成功发送[channel.waitForConfirms()]:
(1) boolean waitForConfirms() throws InterruptedException;
(2) boolean waitForConfirms(long timeout) throws InterruptedException,TimeoutException;
(3) void waitForConfirmsOrDie() throws IOException, InterruptedException;
(4) void waitForConfirmsOrDie(long timeout) throws IOException, InterruptedException,TimeoutException;
发送方确认 机制三种实现方式:
- 单条确认机制:性能较差,实现简单;
- 批量confirm:性能一般,实现简单;
- 异步confirm:性能最好,实现较复杂。