什么是消息中间件

Message Queue,消息队列是基础数据结构中“先进先出”的一种数据结构。一般用来解决应用解耦,异步消息,流量削峰等问题,实现高性能,高可用,可伸缩和最终一致性架构。实现消息队列的框架通常被称为“消息中间件”。

主要特点:

1. 分布式:消息中间件都是分布式的,因此才可以提供异步、解耦等功能。
2. 可靠性:基于消息的通信是可靠的,消息不会丢失。大多数消息中间件都提供将消息持久化到磁盘的功能。
3. 异步:通过消息中间件,可将远程同步调用拆解成为异步调用。对于不需要获取远程调用结果的应用场景来说,性能提升明显。
4. 松耦合:消息直接由中间件存储和分发。消息生产者只需关注如何将消息发送给消息中介服务器;消费者只需关注如何从中介服务器订阅。生产者和消费者之间是完全解耦的,不需要知道彼此的存在。
5. 事件驱动:可以将复杂的应用系统重构成为事件驱动的系统。事件溯源(Event Sourcing),表示一个对象从创建到消亡,会经过的多种状态。如果把对象的状态变化都存储下来,不但可以根据状态变化记录获取对象的当前状态,也可以回溯对象的变化过程。消息中间件能很好地支持这样的系统设计方式,将触发对象状态变化的事件放入消息队列。

消息中间件的组成

  • Broker:消息服务器,作为server提供消息核心服务
  • Producer:消息生产者,业务的发起方,负责生产消息传输给broker,
  • Consumer:消息消费者,业务的处理方,负责从broker获取消息并进行业务逻辑处理
  • Topic:主题,发布订阅模式下的消息统一汇集地,不同生产者向topic发送消息,由MQ服务器分发到不同的订阅者,实现消息的 广播
  • Queue:队列,PTP模式下,特定生产者向特定queue发送消息,消费者订阅特定的queue完成指定消息的接收
  • Message:消息体,根据不同通信协议定义的固定格式进行编码的数据包,来封装业务数据,实现消息的传输

    消息中间件的两种模式

  • p2p模式 (点对点)

  • pub/sub模式 (发布订阅)

    P2P模式

    P2P模式包含三个角色:消息队列(Queue),发送者(Sender),接收者(Receiver)。每个消息都被发送到一个特定的队列,接收者从队列中获取消息。队列保留着消息,直到他们被消费或超时。
    P2P的特点:
    每个消息只有一个消费者(Consumer)(即一旦被消费,消息就不再在消息队列中)
    发送者和接收者之间在时间上没有依赖性,也就是说当发送者发送了消息之后,不管接收者有没有正在运行它不会影响到消息被发送到队列
    接收者在成功接收消息之后需向队列应答成功。如果希望发送的每个消息都会被成功处理的话,那么需要P2P模式。

    Pub/Sub模式

    Pub/Sub模式包含三个角色:主题(Topic),发布者(Publisher),订阅者(Subscriber) 。多个发布者将消息发送到Topic,系统将这些消息传递给多个订阅者。
    Pub/Sub的特点:

  • 每个消息可以有多个消费者

  • 发布者和订阅者之间有时间上的依赖性。针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息。
  • 为了消费消息,订阅者必须保持运行的状态。
  • 如果希望发送的消息可以不被做任何处理、或者只被一个消息者处理、或者可以被多个消费者处理的话,那么可以采用Pub/Sub模型。

    消息中间件相关概念

    消息中间概述

  • 关注数据的发送和接受,利用高效可靠的异步消息传递机制集成了分布式系统

    什么是JMS?

  • Java消息服务(Java Message Service),是一个Java平台中关于面向消息的中间件的API,用于两个应用程序之间或者分布式 系统中发布消息,进行异步通信。

    什么是AMQP?

  • AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。 基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。Erlang中的实现有 RabbitMQ等。

    JMS和AMQP的比价

    MQ-消息队列 - 图1

MQ协议

协议是什么

协议是计算机之间通信时共同遵循的一组约定,遵循相同的约定,计算机之间才能交流。
协议是对数据格式和对交换数据时必须遵守的规则的正式描述,简单来说协议就是规则。

