高并发架构系列:如何从0到1设计一个MQ消息队列
消息队列作为系统解耦,流量控制的利器,成为分布式系统核心组件之一。
如果你对消息队列背后的实现原理关注不多,其实了解消息队列背后的实现非常重要。
不仅知其然还要知其所以然,这才是一个优秀的工程师需要具备的特征。
今天,我们就一起来探讨设计一个消息队列背后的技术。
消息队列整体设计思路
主要是设计一个整体的消息被消费的数据流。
这里会涉及到:消息生产Producer、Broker(消息服务端)、消息消费者Consumer。
1.Producer(消息生产者):发送消息到Broker。
2.Broker(服务端):Broker这个概念主要来自于Apache的ActiveMQ,特指消息队列的服务端。
主要功能就是:把消息从发送端传送到接收端,这里会涉及到消息的存储、消息通讯机制等。
3.Consumer(消息消费者):从消息队列接收消息,consumer回复消费确认。
Broker(消息队列服务端)设计重点
1)消息的转储:在更合适的时间点投递,或者通过一系列手段辅助消息最终能送达消费机。
2)规范一种范式和通用的模式,以满足解耦、最终一致性、错峰等需求。
3)其实简单理解就是一个消息转发器,把一次RPC做成两次RPC,发送者把消息投递到broker,broker再将消息转发一手到接收端。
总结起来就是两次RPC加一次转储,如果要做消费确认,则是三次RPC。
为了实现上述消息队列的基础功能:
1)消息的传输
2)存储
3)消费
就需要涉及到如下三个方面的设计:
1)通信协议
2)存储选择
3)消费关系维护
通讯协议
消息Message:既是信息的载体,消息发送者需要知道如何构造消息,消息接收者需要知道如何解析消息,它们需要按照一种统一的格式描述消息,这种统一的格式称之为消息协议。
传统的通信协议标准有XMPP和AMQP协议等,现在更多的消息队列从性能的角度出发使用自己设计实现的通信协议。
1.JMS
JMS(Java MessageService)实际上是指JMS API。JMS是由Sun公司早期提出的消息标准,旨在为java应用提供统一的消息操作,包括创建消息、发送消息、接收消息等。
JMS通常包含如下一些角色:
JMS提供了两种消息模型:
1)点对点
2)以及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自身的业务需求而定制的。
存储选型
对于分布式系统,存储的选择有以下几种
1)内存
2)本地文件系统
3)分布式文件系统
4)nosql
5)DB
从速度上内存显然是最快的,对于允许消息丢失,消息堆积能力要求不高的场景(例如日志),内存会是比较好的选择。
DB则是最简单的实现可靠存储的方案,很适合用在可靠性要求很高,最终一致性的场景(例如交易消息),对于不需要100%保证数据完整性的场景,要求性能和消息堆积的场景,hbase也是一个很好的选择。
理论上,从速度来看,文件系统>分布式KV(持久化)>分布式文件系统>数据库,而可靠性却截然相反。
还是要从支持的业务场景出发作出最合理的选择,如果你们的消息队列是用来支持支付/交易等对可靠性要求非常高,但对性能和量的要求没有这么高,而且没有时间精力专门做文件存储系统的研究,DB是最好的选择。
对于不需要100%保证数据完整性的场景,要求性能和消息堆积的场景,hbase也是一个很好的选择,典型的比如 kafka的消息落地可以使用hadoop。
消费关系处理
现在我们的消息队列初步具备了转储消息的能力。
下面一个重要的事情就是解析发送接收关系,进行正确的消息投递了。
市面上的消息队列定义了一堆让人晕头转向的名词,如JMS 规范中的Topic/Queue,Kafka里面的Topic/Partition/ConsumerGroup,RabbitMQ里面的Exchange等等。
抛开现象看本质,无外乎是单播与广播的区别。
所谓单播,就是点到点;而广播,是一点对多点。
为了实现广播功能,我们必须要维护消费关系,通常消息队列本身不维护消费订阅关系,可以利用zookeeper等成熟的系统维护消费关系,在消费关系发生变化时下发通知。
消息队列需要支持高级特性
1.消息的顺序
2.投递可靠性保证
3.消息持久化
4.支持不同消息模型
5.多实例集群功能
6.事务特性等
除了上述的消息队列基本功能以外,消息队列在某些特殊的场景还需要支持事务,消息重试等功能。
以上就是如何设计一个消息队列MQ的介绍,由于篇幅关系,后续再详解消息队列需要支持的高级特性。
觉得有用请点赞支持,送你[架构学习资料包],资料包内容:
1.最新最全的架构师学习图谱高清版:架构师知识点一目了然;
2.架构师学习专题88期资料合集:配合图谱,学习更科学;
3.程序员高赞的架构师学习图书9本。
高并发架构系列:如何从0到1设计一个MQ消息队列相关推荐
- 高并发架构系列:如何从0到1设计一个类Dubbo的RPC框架
优知学院 2019-01-22 18:43:51 之前持续分享的几十期阿里Java面试题中,几乎每次必问Dubbo,比如:"如何从0到1设计一个Dubbo的RPC框架",其实主要考 ...
- 高并发架构系列:MQ消息队列的12点核心原理总结
2019独角兽企业重金招聘Python工程师标准>>> 消息队列已经逐渐成为分布式应用场景.内部通信.以及秒杀等高并发业务场景的核心手段,它具有低耦合.可靠投递.广播.流量控制.最终 ...
- 高并发架构系列:Spring Cloud的核心成员、以及架构实现详细介绍
高并发架构系列:Spring Cloud的核心成员.以及架构实现详细介绍 什么是微服务 微服务的概念源于Martin Fowler所写的一篇文章"Microservices". 微 ...
- 高并发架构系列:Redis缓存和MySQL数据一致性方案详解
需求起因 在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节.所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库. 这个业务场景,主要 ...
- 高并发架构系列:什么是流量削峰?如何解决秒杀业务的削峰场景
流量削峰的由来 主要是还是来自于互联网的业务场景,例如,马上即将开始的春节火车票抢购,大量的用户需要同一时间去抢购:以及大家熟知的阿里双11秒杀, 短时间上亿的用户涌入,瞬间流量巨大(高并发),比如: ...
- 高并发架构系列:如何解决Redis雪崩、穿透、并发等5大难题
别人用手机刷新闻.刷段子,你用手机刷知识.你会的越多,成功率就越高. 本篇分享大型网站高并发架构设计是如何解决Redis雪崩.穿透.并发等5大难题的,以下,enjoy~ 缓存雪崩 数据未加载到缓存中, ...
- base cap 分布式_高并发架构系列:详解分布式一致性ACID、CAP、BASE,以及区别
在面试环节,经常会问CAP.BASE等相关的分布式理论,其实这些名词主要还是来自于分布式的一致性,今天主要介绍分布式一致性:强一致性.最终一致性.ACID.CAP等理论. 分布式一致性的背景 随着分布 ...
- 高并发架构系列:Redis为什么是单线程、及高并发快的3大原因详解
Redis的高并发和快速原因 1.redis是基于内存的,内存的读写速度非常快: 2.redis是单线程的,省去了很多上下文切换线程的时间: 3.redis使用多路复用技术,可以处理并发的连接.非阻塞 ...
- 高并发用redis还是mysql_高并发架构系列:Redis缓存和MySQL数据一致性方案详解
需求起因 在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节.所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库. 这个业务场景,主要 ...
最新文章
- 为什么Rust连续4年获“最受喜爱编程语言”?
- Python学习前的计划
- SIC插槽,WSIC插槽,XSIC插槽
- 2017上半年软考 第六章 重要知识点
- Objective-C笔记
- springboot 设置server.port不失效原因
- 关于vmware中的centos无法ping通宿主机或者是外网的解决思路
- VS学习笔记(一)创建C++项目
- 怎么清理ug10注册表_鼠标的滚轮失灵了怎么办
- 计算机操作基础知识培训,计算机基础操作技能培训知识要点
- android获取系统剪贴板内容,android系统如何如何恢复剪贴板内容
- userscript ajax,在Greasemonkey的userscript文本追加到一个表单时使用Ajax提交
- 反射+自定义属性拼接sql
- 基于51单片机PWM(即脉冲宽度调制)调速数码管显示测速L298M芯片控制直流电机正反运转的项目
- TJUCTF新生赛-AI安全专栏write up
- 计算机网络相关论文目录怎么弄,如何给你的标书、论文编页码和目录-论文页码设置...
- SpringBoot日志框架篇
- php_game1姓名大战
- java 使用itext合并多个pdf文件成一个pdf
- python爬取前程无忧scrapy存mogondb案例
热门文章
- USART中的SART_IT_RXNE,USART_IT_TC,USART_IT_TXE
- Protocol Buffer数据编码
- mybaits二十六:mybatis,spring整合
- java:栈空间,堆空间,方法区
- SQL Server 死锁的告警监控
- lighttpd防御 Slow HTTP Denial of Service Attack 解决办法
- Spring Boot中验证码实现kaptcha
- Outlook新邮件要双击打开后才显示为已读
- java基础学习(一)方法
- C++ 构造函数的初始化列表