消息队列中的可靠性主要是分为三部分:
解决方案主要有以下几部分:
确保生产者发送的消息成功到达mq,避免消息在传输过程中丢失
Channel channel = connection.createChannel();
channel.confirmSelect(); // 开启确认模式
channel.addConfirmListener((sequenceNumber, multiple) -> {
// 消息确认
System.out.println("Message confirmed: " + sequenceNumber);
}, (sequenceNumber, multiple) -> {
// 消息未确认
System.out.println("Message not confirmed: " + sequenceNumber);
});
对消息可靠性要求高的场景,如金融交易、订单处理等
将消息和队列持久化到磁盘,防止mq重启或者崩溃时消息丢失
boolean durable = true;
channel.queueDeclare("my_queue", durable, false, false, null);
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
.deliveryMode(2) // 2 表示持久化消息
.build();
channel.basicPublish("", "my_queue", properties, message.getBytes());
需要保证消息不丢失的场景,如日志存储、重要数据同步
确保消费者成功处理消息之后,mq才会将消息从消息队列中删除,避免消息丢失
boolean autoAck = false; // 关闭自动确认
channel.basicConsume("my_queue", autoAck, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// 处理消息
System.out.println("Received: " + new String(body));
// 手动发送 ack
channel.basicAck(envelope.getDeliveryTag(), false);
}
});
需要确保消息成功处理的场景,如订单处理、消息通知等
处理无法正常消费的消息(被拒绝或者过期),避免消息丢失
Map args = new HashMap<>();
args.put("x-dead-letter-exchange", "my_dlx_exchange"); // 设置死信交换机
args.put("x-dead-letter-routing-key", "my_dlx_routing_key"); // 设置死信路由键
channel.queueDeclare("my_queue", true, false, false, args);
需要处理异常消息的场景,如消息重试,失败信息分析等
当消息处理失败的时候,通过重试机制重新投递消息,确保消息最终被成功处理
channel.basicConsume("my_queue", false, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
try {
// 处理消息
System.out.println("Received: " + new String(body));
channel.basicAck(envelope.getDeliveryTag(), false);
} catch (Exception e) {
// 处理失败,拒绝消息并重新入队
channel.basicNack(envelope.getDeliveryTag(), false, true);
}
}
});
需要重试机制的场景,如网络抖动、依赖服务不可用等
通过集群和经销队里额,确保mq在节点出现故障仍然可以要运行,避免消息丢失。
镜像队列结构是一主多从,所有操作都是主节点完成,然后同步给镜像节 点,如果主节点宕机后,镜像节点会替代成新的主节点
rabbitmqctl join_cluster rabbit@node1
Map args = new HashMap<>();
args.put("x-ha-policy", "all"); // 镜像到所有节点
channel.queueDeclare("my_queue", true, false, false, args);
适用于高可用的场景,如分布式系统、关键业务系统等
在镜像队列主从同步的过程中,会出现在主从同步完成前,主节点就已经宕机,可能出现数据丢失。
我们可以通过仲裁队列来进行解决,和镜像队列一样,都是主从模式,支持主从数据同步但是不一样的点就是主从同步基于Raft协议,强一致性
并且使用起来也非常简单,不需要额外的配置,在声明队列的时候只要指定 这个是仲裁队列即可