协议三要素

  1. 语法:即数据与控制信息的结构或格式
  2. 语义:即需要发出何种控制信息、完成何种动作及做出何种反应
  3. 时序:即事件实现顺序的详细说明

以 HTTP 协议为例

  • 语法:HTTP 规定了请求报文和响应报文的具体格式
  • 语义:客户端主动发起的操作成为请求
  • 时序:一个请求对应一个响应

    消息中间件常用的协议

    OpenWire、AMQP、MQTT、Kafka、OpenMessage
    思考:为什么消息中间件不直接使用 HTTP 协议?

    协议介绍

    AQMP 协议

    AMQP(Advanced Message Queuing Protocol)是高级消息队列协议
    04年 JpMorgan Chase(摩根大通集团)联合其他公司共同设计。
    特性:
    事务支持、持久化支持,出生于金融行业,在可靠性消息处理上有天然的优势。
    RabbitMQ、ActiveMQ 实现了此协议

    MQTT 协议

    MQTT(Message Queuing Telemetry Teansport)消息队列遥测传输
    是 IBM 开发的一个即使通讯协议,物联网系统架构中的重要组成部分。
    特性:
    轻量、结构简单、传输快、没有事务支持、没有持久化相关设计。
    应用场景:
    适用于计算能力有限、低带宽、网络不稳定的场景。
    RabbitMQ、ActiveMQ 实现了此协议

    OpenMessage 协议

    OpenMessage 是近一两年由阿里发起,与雅虎、滴滴出行、Streamlio 等公司共同参与创立的分布式消息中间件、流处理领域的应用开发标准。
    特性:
    结构简单、解析快、有事务设计、有持久化设计
    RocketMQ 实现了此协议

    Kafka 协议

    Kafka 协议是基于 TCP 的二进制协议。消息内部是通过长度来分隔,由一些基本数据类型组成。
    特性:
    结构简单、解析快、无事务设计、有持久化设计
    Kafka 实现了此协议

    持久化

    简单来说就是将数据存入磁盘,而不是存在内存中随服务重启而消失,使数据能够永久保存叫做持久化。

MQ-消息队列 - 图2

常用消息中间件支持的持久化方式

- ActiceMQ RabbitMQ Kafka RocketMQ
文件系统 支持 支持 支持 支持
数据库 支持 / / /

消息分发

常用消息中间件的分发策略
- ActiveMQ RabbitMQ Kafka RocketMQ
发布订阅 支持 支持 支持 支持
轮询分发 支持 支持 支持 /
公平分发 / 支持 支持 /
重发 支持 支持 / 支持
消息拉取 / 支持 支持 支持
  • 发布订阅:当多个系统连接到消息中间件时,通过发布订阅知道消息是要发送给谁。
  • 轮询分发、公平分发:当有多个节点有相同的订阅,是大家公平的接收,还是通过权重计算分发的对象。
  • 重发:当由于系统原因导致异常,消息中间件可以重发这条数据
  • 消息拉取:消息是主动分发,还是客户端主动拉取数据

    高可用

    高可用性,指的是产品在规定的条件和规定的时刻或时间区间内,处于可执行规定状态功能的能力。
    当业务量大时,一台消息中间件服务器可能无法满足需求,所以需要消息中间件能够集群部署,来达到高可用目的。

    Master-Slave 主从共享数据部署方式

    MQ-消息队列 - 图3

和数据库主从类似,但这里是共享数据,读取同一份数据源,当一台挂了,就切换到其他服务器,但数据还是同一份

Master-Slave 主从同步部署方式

MQ-消息队列 - 图4

和数据库主从一样,数据库会同步到 slave 上

Broker-Cluster 多主集群同步部署方式

MQ-消息队列 - 图5

多个服务器可以同时接收不同消费者的请求,数据会在每个服务器上备份

Broker-Cluster 多主集群转发部署方式


MQ-消息队列 - 图6

服务器可以将请求转发给其他服务器,可以选择转发数据或者转发请求,若转发请求的话,则所有服务器公用同一份数据。

Master-Slave 与 Broker-Cluster 结合

MQ-消息队列 - 图7

