消息队列的流派及分类

文章目录

  • 什么是消息队列
  • 核心概念
  • 消息队列的数据结构
  • 消息队列的两大流派
    • 有 Broker
      • 重 Topic
      • 轻 Topic
    • 无 Broker
  • Actor 模型
    • Actor 是异步的
    • 并发原语
    • 调度

什么是消息队列

MQ (Message Queue),消息队列可以理解为一种在 TCP 协议之上构建的一个 简单的协议,但它又不是具体的通信协议,而是更高层次的 通信模型 即 生产者 / 消费者模型,通过定义自己的生产者和消费者实现消息通信从而屏蔽复杂的底层通信协议;它为分布式应用系统提供异步解耦和削峰填谷的能力,同时也具备互联网应用所需的海量消息堆积、高吞吐、可靠重试等特性

核心概念

  • Topic:消息主题,一级消息类型,生产者向其发送消息
  • 生产者:也称为消息发布者,负责生产并发送消息至 Topic
  • 消费者:也称为消息订阅者,负责从 Topic 接收并消费消息
  • 消息:生产者向 Topic 发送并最终传送给消费者的数据和(可选)属性的组合
  • 消息属性:生产者可以为消息定义的属性,包含 Message Key 和 Tag
  • Group:一类生产者或消费者,这类生产者或消费者通常生产或消费同一类消息,且消息发布或订阅的逻辑一致

消息队列的数据结构

消息队列采用 FIFO 的方式,即 先进先出 的数据结构

消息队列的两大流派

有 Broker

这个流派通常有一台服务器作为 Broker,所有的消息都通过它中转。生产者把消息发送给它就结束自己的任务了,Broker 则把消息主动推送给消费者(或者消费者主动轮询)

重 Topic

kafka、RocketMQ (前身是 ActiveMQ) 就属于这个流派,生产者会发送 KEY 和数据到 Broker,由 Broker 比较 KEY 之后决定给哪个消费者(推送消息给消费者)
消息队列的流派及分类_第1张图片

轻 Topic

这种的代表是 RabbitMQ(或者说是 AMQP),生产者发送 KEY 和数据,消费者定义订阅的队列,Broker 收到数据之后会通过一定的逻辑计算出 KEY 对应的队列,然后把数据交给队列(消费者主动拉取消息)

消息队列的流派及分类_第2张图片

这种模式下解耦了 KEY 和 Queue,在这种架构中 Queue 是非常轻量级的(在 RabbitMQ 中它的上限取决于你的内存),消费者关心的只是自己的 Queue;生产者不必关心数据最终给谁只要指定 KEY 就行了,中间的那层映射在 AMQP 中叫 Exchange

无 Broker

无 Broker 的 MQ 的代表是 ZeroMQ。该作者非常睿智,他非常敏锐的意识到 MQ 是更高级的 Socket,它是解决通讯问题的。所以 ZeroMQ 被设计成了一个 “库” 而不是一个中间件
消息队列的流派及分类_第3张图片

节点之间通讯的消息都是发送到彼此的队列中,每个节点都既是生产者又是消费者。ZeroMQ 做的事情就是封装出一套类似于 Socket 的 API 可以完成发送和读取数据

ZeroMQ 其实就是一个跨语言的、重量级的 Actor 模型邮箱库。你可以把自己的程序想象成一个 Actor,ZeroMQ 就是提供邮箱功能的库;ZeroMQ 可以实现同一台机器的 RPC 通讯也可以实现不同机器的 TCP、UDP 通讯,如果你需要一个强大的、灵活、野蛮的通讯能力,别犹豫 ZeroMQ

Actor 模型

Actor 模式是一个解决分布式计算的数学模型,其中 Actor 是基础,它能回应接收到消息,能够自我决策,创建更多的 Actor,发送更多的消息,决定如何回应下一个接收到的消息。Actor 认为一切皆是 Actor,类似于面向对象认为一切皆 Object 一样。OO 的执行是顺序的,Actor 模型内在设计就是并行的

Actor 可以被认为是在用户空间实现的并发实体,所以它应该是应用级别的线程。如果认同这个观点那么 Actor 要满足的要求 = 操作系统对进程/线程 提出的要求一样

Actor 是异步的

Actor 是计算实体,它回复接收到的消息,能够并行的:

  • 发生有限的消息给其他 Actor
  • 创建有限数目的新 Actor
  • 指定一个消息到达时的行为

这些操作并没有顺序要求,它们能够并行地实施。由于没有对消息的时序做规定,Actor 模式是一种异步模型,发送到 Actor 不等待消息被接收而继续执行。Actor 之间不共享状态,如果想获取其他 Actor 的状态,只能通过消息请求的方式

Actor 在消息内部指定接收消息的 Actor 地址。Actor 可以用自己的地址发送消息,相当于自己接收到自己发送的消息,可以驱动自己的状态

并发原语

操作系统的是通过临界区,锁来定义多线程共享数据模型的。在 Actor 中是通过消息来共享数据的。基于消息传递要求“数据只读”,你发送出去的数据再修改肯定就不对了。但是这一点在 Java 里面无论如何都是做不到的,你不修改变量的引用但是还可以修改变量里面的值,调用对象的方法。

调度

这是最重要的:没有调度,并发实体根本不能称之为并发实体。操作系统中 CPU 是由内核管理的,调度算法是基于时间片来调任务的,内核随时可以剥夺一个任务的 CPU 使用权这就是“抢占”。这一点非常重要,没有这个功能就意味着调度是不公平的。一个任务耗费大量 CPU 会把另个一任务给饿死。但是在用户空间(应用层)很难实现这一点,毕竟 CPU 是不受应用程序的控制的,没有把办法剥夺。抢占看似可有可无,但是没有它就没有“公平调度”,也就谈不上并发。(有任务撑死,有任务饿死)

所谓“公平调度”: 比如写两个 Actor,使用无限循环输出字符串(while(true))会疯狂的吃 CPU,如果是可抢占的公平调度,则 actor1 和 actor2 应该是比较有规律的交替(大家得到的 CPU 时间差不多)

你可能感兴趣的:(编程思想)