美文网首页消息队列LYQ_JAVA
消息队列(一)——消息队列的应用场景

消息队列(一)——消息队列的应用场景

作者: Jerry_Liang | 来源:发表于2019-12-06 16:32 被阅读0次

    以下是本消息队列系列文章的传送门:

    1. 什么是消息队列


    队列相信大家应该都不陌生,它是一种先进先出的数据结构,基本结构如下图。

    队列

    在java中已经实现了各种各样的队列了,那为什么还需要消息队列MQ(Message Queue)这种中间件呢?我们可以先尝试思考一下消息队列存在的意义,它能满足我们项目中的什么需求,下面我会继续补充。

    消息队列可以简单理解为,我们把想要传输的数据放到队列中(其结构与普通队列是一样的)

    消息队列

    我们将把数据放入到队列的那一方叫做生产者;将从消息队列中取数据的一方叫做消费者

    2. 为什么要使用消息队列


    以下我将通过几个简单的场景来简单说明我们为什么使用消息队列。

    2.1 解耦

    假设我们现在有一个环境数据生成系统A,系统A通过调用系统B和系统C的接口来向系统B、C来发送数据,场景一图如下:


    场景1

    即系统A在有新的环境数据生成时,会通过调用B、C系统的接口来将生成的数据发送给B、C。写成伪代码如下所示(此处不考虑用观察者模式实现解耦并实时通知观察者的情况):

    public class SystemA {
     // 系统B和系统C的依赖
     SystemB systemB = new SystemB();
     SystemC systemC = new SystemC();
     // 系统A独有的数据
     private String environmentData= "data";
     public void doSomething() {
     // 通过调用接口发送数据
     systemB.SystemBNeed2do(environmentData);
     systemC.SystemCNeed2do(environmentData);
     }
    }
    

    这种情况下,会有以下问题:

    • 如果某一天系统B不需要这些数据了,让系统A的负责人将发送数据给他们的那一部分代码给改了,即注释掉systemB.SystemBNeed2do(environmentData);
    • 有新的系统D需要这些数据了,需要增加调用D系统接口来发送数据的代码;
    • 同时,系统A还需要考虑如果其余系统B、C、D的系统如果挂了怎么办,要不要重发。

    从上面的场景可以发现,系统A与其他三个系统高度耦合了。我们试想如下场景二,系统A将最新的环境数据信息放到MQ中,哪个系统需要就可以订阅这个消息消费。如果某个系统不需要这些数据了,就取消对MQ消息的消费即可。这种场景下,A系统完全不需要去考虑将数据发送给谁,也不需要去维护之前发送数据的代码,不需要考虑其他系统是否调用成功、失败超时等情况。

    场景2

    小结
    通过这种模式消息发布与订阅的模式,使得系统A与其他系统解耦。

    2.2 异步

    其实我仔细斟酌了一下异步与解耦的场景,发现其实异步与解耦是有一定关系的,我们使用同样的场景,只是我们考虑的面不同,场景三如下图所示。但我们现在考虑的面是时间效率。


    场景3

    假设系统A产生环境数据需要100ms,调用系统B、C、D的接口分别需要300ms、300ms、300ms,那么在类似场景一的设计方式时,这次请求所需要耗费的时间为100+300+300+300 = 1000ms = 1s。请求会随着需要环境数据的系统越来越多而使得请求响应越来越慢,这是用户不能忍受的,即类似我们去请求一个系统服务,我们主要想要的服务只是系统A生成的环境数据服务,而系统A这个时候却因为其它系统调用而使得这个服务请求响应过慢。

    而如果是类似于如下场景时,我们的响应时间仅仅是产生消息的时间100ms。


    场景4

    小结

    • 同步场景下,整个请求需要耗时1s;
    • 异步场景下,请求只需要100ms。
    2.3 削峰/限流

    我们接着考虑如下场景,假设我们的系统A有个促销功能,大促销期间并发量较大,我们假设每秒可能有5k个请求。如下图。


    场景5

    一般的MySQL,每秒能处理2k个请求就差不多了,如果每秒5k个请求同时处理的话,可能会导致MySQL不可用,导致整个系统崩溃,用户也就没法使用MySQL了。但一过了促销期,每秒请求只有百来个,这个时候对系统几乎没有任何压力。

    如果使用MQ,每秒5k个请求写入MQ,A系统可以根据自身的处理能力来决定每秒拉取的请求数。这样下来,在高峰期时系统A也不会挂掉。


    场景6

    这个短暂的高峰期积压是完全OK的。(消息队列是支持吞高吐量的,为此不用担心这个量的问题,同样,我们可以暂不考虑MQ挂掉的情况)。
    系统A按照它能处理的速率来处理请求。

    小结
    通过将请求放在支持高吞吐量的MQ中来到达削峰/限流的效果。

    2.4 其它应用场景

    • 日志处理:将大量日志存储到消息队列中(一般采用分布式消息队列kafka),解决大量日志传输的问题。其中,消息队列负责日志数据的接收,存储和转发;
    • 消息通讯:点对点通讯或聊天室通讯。

    3. 使用消息队列会有什么优缺点


    优点其实就是上文中谈到的,在特殊场景下的应用好处,解耦、异步与削峰等。

    系统可用性
    系统因为依赖与MQ消息队列这个服务,若这个服务崩溃了,那么我们的整个系统将不可用。为此往往我们都是通过集群/分布式部署来实现MQ高可用的。

    系统复杂度
    我们将数据写到消息队列上,就有可能会存在数据丢失的情况。以及我们如何保证消息没有被重复消费等问题。

    一致性问题
    A系统将请求写入到消息队列后就返回请求成功了,假设在多机部署的时候,系统B、C写库成功,假设D写入失败了,这种情况下就会产生数据不一致的问题。

    4. 后语


    总的来说,虽然引入消息队列有很多好处,但是也得针对它的缺点来引入其它技术方案和架构来规避这些问题,所以我们应该按照我们的实际需求与场景,来选择我们的技术方案。

    本人水平有限,难免有错误或遗漏之处,望大家指正和谅解,欢迎评论留言。

    相关文章

      网友评论

        本文标题:消息队列(一)——消息队列的应用场景

        本文链接:https://www.haomeiwen.com/subject/dvdsgctx.html