• 消息中间件基础


    我们从三个方面了解消息中间件

    what why how

    1.  什么是消息中间件?

    2.  为什么要使用消息中间件?

    3.  怎么用消息中间件?

     

    1. 什么是消息中间件?

    消息中间件是指一种在需要进行网络通信的系统进行通道的建立,数据文件发送的中间件。消息中间件的一个重要作用是可以跨平台操作,为不同操作系统上的应用软件集成提供便利。

    现在越来越多的分布式应用系统采用消息中间件方式来构建,人们通过使用消息中间件把应用扩展到不同的操作系统和不同的网络环境。基于消息的机制更适用于由事件驱动的应用,当一个事件发生时,消息中间件通知服务方应该进行如何操作。

    使用消息中间件编程可以很好地扩展到不同的操作系统和硬件平台上。可以将消息中间件的核心安装在需要进行消息传递的系统上,并在它们之间建立逻辑通道,由消息中间件实现消息发送。消息中间件既可以支持同步方式通讯,又可以支持异步方式通讯,实际上它是一种点到点的机制,因而可以很好地适用于面向对象的编程方式。

     

    当今市面上有很多主流的消息中间件,如老牌的ActiveMQRabbitMQ,炙手可热的Kafka,阿里巴巴自主开发RocketMQ等。

    2.为什么要使用消息中间件?

     

    回答这个问题,其实就是让你先说说消息中间件的常见使用场景,然后结合你们自身系统对应的使用场景,说一下在你们系统中引入消息中间件是解决了什么问题。

    1)系统解耦

     

    假设你有个系统A,这个系统A会产出一个核心数据,现在下游有系统B和系统C需要这个数据。那简单,系统A就是直接调用系统B和系统C的接口发送数据给他们就好了。

    但是现在要是来了系统D、系统E、系统F、系统G,等等,十来个其他系统慢慢的都需要这份核心数据呢?如下图所示:

    一个大规模系统,往往会拆分为几十个甚至上百个子系统,每个子系统又对应N多个服务,这些系统与系统之间有着错综复杂的关系网络。

    如果某个系统产出一份核心数据,可能下游无数的其他系统都需要这份数据来实现各种业务逻辑。

    此时如果你要是采取上面那种模式来设计系统架构,那么绝对你负责系统A的同学要被烦死了。

    先是来一个人找他要求发送数据给一个新的系统H,系统A的同学要修改代码然后在那个代码里加入调用新系统H的流程。

    一会那个系统B是个陈旧老系统要下线了,告诉系统A的同学:别给我发送数据了,接着系统A再次修改代码不再给这个系统B。

    然后如果要是某个下游系统突然宕机了呢?

    系统A的调用代码里是不是会抛异常?那系统A的同学会收到报警说异常了,结果他还要去关注是下游哪个系统宕机了。

    所以在实际的系统架构设计中,如果全部采取这种系统耦合的方式,在某些场景下绝对是不合适的,系统耦合度太严重。

    并且互相耦合起来并不是核心链路的调用,而是一些非核心的场景(比如上述的数据消费,日志等)导致了系统耦合,这样会严重的影响上下游系统的开发和维护效率。

    因此在上述系统架构中,就可以采用MQ中间件来实现系统解耦。

    系统A就把自己的一份核心数据发到MQ里,下游哪个系统感兴趣自己去消费即可,不需要了就取消数据的消费,如下图所示


     

     

     

    2)异步调用

    假设你有一个系统调用链路,是系统A调用系统B,一般耗时20ms;系统B调用系统C,一般耗时200ms;系统C调用系统D,一般耗时2s,如下图所示:

     

    现在最大的问题就是:

    用户一个请求过来巨慢无比,因为走完一个链路,需要耗费:

    20ms + 200ms + 2000ms(2s) = 2220ms,

    也就是2秒多的时间。但是实际上,链路中的系统A调用系统B,系统B调用系统C,这两个步骤起来也就220ms。

    就因为引入了系统C调用系统D这个步骤,导致最终链路执行时间是2秒多,直接将链路调用性能降低了10倍,这就是导致链路执行过慢的罪魁祸首。

    那此时我们可以思考一下,是不是可以将系统D从链路中抽离出去做成异步调用呢?

    其实很多的业务场景是可以允许异步调用的。

    举个例子:你平时点个外卖,咔嚓一下子下订单然后付款了,此时账户扣款、创建订单、通知商家给你准备菜品。

    接着,是不是需要找个骑手给你送餐?那这个找骑手的过程,是需要一套复杂算法来实现调度的,比较耗时。

    但是其实稍微晚个几十秒完成骑手的调度都是ok的,因为实际并不需要在你支付的一瞬间立马给你找好骑手,也没那个必要。

    那么我们是不是就可以把找骑手给你送餐的这个步骤从链路中抽离出去,做成异步化的,哪怕延迟个几十秒,但是只要在一定时间范围内给你找到一个骑手去送餐就可以了。

    这样是不是就可以让你下订单点外卖的速度变得超快?支付成功之后,直接创建好订单、账户扣款、通知商家立马给你准备做菜就ok了,这个过程可能就几百毫秒。

    然后后台异步化的耗费可能几十秒通过调度算法给你找到一个骑手去送餐,但是这个步骤不影响我们快速下订单。

    当然我们不是说那些大家熟悉的外卖平台的技术架构就一定是这么实现的,只不过是用一个生活中常见的例子给大家举例说明而已。

    所以上面的链路也是同理,如果业务流程支持异步化的话,是不是就可以考虑把系统C对系统D的调用抽离出去做成异步化的,不要放在链路中同步依次调用。

    这样,实现思路就是系统A -> 系统B -> 系统C,直接就耗费220ms后直接成功了。

    然后系统C就是发送个消息到MQ中间件里,由系统D消费到消息之后慢慢的异步来执行这个耗时2s的业务处理。通过这种方式直接将核心链路的执行性能提升了10倍。

    整个过程,如下图所示:

    3)流量削峰

    假设你有一个系统,平时正常的时候每秒可能就几百个请求,系统部署在8核16G的机器的上,正常处理都是ok的,每秒几百请求是可以轻松抗住的,

    但是如左图所示,在高峰期一下子来了每秒钟几千请求,瞬时出现了流量高峰,此时你的选择是要搞10台机器,抗住每秒几千请求的瞬时高峰吗?

    那如果瞬时高峰每天就那么半个小时,接着直接就降低为了每秒就几百请求,如果你线上部署了很多台机器,那么每台机器就处理每秒几十个请求就可以了,这不是有点浪费机器资源吗?

    大部分时候,每秒几百请求,一台机器就足够了,但是为了抗那每天瞬时的高峰,硬是部署了10台机器,每天就那半个小时有用,别的时候都是浪费资源的,如下图

    但是如果你就部署一台机器,那会导致瞬时高峰时,一下子压垮你的系统,因为绝对无法抗住每秒几千的请求高峰。

    此时我们就可以用MQ中间件来进行流量削峰。所有机器前面部署一层MQ,平时每秒几百请求大家都可以轻松接收消息。

    一旦到了瞬时高峰期,一下涌入每秒几千的请求,就可以积压在MQ里面,然后那一台机器慢慢的处理和消费。

    等高峰期过了,再消费一段时间,MQ里积压的数据就消费完毕了。

    这个就是很典型的一个MQ的用法,用有限的机器资源承载高并发请求,如果业务场景允许异步削峰,高峰期积压一些请求在MQ里,然后高峰期过了,后台系统在一定时间内消费完毕不再积压的话,那就很适合用这种技术方案。

    3. 怎么用消息中间件?

     

    当前使用较多的 消息队列 有 RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMQ 等,而部分 数据库 如 Redis、MySQL也可实现消息队列的功能

     

    消息中间件组成

    Broker:消息服务器,作为server提供消息核心服务

    Producer:消息生产者,业务的发起方,负责生产消息传输给broker,

    Consumer:消息消费者,业务的处理方,负责从broker获取消息并进行业务逻辑处理

    Topic:主题,发布订阅模式下的消息统一汇集地,不同生产者向topic发送消息,由MQ服务器分发到不同的订阅者,实现消息的广播

    Queue:队列,点对点模式下,特定生产者向特定queue发送消息,消费者订阅特定的queue完成指定消息的接收

    Message:消息体,根据不同通信协议定义的固定格式进行编码的数据包,来封装业务数据,实现消息的传输

    消息中间件模式分类:

    1)点对点:使用queue作为通信载体

    说明: 
    消息生产者生产消息发送到queue中,然后消息消费者从queue中取出并且消费消息。 
    消息被消费以后,queue中不再存储,所以消息消费者不可能消费到已经被消费的消息。 Queue支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费

    2) 发布/订阅

     

    说明:

    消息生产者(发布)将消息发布到topic中,同时有多个消息消费者(订阅)消费该消息。和点对点方式不同,发布到topic的消息会被所有订阅者消费。

    queue实现了负载均衡,将producer生产的消息发送到消息队列中,由多个消费者消费。但一个消息只能被一个消费者接受,当没有消费者可用时,这个消息会被保存直到有一个可用的消费者。

    topic实现了发布和订阅,当你发布一个消息,所有订阅这个topic的服务都能得到这个消息,所以从1到N个订阅者都能得到一个消息的拷贝。

  • 相关阅读:
    机器学习手稿--NumPy篇
    机器学习手稿--PyTorch篇
    算法相关库
    如何保存用户的登录状态
    Go开发新手需知:Printf、Sprintf、Println 的区别
    二、Bean生命周期中AOP的流程
    Spring 注解驱动开发-IOC (精华版)
    我是如何编写流程图程序的?
    微前端架构设计之 WebSocket API 断连后重连的设计方案
    工具-使用distinct方法去重对象List
  • 原文地址:https://www.cnblogs.com/BrokenHeart/p/10827900.html
Copyright © 2020-2023  润新知