什么是消息队列
消息队列(Message Queue 又或者叫做 MQ)
从名字大概猜出来这个是一种存放消息的队列。
- 把数据放到消息队列叫做生产者
- 从消息队列里边取数据叫做消费者
队列是一种先进先出的数据结构并且在java中已经有多种队列的结构了。
那么既然java里有这么多队列类了,那我为什么还要用MQ这种中间件呢? java提供的都是一些简单的内存队列,而 使用MQ有三个优点:解耦、削锋、异步。
解耦
解耦的场景:
有一个系统A,负责向系统B,C发送对象message,这样系统A内部就有BC类的对象用于实现功能。
之后由于业务的变更,B类不再需要A类的message对象了,A也就不用再向B发送了,所以A把与此相关的B类信息都删掉了。
之后又有了D业务,所以A又把D加进来了,之后C又走了,B又回来了,又来了个E......增增删删无穷无尽。
还有另外一个问题,调用系统C的时候,如果系统C挂了,系统A还得想办法处理。如果调用系统D时,由于网络延迟,请求超时了,那系统A是反馈fail还是重试?
上面的情况A系统会频繁地进行修改操作才行,而且如果关联的系统B、C、D有一个出了故障怎么办?A 系统是重发还是先把消息保存起来呢?A要办的事要操心的事太多了。
那么使用了消息队列之后,A只需要将Student放入消息队列中去就可以了,剩下的就再不管了。也就是A只管生产,由谁来获得,谁又不想要了,A都不需要管。同时如果有消费的系统发生了故障A也不会去管。这样就实现了A与其他系统的解耦。
异步
还是上面没有使用MQ的情况,我们假设A生成message需要50ms,调用B接口需要500ms,调用C接口需要300ms,那么需要花费的总时间是50+500+300 = 850ms
我们后来得知,系统A做的是主要的业务,而系统B、C是非主要的业务。比如系统A处理的是订单下单,而系统B是订单下单成功了,那发送一条短信告诉具体的用户此订单已成功。C与B类似。
那么我们为了一些非核心的业务功能就要等待很多时间就有点得不偿失了。
所以为了提升用户的体验和吞吐量,我们可以使用MQ,让A将对象放到消息队列中,再让系统B、C异步地获取消息。
假设系统A生产完了message对象之后放入到消息队列中的时间是60ms,那么花费的总时间就是50+60=110ms。
削锋
假如说我们的系统是一个电商,在某一天搞了一个促销活动,结果导致系统A每秒产生3000条message,而系统B、C每个系统的处理能力是每秒1000条,那么就有1000条数据无法处理,那这就有可能会把系统搞崩溃。
我们可以使用消息队列,A将生成的消息放入到消息队列中,B和C根据自己的处理能力来处理消息,这样就不会导致系统崩溃了。
使用消息队列存在的问题
- 降低了系统的可用性,系统引入的外部依赖越多,越容易出现问题。
- 系统的复杂度提高,使用了消息队列,需要考虑的问题也会变多,比如如何处理重复的消息,如何保证消息可以被消费,消息丢失、顺序性问题等等。
- 一致性问题,系统A写完了消息放入队列中就完了,BC两系统一个消费成功了,另一个没成功,就会导致数据的不一致。