消息队列摘要
1,为什么要使用消息队列
解耦、弹性伸缩、冗余存储、流量削峰、异步通信、数据同步
(1) 解耦
将消息写入消息队列,需要消息的系统自己从消息队列中订阅,原系统不需要做任何修改。
(2) 异步
将消息写入消息队列,非必要的业务逻辑以异步的方式运行,加快响应速度
(3) 削峰
并发请求到消息队列,业务系统按照实际处理能力从消息队列拉去数据。
2,使用了消息队列会有什么缺点
系统可用性降低: 消息队列如果宕机,系统直接崩溃,因此,系统可用性降低
系统复杂性增加: 要多考虑的问题,比如一致性问题、如何保证消息不被重复消费,如何保证保证消息可靠传输。因此,需要考虑的东西更多,系统复杂性增大。
3,消息队列如何选型
中小型软件公司:建议选RabbitMQ
大型软件公司:根据具体使用在rocketMq和kafka之间二选一
4,如何保证消息队列是高可用的
参考具体的消息队列高可用方案
5,如何保证消息不被重复消费
即保证消息队列的幂等性。
正常情况下,消费者在消费消息时候,消费完毕后,会发送一个确认信息给消息队列,消息队列就知道该消息被消费了,就会将该消息从消息队列中删除。只是不同的消息队列发送的确认信息形式不同,例如RabbitMQ是发送一个ACK确认消息,RocketMQ是返回一个CONSUME_SUCCESS成功标志,kafka实际上有个offset的概念,简单说一下(如果还不懂,出门找一个kafka入门到精通教程),就是每一个消息都有一个offset,kafka消费过消息后,需要提交offset,让消息队列知道自己已经消费过了。那造成重复消费的原因?,就是因为网络传输等等故障,确认信息没有传送到消息队列,导致消息队列不知道自己已经消费过该消息了,再次将该消息分发给其他的消费者。
解决:
- (1) 拿到这个消息做数据库的insert操作,分配这个消息一个唯一主键,如果出现重复消费,则会导致主键冲突。
- (2) redis的set的操作,无论set几次结果都是一样的,set操作本来就算幂等操作。
- (3) 消费记录,以redis为例,给消息分配一个全局id,只要消费过该消息,将<id,message>以K-V形式写入redis。那消费者开始消费前,先去redis中查询有没消费记录即可。
6,保证消费的可靠性传输
- (1)生产者丢数据
- (2)消息队列丢数据
- (3)消费者丢数据
如何保证消息的顺序性
通过某种算法,将需要保持先后顺序的消息放到同一个消息队列中(kafka中就是partition,rabbitMq中就是queue)。然后只用一个消费者去消费该队列。
参考: