什么是消息队列
相当于存放消息的一个容器,生产出来的消息都放到这个容器里面,如果我们想使用消息就直接从容器中取即可,是分布式系统中重要的组件,常用的消息队列有ActiveMQ,RabbitMQ,Kafka,RocketMQ。
通过提供消息传递和消息排队模型,它可以在分布式环境下提供应用解耦、弹性伸缩、冗余存储、流量削峰、异步通信、数据同步等等功能。
为什么要使用消息队列
解耦
使用发布订阅模式,生产者发布消息,消费者订阅消息,生产者把消息放到分布式消息队列中就结束了对这个消息的管理,消费者从分布式消息队列中获取消息后进行后续处理,不需要知道这个消息从何而来,两者没有直接耦合
为了避免消息队列服务器宕机造成消息丢失,会将成功发送到消息队列的消息存储在消息生产者服务器上,等消息真正被消费者服务器处理后才删除消息,在消息队列服务器宕机后,生产者服务器会选择分布式消息队列服务器集群中的其他服务器发布消息
异步处理
一些非必要的业务在传统模式中是同步进行的,这样就会很耗费时间,我们可以使用消息队列,将这些业务发到消息队列中我们就可以直接返回,不用关心这些业务怎样运作,由消费者读取消息队列中的业务来异步处理即可,大大缩短了响应时间
场景:
用户支付订单,处理返回订单结果,除了主要业务支付外,在支付完毕后还需要发送优惠券信息,短信信息,邮箱信息这些非必要业务
- 同步
必须要支付、短信、优惠卷、邮箱都发送完毕才返回支付结果,耗时200ms
- 并行
支付业务占用50ms,其他业务并行处理,共耗时100ms
- 异步
我们只需关心主要业务,也就是支付即可,将订单结果发送到消息队列就可以返回了,其他非必要业务由消费者去处理,因为将消息发送到消息队列速度极快,基本上可以忽略,所以最终可能达到50ms就可以把支付结果返回给用户了,响应时间大大缩短
削峰
通过异步处理,我们可以将短时间内高并发产生的事务消息存储到消息队列中,由消费者慢慢处理,以达到削平高峰期的事务的效果
消息队列的一些缺点
- 系统可用性降低
在加入MQ之前,需要考虑消息丢失或者MQ挂掉等情况
- 系统复杂性提高
加入MQ之后,需要保证消息没有被重复消费、处理消息丢失的情况、保证消息传递的顺序性等等问题
- 一致性问题
消息队列可以实现异步,消息队列带来的异步确实可以提高系统响应速度。但是,万一消息的真正消费者并没有正确消费消息怎么办?这样就会导致数据不一致的情况了
JMS两种消息模型
- 点到点(P2P)模型
使用 队列(Queue) 作为消息的载体以保证一个消息由一个消费者使用,未被消费的消息在队列中保留直到被消费
比如有人生产者生产了100个消息,有两个消费者,一般情况下每个消费者都会按照消息发送的顺序各自消费一半(你一个我一个来进行)
- 发布/订阅(Pub/Sub)模型
使用主题(Topic)作为消息的载体,生产者生产一个消息放到消息队列中,主题会通知到每个订阅者,没有订阅的是不会被通知到的
消息队列由哪些角色组成?
- 生产者(Producer):负责产生消息。
- 消费者(Consumer):负责消费消息。
- 消息代理(Message Broker):负责存储消息和转发消息两件事情。其中,转发消息分为推送和拉取两种方式。
常见消息中间件比较
中小型公司建议使用RabbitMQ,一方面,数据量没有大型公司那么大,另一方面,RabbitMQ功能较为完备,性能较强
大型公司建议使用RocketMq或kafka,这两个吞吐量都比较大,可以应对大数据量,RocketMq的源码是java,所以java开发人员可以对其进行定制化开发,如果公司业务中有日志采集功能,那么kafka是首选。