面试题
如何保证消息没有重复消费?或者说,如何保证消息消费的幂等性?
考察缘由
消息消费,肯定就要考虑到消息是否被重复消费?能不能避免重复消费?或者重复消费了也别造成系统异常可以吗?这个是 MQ 领域的基本问题,其实本质上还是问你使用消息队列如何保证幂等性,这个是你架构里要考虑的一个问题。
面试题剖析
一、重复消费产生的问题描述
因为消息发送是基于网络发送的,假设网络延迟或者网络卡顿,消息发送机制多次重试,消息重复发送的问题不可避免的发生。要直接避免不重复发送基本太难,因为网络环境无法预知,还会使程序复杂度加大,因此默认允许消息重复发送。因此无论是点对点,还是发布/订阅模型,都可能出现生产者发送多条一样的数据到MQ,此时就会出现重复数据。
二、如何保证消息不被重复消费
基于以上问题描述, MQ 自己保证发送的消息不重复,这就需要我们开发来保证的。
2.1、ActiveMQ
消费者接收到消息时,将消息对象进行MD5加密,作为消息唯一性。如果发现messageObj(发送到mq的数据)已经存在,则忽略,进而保证消息不被重复消费。
String md5 = MD5.encrypt(t.getMessageObj());
List list =super.query("SELECT * FROM message_mq WHERE MD5=? AND STATUS>=? AND STATUS<=? ",this, md5, MessageMq.MessageStatus.MESSAGE_STATUS_NORMAL, MessageMq.MessageStatus.MESSAGE_STATUS_HANDLE);
if (list !=null && list.size() >0) {
log.info("已经有相同消息存在,忽略此消息!!! 【MESSAGE_ID】=" + t.getMessageId() +",【MESSAGE_TYPE】=" + t.getMessageType());
return 0;// 已经有相同的消息
}
幂等性:联想到之前数学学习的幂等性,即使公式:f(x)=f(f(x)) 能够成立的数学性质。用在编程领域,则意为对同一个系统,使用同样的条件,一次请求和重复的多次请求对系统资源的影响是一致的。而计算机幂等性,直白讲就是,就一个数据,或者一个请求,给你重复来多次,你得确保对应的数据是不会改变的,不能出错。