mq服务器如何防止消息丢失,Rabbitmq如何保证消息不丢失

1.mq原则

数据不能多,也不能少,不能多是说消息不能重复消费;不能少,就是说不能丢失数据。如果mq传递的是非常核心的消息,支撑核心的业务,那么这种场景是一定不能丢失数据的。

2.丢失数据场景

丢数据一般分为三种,一种是mq把消息丢了,一种就是消费时将消息丢了。下面从rabbitmq和kafka分别说一下,丢失数据的场景,

A:生产者弄丢了数据

生产者将数据发送到rabbitmq的时候,可能在传输过程中因为网络等问题而将数据弄丢了。

B:rabbitmq自己丢了数据

如果没有开启rabbitmq的持久化,那么rabbitmq一旦重启,那么数据就丢了。所依必须开启持久化将消息持久化到磁盘,这样就算rabbitmq挂了,恢复之后会自动读取之前存储的数据,一般数据不会丢失。除非极其罕见的情况,rabbitmq还没来得及持久化自己就挂了,这样可能导致一部分数据丢失。

C:消费端弄丢了数据

如果一个消费者应用在消费的时候,刚消费到,还没处理,如进程挂了,比如重启了,rabbitmq认为你都消费了,这数据就丢了。

3.如何解决

A:生产者丢失消息

①:可以选择使用rabbitmq提供事务功能,就是生产者在发送数据之前开启事务,然后发送消息,如果消息没有成功被rabbitmq接收到,那么生产者会受到异常报错,这时就可以回滚事务,然后尝试重新发送;如果收到了消息,那么就可以提交事务。

特别说明:AMQP 协议中的事务仅仅是指生产者发送消息给 broker 这一系列流程处理的事务机制,并不包含消费端的处理流程。

channel.txSelect();//开启事物

try{

//发送消息

}catch(Exection e){

channel.txRollback();//回滚事物

//重新提交

}

缺点:rabbitmq事物已开启,就会变为同步阻塞操作,生产者会阻塞等待是否发送成功,太耗性能会造成吞吐量的下降。

②:可以开启confirm模式。在生产者哪里设置开启了confirm模式之后,每次写的消息都会分配一个唯一的id,然后如何写入了rabbitmq之中,rabbitmq会给你回传一个ack消息,告诉你这个消息发送OK了;如果rabbitmq没能处理这个消息,会回调你一个nack接口,告诉你这个消息失败了,你可以进行重试。而且你可以结合这个机制知道自己在内存里维护每个消息的id,如果超过一定时间还没接收到这个消息的回调,那么你可以进行重发。

//开启confirm

channel.confirm();

//发送成功回调

public void ack(String messageId){

}

// 发送失败回调

public void nack(String messageId){

//重发该消息

}

复制代码

二者不同

事务机制是同步的,你提交了一个事物之后会阻塞住,但是confirm机制是异步的,发送消息之后可以接着发送下一个消息,然后rabbitmq会回调告知成功与否。

一般在生产者这块避免丢失,都是用confirm机制。

B:rabbitmq自己弄丢了数据

设置消息持久化到磁盘。设置持久化有两个步骤:

①创建queue的时候将其设置为持久化的,这样就可以保证rabbitmq持久化queue的元数据,但是不会持久化queue里面的数据。

②发送消息的时候讲消息的deliveryMode设置为2,这样消息就会被设为持久化方式,此时rabbitmq就会将消息持久化到磁盘上。

必须要同时开启这两个才可以。

而且持久化可以跟生产的confirm机制配合起来,只有消息持久化到了磁盘之后,才会通知生产者ack,这样就算是在持久化之前rabbitmq挂了,数据丢了,生产者收不到ack回调也会进行消息重发。

C:消费者弄丢了数据

rabbitmq有手动ack机制与自动ack机制来解决消费者弄丢数据:

如果使用rabbitmq提供的ack机制,首先关闭rabbitmq的自动ack,使用手动ack,每次在确保处理完这个消息之后,在代码里手动调用ack。这样就可以避免消息还没有处理完就ack。

但是ack机制在异常情况下可能造成重复消费:当消费者异常断掉连接,但并未挂掉,broker 会得知, 此时broker 尚未获得 ack,那么消息会被重新放入其他队列,这样就导致数据被重复消费了。

应用层解决重复的方式:

专门的 Map 存储:用来存储每个消息的执行状态(用 msgid 区分),执行成功之后更新 Map,有另外消息重复消费的时候,读取 Map 数据判断 msgid 对应的执行状态,已消费则不执行。

业务逻辑判断:消息执行完会更改某个实体状态,判断实体状态是否更新,如果更新,则不进行重复消费。

总结:AMQP 提供的是“至少一次交付”(at-least-once delivery),异常情况下,消息会被重复消费,此时业务要实现幂等性(重复消息处理)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RabbitMQ 中,可以通过以下方式保证生产者和消费者之间的消息传输的可靠性: 1. 消息持久化:生产者可以将消息标记为持久化,确保即使在服务器重启后,消息也不会丢失。在发布消息时,可以设置消息的 delivery mode 为2。 ```java channel.basicPublish(exchange, routingKey, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes()); ``` 2. 消息确认机制:使用消息确认机制可以确保消息已经成功发送到 RabbitMQ 服务器。生产者发送消息后,等待服务器返回确认消息后再继续发送下一条消息。 ```java channel.confirmSelect(); channel.basicPublish(exchange, routingKey, null, message.getBytes()); if (channel.waitForConfirms()) { // 消息发送成功 } else { // 消息发送失败 } ``` 3. 消费者确认机制:消费者在接收到消息后,需要发送确认信号给 RabbitMQ 服务器,告知已经成功处理该消息。只有当消费者发送确认信号后,RabbitMQ 才会将该消息从队列中删除。 ```java channel.basicConsume(queueName, false, new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { // 处理消息 channel.basicAck(envelope.getDeliveryTag(), false); // 发送确认信号 } }); ``` 通过以上机制的组合使用,可以确保消息在生产者与消费者之间的可靠传输。同时,RabbitMQ 也提供了备份交换器、队列镜像等高可用性机制,以进一步增加消息传输的可靠性。 希望这能解答你的问题!如果还有疑问,请随时追问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值