消息队列作为系统解耦,流量控制的利器,成为分布式系统核心组件之一。

如果你对消息队列背后的实现原理关注不多,其实了解消息队列背后的实现非常重要。

不仅知其然还要知其所以然,这才是一个优秀的工程师需要具备的特征。

今天,我们就一起来探讨设计一个消息队列背后的技术。

消息队列整体设计思路

主要是设计一个整体的消息被消费的数据流。

这里会涉及到:消息生产Producer、Broker(消息服务端)、消息消费者Consumer。

1.Producer(消息生产者):发送消息到Broker。

2.Broker(服务端):Broker这个概念主要来自于Apache的ActiveMQ,特指消息队列的服务端。

主要功能就是:把消息从发送端传送到接收端,这里会涉及到消息的存储、消息通讯机制等。

3.Consumer(消息消费者):从消息队列接收消息,consumer回复消费确认。

Broker(消息队列服务端)设计重点

1)消息的转储:在更合适的时间点投递,或者通过一系列手段辅助消息最终能送达消费机。

2)规范一种范式和通用的模式,以满足解耦、最终一致性、错峰等需求。

3)其实简单理解就是一个消息转发器,把一次RPC做成两次RPC,发送者把消息投递到broker,broker再将消息转发一手到接收端。

总结起来就是两次RPC加一次转储,如果要做消费确认,则是三次RPC。

为了实现上述消息队列的基础功能:

  • 消息的传输
  • 存储
  • 消费

就需要涉及到如下三个方面的设计:

  • 通信协议
  • 存储选择
  • 消费关系维护

通讯协议

消息Message:既是信息的载体,消息发送者需要知道如何构造消息,消息接收者需要知道如何解析消息,它们需要按照一种统一的格式描述消息,这种统一的格式称之为消息协议。

传统的通信协议标准有XMPP和AMQP协议等,现在更多的消息队列从性能的角度出发使用自己设计实现的通信协议。

1.JMS

JMS(Java MessageService)实际上是指JMS API。JMS是由Sun公司早期提出的消息标准,旨在为java应用提供统一的消息操作,包括创建消息、发送消息、接收消息等。

JMS通常包含如下一些角色:

JMS提供了两种消息模型:

  • 点对点
  • 以及publish-subscribe(发布订阅)模型。

当采用点对点模型时,消息将发送到一个队列,该队列的消息只能被一个消费者消费。

而采用发布订阅模型时,消息可以被多个消费者消费。

在发布订阅模型中,生产者和消费者完全独立,不需要感知对方的存在。

2.AMQP

AMQP是 Advanced Message Queuing Protocol,即高级消息队列协议。

AMQP不是一个具体的消息队列实现,而 是一个标准化的消息中间件协议。

目标是让不同语言,不同系统的应用互相通信,并提供一个简单统一的模型和编程接口。 目前主流的ActiveMQ和RabbitMQ都支持AMQP协议。

AMQP是一种协议,更准确的说是一种binary wire-level protocol(链接协议)。这是其和JMS的本质差别,AMQP不从API层进行限定,而是直接定义网络交换的数据格式。

JMS和AMQP比较

JMS: 只允许基于JAVA实现的消息平台的之间进行通信

AMQP: AMQP允许多种技术同时进行协议通信

3.Kafka的通信协议

Kafka的Producer、Broker和Consumer之间采用的是一套自行设计的基于TCP层的协议。Kafka的这套协议完全是为了Kafka自身的业务需求而定制的。

存储选型

对于分布式系统,存储的选择有以下几种

  • 内存
  • 本地文件系统
  • 分布式文件系统
  • nosql
  • DB

从速度上内存显然是最快的,对于允许消息丢失,消息堆积能力要求不高的场景(例如日志),内存会是比较好的选择。

DB则是最简单的实现可靠存储的方案,很适合用在可靠性要求很高,最终一致性的场景(例如交易消息),对于不需要100%保证数据完整性的场景,要求性能和消息堆积的场景,hbase也是一个很好的选择。

理论上,从速度来看,文件系统>分布式KV(持久化)>分布式文件系统>数据库,而可靠性却截然相反。

还是要从支持的业务场景出发作出最合理的选择,如果你们的消息队列是用来支持支付/交易等对可靠性要求非常高,但对性能和量的要求没有这么高,而且没有时间精力专门做文件存储系统的研究,DB是最好的选择。

对于不需要100%保证数据完整性的场景,要求性能和消息堆积的场景,hbase也是一个很好的选择,典型的比如 kafka的消息落地可以使用hadoop。

消费关系处理

现在我们的消息队列初步具备了转储消息的能力。

下面一个重要的事情就是解析发送接收关系,进行正确的消息投递了。

市面上的消息队列定义了一堆让人晕头转向的名词,如JMS 规范中的Topic/Queue,Kafka里面的Topic/Partition/ConsumerGroup,RabbitMQ里面的Exchange等等。

抛开现象看本质,无外乎是单播与广播的区别。

所谓单播,就是点到点;而广播,是一点对多点。

为了实现广播功能,我们必须要维护消费关系,通常消息队列本身不维护消费订阅关系,可以利用zookeeper等成熟的系统维护消费关系,在消费关系发生变化时下发通知。

消息队列需要支持高级特性

除了上述的消息队列基本功能以外,消息队列在某些特殊的场景还需要支持事务,消息重试等功能。

  • 消息的顺序
  • 投递可靠性保证
  • 消息持久化
  • 支持不同消息模型
  • 多实例集群功能
  • 事务特性等

