赞
踩
原因:网络不稳定导致生产者向Mq发送消息时Mq没有接收成功,但是生产者认为Mq已经成功收到了消息,所以不会再次重新发送消息最终导致消息丢失。
解决方案:
(1).事务机制。
事务机制是同步的所以会很占用资源耗费服务器性能,导致降低Mq的吞吐量,所以不推荐使用。
(2).confirm机制(发布确认机制)。
confirm机制是异步的,生产者发送消息以后不需要等待回调通知Mq就可以继续发送下一个消息,Mq接收到消息后会异步通知给生产者消息接收成功与否。
生产者发送数据之前开启 Mq事务channel.txSelect,如果消息没有成功被Mq接收到,那么生产者会收到异常报错,此时就可以回滚事务 channel.txRollback,然后重试发送消息;如果收到了消息,那么可以提交事务channel.txCommit如下:
在生产者那里设置开启confirm模式之后,如果消息成功写入 Mq中,Mq会给生产者回传一个ack消息,告诉你说这个消息发送成功与否。
原因:Mq接收到生产者发送过来的消息,是存在内存中的,如果没有被消费完,此时Mq宕机了,那么再次启动的时候,原来内存中的那些消息都丢失了。
解决方案:开启Mq的持久化。当生产者把消息成功写入Mq之后,Mq就把消息持久化到磁盘。结合上面的说到的confirm机制,如果开启了消息的持久化,只有当消息成功持久化磁盘之后,才会回调生产者的接口返回ack消息,否则都算失败 。存入磁盘的消息不会丢失,就算Mq挂掉了,重启之后,他会读取磁盘中的消息,不会导致消息的丢失。
持久化配置:
持久化要起作用必须同时设置这两个持久化才行,Mq哪怕是挂了,再次重启,也会从磁盘上重启 恢复queue,恢复这个queue里的数据。
要保证消息不丢失,我们开启队列、消息持久化的同时,也必须要开启 confirm(发布确认)模式。因 为即使我们在生产者中设置了队列持久化、消息持久化,但依然存在消息被传送到队列上,还没来得及存储在磁盘上,队列就宕机了,这种情况下消息也是会丢失的。所以在之前两步的基础上还是进行第三步:发布确认。三步操作加一起才能保证消息 从生产者到Mq服务器这个过程是不丢失的。
原因:如果Mq成功的把消息发送给了消费者,那么Mq的ack机制会自动的返回成功,表明发送消息成功,下次就不会发送这个消息。但如果就在此时,消费者还没处理完该消息,然后宕机了,那么这个消息就丢失了。
解决方案:关闭Mq的自动ack,采用手动ack 。如果你还没处理完,就不会ack,没有调用手动的ack方法,消息会自动重新入队,这个时候mq会把这个消费分配给别的 consumer 去处理,消息是不会丢的。
消息应答机制 :为了保证消息在消费过程中不丢失,rabbitmq 引入消息应答机制,消息应答就是:消费者在接收到消息并且处理该消息之后,告诉 rabbitmq 它已经处理了,rabbitmq 可以把该消息删除了。
手动ack代码:
原因:正常情况下,消费者在消费消息的时候,消费完毕后,(手动应答)会发送一个确认消息给消息队列,消息队列就知道该消息被消费了,就会将该消息从消息队列中删除;但是因为网络传输等故障,确认信息没有传送到消息队列,消息队列不知道消费者已经消费过该消息了,最终导致消息分发给其他的消费者,出现了重复消费。
解决方案:保证消息的幂等性。
以redis为例,给消息分配一个全局id,只要消费过该消息,将<id,message>以K-V形式写入redis。那消费者开始消费前,先去redis中查询有没消费记录即可。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。