什么是消息队列?
分布式系统通信有两种方式:直接的远程调用、间接的第三方通信。
而消息队列(MQ)就是这样一个存储消息的第三方中间件。
通俗的理解,MQ的最重要作用就是缓冲消息,你不必直接将消息即时的发给谁,而是将消息发给MQ进行管理,另一方会在合适的时间将消息拿走。
MQ的优势
1)应用解耦
订单系统将消息发送给库存系统、支付系统、物流系统,所以它们是耦合在一起的。当库存系统出了问题,会导致订单系统出错,进而整个系统就全部瘫痪了。
中间件正是解耦的常用手段。改造后的系统中,订单系统将消息发送给MQ即可,其余的系统独立的从MQ中取出消息。这样,如果库存系统出错,并不会影响到任何其他系统,我们在该错误造成严重影响前将其偷偷修复即可,并不需要停下整个系统的运行。
也就是说,整个系统的容错性和可维护性得到了提高。
2)异步提速
未使用MQ,消息严格按照顺序进行同步发送。一个用户点击下单后,他需要等待(20+300+300+300=920ms)后才能得到响应反馈!
但实际生活中,我们并不需要这么久啊?这是系统的一个小把戏。点击下单后,其实根本没有走完整个流程,就给你反馈了!事实上,你只等待了(20+5=25ms)的时间。
这种小把戏极大提高了用户体验,因为响应时间极短。
3)削峰填谷
假设订单系统每秒最多处理1000个请求消息,而这时总共有5000个请求消息发来,订单系统不就爆炸了吗?那么各种抢购活动、秒杀活动,是如何解决这个问题的?
这里就体现了中间件的缓冲作用——在MQ中存储这5000个请求消息,然后订单系统每秒从MQ中拉取1000个请求即可;直到MQ中积压的消息都被拿走。
看看下面的图,你立即理解为什么这被称为“削峰填谷”。
MQ的劣势
1)系统可用性降低
系统引入的外部依赖越多,系统稳定性越差。这是不变的定理。一旦MQ宕机,就会造成严重的后果。
2)系统复杂度提高
MQ的加入大大提高了系统的复杂度。使用MQ,比使用Dubbo进行远程调用,在难度上提升了一个档次。
3)一致性问题
A系统通过MQ向B、C、D发送信息,如果B、C系统处理成功,D系统处理失败,那么B、C、D系统的数据就不一致了。
如何保证MQ的高可用?如何保证消息没有被重复消费?如何处理消息丢失的问题?如何保证消息传递的顺序性?如何保证数据处理的一致性?这些,在MQ高级特性中我们会进一步探讨。
理解MQ的使用场景
关于条件
你可能已经注意到了上面的一个小问题,在介绍异步提速计算时间时,我们默认库存系统、支付系统、物流系统是各自独立的从MQ中拿数据并处理业务的,即所谓异步。
这其实就默认了MQ的一个使用条件,从MQ中消费信息的B、C、D系统之间没有同步关系,即下一步动作并不需要上一步动作提供数据。
关于统筹
再思考一个问题,MQ有解耦、提速、削峰等优势,也有着可用性、复杂度、一致性等问题,那么我们在技术选型时,如何决定是否使用MQ?
这很好回答,保证使用MQ获得的效果要超过加入MQ的成本即可;但是根据真实业务场景来统筹MQ的诸多优势和劣势,确实并非易事。
AMQP与JMS
两种主流的MQ实现方式分别基于:
AMQP协议
AMQP是一种协议,即高级消息队列协议(Advanced Message Queuing Protocol)。这是其和JMS的本质差别,AMQP不从API层进行限定,而是直接定义网络交换的数据格式。
JMS规范
JMS是一种接口规范,即Java消息服务(JavaMessage Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
常见的MQ产品
RabbitMQ | ActiveMQ | RocketMQ | Kafka |
---|---|---|---|
Rabbit公司 | Apache基金会 | 阿里巴巴 | Apache基金会 |
基于AMQP | 基于JMS | 基于AMQP | 基于自定义协议 |
Erlang | Java | Java | Java/Scala |
性能天花板,社区活跃 | 老牌产品,稳定性高 | 性能极高,扩展性极佳 | 大数据领域专属 |
🐰 Rabbit~