很久以前也写过一篇关于消息队列的文章,这里的文章,这篇文章是对消息队列使用场景,以及一些模型做过一点介绍。
这篇文章将分析消息队列常见问题。
消息队列:利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统集成。
从定义看:它是一种数据交流平台,也是数据通信平台。
然而,数据通信我们可以用http,RPC来进行通信,这些与消息队列有什么区别呢?
最大的区别就是同步和异步。http和RPC一般都是同步,而消息队列是异步。
1.解耦
双方不在基于对方直接通信了,而是基于消息队列来通信,通过MQ解耦了客户端和服务端通信。处理数据的双方关注的点不同了,比如说一个事务,我们只关心核心流程,而需要依赖其他系统但不是那么重要的事情,有通知即可,不需要等待结果。这种消息模型,关心的是通知,而不在意处理过程。也可以用消息队列。
上下游开发人员也可以基于消息队列发送消息,而不需要同步的处理消息了。
2.异步处理
传统的业务逻辑都是基于同步的方式进行处理的。而有了消息队列,就可以把消息存放在MQ里,消息队列的消费者就可以从消息队列中获取数据并进行处理。它不一定要实时处理,可以隔几分钟处理消息队列里的数据。
3.削峰和流控
这里有点像计算机中的硬件,比如CPU和内存,CPU运算速度比内存高N个数量级,那怎么才能缓解两者之间的差异?中间加一个缓存来缓解两者速度的差异。
同理,MQ也可以起到这种作用。对于上下游软件不同的处理速度的差异进行调节。
比如,我们常见的秒杀应用,前端瞬间涌入成千上万的请求,前端可以承受这么大的请求压力,但是复杂的后端系统,肯定会被压垮,从而导致秒杀服务不可以用的情况。为了解决这种前后端处理速度不平衡的差异,导致的服务问题,可以引入消息队列来调节,用消息队列来缓存用户的请求,等待后端系统来消费。
上面就是消息队列的主要功能,当然还有其他一些功能,比如消息广播,最终一致性等。
使用MQ后的问题当然使用了消息队列,会增加系统的复杂性,一致性延迟,可用性降低等问题。
可用性降低是指系统可用性降低,如果MQ挂了,那么肯定会影响到整个系统了。
因为上下游系统可能都会与MQ交互。
这个要看业务系统功能需求,一个是系统处理是否到达了瓶颈,需要消息队列来缓解;
还有,业务系统一致性要求是不是特别高。通常业务系统不会要求那么高的一致性要求。当然一些高频交易系统,一致性要求特别高,就不适合用了。
引入任何一个新的软件必然会增加原有系统的复杂性,还是要根据业务特性进行合理的选择。
四、消息队列常见问题 1.如何保证消息不被重复消费(怎么保证幂等) 为什么会重复消费生产者:也就是客户端,可能会重复推送一条数据到MQ中。有可能是客户端超时重复推送,也有可能是网络比较慢客户端重复推送了数据到MQ中。
MQ:消费者消费完了一条数据,发送ACK信息表示消费成功时,这时候,MQ突然挂了,导致MQ以为消费者还未消费该条消息,MQ恢复后再次推送了该条消息,导致重复消费。
消费者:与上面MQ挂掉情况类似,消费者已经消费完了一条消息,正准备给MQ发送ACK消息但还未发送时,这时候消费者挂了,服务重启后MQ以为消费者还没有消费该条消息,再次推送该条消息。
怎么处理重复消费每个消息都带一个唯一的消息id。消费端保证不重复消费就可以了,即使生产端产生了重复的数据,当然生产端也最好控制下重复数据。
消费端保证不重复消费:
通常方法都是存储消费了的消息,然后判断消息是否存在。
1.先保存在查询
每次保存数据前,先查询下,不存在就插入。这种是并发不高的情况下可以使用。
2.数据库添加唯一约束条件
比如唯一索引
3.增加一个消息表
已经消费的消息,把消息id插入到消息表里面。
为了保证高并发,消息表可以用Redis来存。
生产者:生产者推送消息到MQ中,但是网络出现了故障,比如网络超时,网络抖动,导致消息没有推送到MQ中,在网络中丢失了。又或者推送到MQ中了,但是这时候MQ内部出错导致消息丢失。
MQ:MQ自己内部发生了错误,导致消息丢失。
消费者:有时处理消息的消费者处理不当,还没等消息处理完,就给MQ发送确认信息,但是这时候消费者自身出问题,挂了,确认消息已经发送给MQ告诉MQ自己已经消费完了,导致消息丢失。
如何保证消息不丢失呢? 下面谈谈这方面的做法。
3.如何保证消息可靠性传输整个消息从生产到消费一般分为三个阶段:生产者-生产阶段,MQ-存储阶段,消费者-消费阶段