同时实现负载均衡和数据的备份

主流的消息中间件?

当前业界比较流行的开源消息中间件包括:ActiveMQ、RabbitMQ、RocketMQ、Kafka等。Redis在某种程度上也可以是实现类似 “Queue” 和“ Pub/Sub” 的机制,严格意义上不算消息中间件。

RabbitMQ

RabbitMQ 开始是用在电信业务的可靠通信的,也是少有的几款支持AMQP协议的产品之一。
优点:

  • 轻量级,快速,部署使用方便
  • 支持灵活的路由配置。RabbitMQ中,在生产者和队列之间有一个交换器模块。根据配置的路由规则,生产者发送的消息可以发送到不同的队列中。路由规则很灵活,还可以自己实现。
  • RabbitMQ的客户端支持大多数的编程语言。

缺点:

  • 如果有大量消息堆积在队列中,性能会急剧下降
  • RabbitMQ的性能较差,每秒处理几万到几十万的消息。如果应用要求高的性能,不要选择RabbitMQ。
  • RabbitMQ是Erlang开发的,功能扩展和二次开发代价很高。

    RocketMQ

    RocketMQ 是一个开源的消息队列,使用 java 实现。借鉴了 Kafka 的设计并做了很多改进。
    优点:

  • RocketMQ 主要用于有序,事务,流计算,消息推送,日志流处理,binlog分发等场景。经过了历次的双11考验,性能,稳定性可可靠性没的说。

  • RocketMQ 几乎具备了消息队列应该具备的所有特性和功能。
  • java 开发,阅读源代码、扩展、二次开发很方便。
  • 对电商领域的响应延迟做了很多优化。在大多数情况下,响应在毫秒级。如果应用很关注响应时间,可以使用RocketMQ。
  • 性能比RabbitMQ高一个数量级,每秒处理几十万的消息。

缺点:

  • 跟周边系统的整合和兼容不是很好。

    Kafka

    Kafka的可靠性,稳定性和功能特性基本满足大多数的应用场景。跟周边系统的兼容性是数一数二的,尤其是大数据和流计算领域,几乎所有相关的开源软件都支持Kafka。Kafka是Scala和Java开发的,对批处理和异步处理做了大量的设计,因此Kafka可以得到非常高的性能。它的异步消息的发送和接收是三个中最好的,但是跟RocketMQ拉不开数量级,每秒处理几十万的消息。如果是异步消息,并且开启了压缩,Kafka最终可以达到每秒处理2000w消息的级别。
    优点:

  • 支持多个生产者和消费者

  • 支持broker的横向拓展
  • 副本集机制,实现数据冗余,保证数据不丢失
  • 通过topic将数据进行分类
  • 通过分批发送压缩数据的方式,减少数据传输开销,提高吞高量
  • 支持多种模式的消息
  • 基于磁盘实现数据的持久化
  • 高性能的处理信息,在大数据的情况下,可以保证亚秒级的消息延迟
  • 一个消费者可以支持多种topic的消息
  • 对CPU和内存的消耗比较小
  • 对网络开销也比较小
  • 支持跨数据中心的数据复制
  • 支持镜像集群

缺点:

  • 由于是批量发送,所以数据达不到真正的实时
  • 对于mqtt协议不支持
  • 不支持物联网传感数据直接接入
  • 只能支持统一分区内消息有序,无法实现全局消息有序
  • 监控不完善,需要安装插件
  • 需要配合zookeeper进行元数据管理
  • 会丢失数据,并且不支持事务
  • 可能会重复消费数据,消息会乱序,可用保证一个固定的partition内部的消息是有序的,但是一个topic有多个partition的话,就不能保证有序了,需要zookeeper的支持,topic一般需要人工创建,部署和维护一般都比mq高。、

引入MQ优缺点

优点:

  • 解耦
  • 消峰

缓冲池的作用,类似缓存,提供高并发的可能性。

缺点

  • 系统总体复杂性会提高
  • 系统总体可用性会降低
  • MQ自身的一系列问题
    • 消息丢失
    • 分布式数据一致性问题
    • 消息消费顺序
    • 消息积压
    • 消息重复消费,幂等性