如何从0到1设计一个MQ消息队列的更多相关文章

  1. 如何从0到1设计一个类Dubbo的RPC框架

    之前分享了如何从0到1设计一个MQ消息队列,今天谈谈"如何从0到1设计一个Dubbo的RPC框架",重点考验: 你对RPC框架的底层原理掌握程度. 以及考验你的整体RPC框架系统设 ...

  2. Java语言快速实现简单MQ消息队列服务

    目录 MQ基础回顾 主要角色 自定义协议 流程顺序 项目构建流程 具体使用流程 代码演示 消息处理中心 Broker 消息处理中心服务 BrokerServer 客户端 MqClient 测试MQ 小 ...

  3. 设计一个MQ的考虑点

    转自: https://segmentfault.com/a/1190000004461970 序 这里总结下MQ的研究点,以及如果要自己设计一个MQ应该考虑的因素. 考虑点 1.远程通信功能 (1) ...

  4. 高并发架构系列:如何从0到1设计一个类Dubbo的RPC框架

    在过去持续分享的几十期阿里Java面试题中,几乎每次都会问到Dubbo相关问题,比如:“如何从0到1设计一个Dubbo的RPC框架”,这个问题主要考察以下几个方面: 你对RPC框架的底层原理掌握程度. ...

  5. 一个用消息队列 的人,不知道为啥用 MQ,这就有点尴尬

    消息队列 为什么写这篇文章? 博主有两位朋友分别是小A和小B: 小A,工作于传统软件行业(某社保局的软件外包公司),每天工作内容就是和产品聊聊需求,改改业务逻辑.再不然就是和运营聊聊天,写几个SQL, ...

  6. 手把手教你用redis实现一个简单的mq消息队列(java)

    众所周知,消息队列是应用系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构.目前使用较多的消息队列有 ActiveMQ,RabbitMQ,Zero ...

  7. IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

    1.引言 消息是互联网信息的一种表现形式,是人利用计算机进行信息传递的有效载体,比如即时通讯网坛友最熟悉的即时通讯消息就是其具体的表现形式之一. 消息从发送者到接收者的典型传递方式有两种: 1)一种我 ...

  8. 多维度对比5款主流分布式MQ消息队列,妈妈再也不担心我的技术选型了

    1.引言 对于即时通讯网来说,所有的技术文章和资料都在围绕即时通讯这个技术方向进行整理和分享,这一次也不例外.对于即时通讯系统(包括IM.消息推送系统等)来说,MQ消息中件间是非常常见的基础软件,但市 ...

  9. 使用Rabbit MQ消息队列

    使用Rabbit MQ消息队列 综合概述 消息队列 消息队列就是一个消息的链表,可以把消息看作一个记录,具有特定的格式以及特定的优先级.对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息 ...

随机推荐

  1. Django框架登录验证及产生随机验证码的实例

    1:views视图代码 # 登录验证 def login(request): # 使用ajax请求可以使用判断 # if request.is_ajax(): if request.method == ...

  2. 2019-10-22-Roslyn-打包自定义的文件到-NuGet-包

    title author date CreateTime categories Roslyn 打包自定义的文件到 NuGet 包 lindexi 2019-10-22 19:45:34 +0800 2 ...

  3. MaxCompute Studio使用心得系列7——作业对比

    在数据开发过程中,我们通常需要将两个作业进行对比从而定位作业运行性能或者结果有差异的问题,但是对比作业时需要同时打开两个studio 的tab页,或者两个Logview页,不停切换进行对比,使用起来非 ...

  4. Flask学习之十一 邮件支持

    英文博客地址:blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xi-email-support 中文翻译地址:http://www. ...

  5. win10提示 磁盘包含不是“PARTITION_BASIC_DATA_GUID"类型的分区

    在win10创建新的磁盘分区的时候,有时候会提示 磁盘包含不是"PARTITION_BASIC_DATA_GUID"类型的分区 如果你试了其他方法都不凑效,那么看看你已经有几个盘( ...

  6. 在SQL中number(16,5)中的16和5 及number( 5,-2)中的5和-2是什么意思?

    在SQL中number(16,5)中的16和5 及number( 5,-2)中的5和-2是什么意思? 2018-06-04 19:23:24 xiaonan_IT 阅读数 3672   版权声明:本文 ...

  7. LightOJ 1123 Trail Maintenance

    题意:n个城市m天.每一天修一条道路,输出当前天数的最小生成树,但是这里有一个条件,就是说最小生成树必须包括全部n个城市,否则输出-1 思路:边数有6000如果每一天跑一次最小生成树的话就接近O(m^ ...

  8. C# TransactionScope 事务类

    微软自带的TransactionScope(.Net Framework 2之后)是个好东东,提供的功能也很强大. 首先说说TransactionScope是什么,并能为我们做什么事情.其实看Tran ...

  9. java接口(interface)

    引入:抽象类是从多个类中抽象出来的模板,若要将这种抽象进行得更彻底,就得用到一种特殊的“抽象类”→ 接口; 例子: 生活中听说过的USB接口其实并不是我们所看到的那些插槽,而是那些插槽所遵循的一种规范 ...

  10. JVM堆内存管理与自定义分配参数详解

    堆内存模型: 在Java中,堆被划分成两个不同的区域:新生代(Young),老年代(Old).而Permanent属于永久代(方法区),不属于堆内存.新生代又被分为了三个区域:Eden,from  s ...