【中间件】消息队列中间件intro

中间件middleware

内容管理

    • intro
    • why use MQ
    • MQ实现漫谈
    • 主流消息队列
    • QMQ Intro
    • QMQ架构
    • QMQ 存储模型


本文还是从理论层面分析消息队列中间件


cfeng现在处于理论分析阶段,以中间件例子,之前的blog对于中间件是从使用角度分享了相关的用法,现在就从理论层面分析中间件,后面再从理论出发尝试分析中间件以及实现中间件,这样我们才能更好的自定义相关的功能

intro

消息队列在如今的软件系统中扮演着重要的角色。cfeng之前work中使用RabbitMQ进行的服务通信和解耦,消息队列的发布/订阅模型常常用于服务解耦,众多开源实现(RabbitMQ、RocketMQ、Kafka、QMQ…),都是采用的分布式架构支持弹性高可用。
消息队列的概念很简单: Message Queue,就是消息传播过程中保存消息的一个队列。一端连接生产者,一端连接消费者。

why use MQ

为什么要使用MQ呢,首先就是考虑企业中的应用场景,比如实时索引更新异步化流程… 这些使用MQ就可以轻易解决。 MQ最主要的功能就是异步解耦、流量削峰…

  • 异步: 消息生产者将消息投递到消息队列中,因为可靠性由MQ保证,所以生产者可以继续处理剩余的业务逻辑,提升可靠性,比如注册成功之后发送通知短信…

  • 松耦合: 生产者和消费者不需要知道对方的存在,只需要事先定义好消息的格式,不需要知道对方的实现细节,相比RPC调用强耦合(被调用方异常或者响应慢可能产生回压,甚至雪崩),MQ可以为业务提升稳定性

    cfeng之前work中各个后台系统的通信就采用的MQ进行异步通信,eg: 新增一个用户到系统,需要在主系统中同步,那么我直接在这个队列中增加一条insert的消息,主系统接收即可,因为是异步的,松耦合
    后面这样也出现了问题,本身预算不足,MQ集群规模小,所以MQ的压力增大,后面又改成了PRC调用(Feign)
    
  • 数据分发: Fanout广播,不同的消费者组全量拷贝同一主体的消息队列(topic),并且彼此互不干扰,广播模式的MQ在很多场景下可以发挥重要作用,eg: 对于一个旅游列表变更提供方而言,那么机票、酒店、车票、火车票…等多个业务都不需要轮询旅游业务,就都可以收到变更事件

  • 流量削峰: 消息队列具备积压能力。很多业务像秒杀具有潮汐效应,就是流量成峰谷状,如果实时性要求不高,那么就可以利用Queue的积压能力,进行削峰填谷,就可以不用增加硬件…

  • 可靠投递: 消息队列本身需要考虑的问题就是可靠性,不能够丢失消息。一般成熟的MQ产品都是两次RPC + 一次转储实现整个流程。【生产者投递消息到MQ,MQ作为broker将消息通知给消费者】

在这里插入图片描述

消息队列适用场景

  1. 上下游业务解耦: 订单支付完成后,核心业务完成,但是可能还需要给用户加积分发放优惠劵,这些不是核心逻辑,可靠性要求低,那么就可以引入MQ来进行解耦
  2. 延迟通知: 用户订单下单后可能还没有支付,需要在30分钟内支付,未支付那就取消订单,可以使用延迟MQ实现
  3. 大数据离线分析: 用户的行为日志通过实时系统进入MQ,当业务处于低峰期时且资源充裕,即可进行信息分析
  4. 缓存同步: 类似实时价格变动事件,需要刷新缓存,可以通过MQ广播给消费者,这样就可以不用进行数据库轮询了【轮询会有实时性误差】

MQ实现漫谈

消息队列主要就是一个中间队列,具有积压消息的功能,同时作为系统间的解耦利器,一定是单独部署的。

NoSQL充当消息队列

如果只是需要一个地方进行消息的存取,那么客户端可以直接将消息比如写入MongoDB中,消费者从里面拖出来即可。没有任何的broker代理

一旦升级,涉及大量的客户端【因为代码耦合严重】,消费者之间的协调只能通过DB进行,会涉及DB的modify等操作,性能很低,没有弹性

 producer ------>  ---Mongo DB---  ------> Consumer
                    

引入中间server充当broker

没有server导致MQ只是一个没有弹性的容器,好的MQ应该能够具有消息协调的功能的

producer ------->  Broker --------> consumer
                   |  |
                   Mongo DB

引入一个broker,生产者和消费者直接交互的是borker,那么broker就可以起一个协调作用,客户端很轻,只是和broker通讯,告诉borker需要发消息即可,升级只需要升级borker即可。

但是这里没有binding,一个topic绑定到一个mongo的表上,存储粒度为一个topic【mongo这边消息的清理思路: 分表-- 写了上一张表写下一张表,上一张表直接drop,不用一张表里面insert、delete】

再引入客户端和服务端SDK

上面的还是一个很基础的实现,因为消费者和生产者和Broker的交互性很低,所以borker的协调性很低,那么客户端和服务端引入SDK,制订一套完整的规则,引入binding,加上一些辅助组件,就可以形成一个综合的MQ

 ----------------------   ---> MetaServer -> ----------------------
 |   Producer         |           |          |       Consumer     |
 |      HTTP Recelver |  -----> Broker ----> | Http Deliver       |
 |       APP          |          |           |   App              |
 ----------------------         MySQL        ---------------------

这个也不可能是真正的MQ的架构,只是一个比较抽象的想法。MQ作为成熟的产品,那么就需要具备优秀的性能。需要考虑很多方面的事情:

  • 消息的写入: 消息怎么写入的更快(批量?..)
  • 消息的投递的及时性: 延迟怎么降低 (partition Stick…, 截获代替轮询, Long Pulling…)
  • 集群管理 …

主流消息队列

之前cfeng快速的讲解过Spring中使用RabbitMQ的方式【关键就是binding、exchange和queue,配置的时候一个binding就是将exchange和queue绑定,生产者发送消息的时候指定exchage和bindingKey就可投放到指定的Queue,消费者监听消费Queue中消息即可】

干货|消息队列(一):消息队列优缺点及其选型 - 知乎

可以看到的是Kafka的可用性相比RabbitMQ是非常高的,拥有成熟生态(日志系统、流式系统…、活跃社区)

Kafka主要是Scala实现的,同时能够很好的集成到java生态中
RabbitMQ主要是Erlang实现的,cfeng之前work业务量小采用的该MQ
RocketMQ是ali利用java实现的,具备较高的可靠性
QMQ是qunar利用java是实现的,采用的无序消费存储模型

Kafka

Kafka将一个Topic分成多个Parition,每一个Partition作为一个Broker的物理文件,通过Apend only的方式实现文件顺序写的高性能,线性提高集群单topic的吞吐量。

但是,当Broker上所有的Topic的Partition总和过多时,会产生随机写

Partition 0  |0|1|2|3|4|5|6|7|..     <--------
Partition 1  |0|1|2|3|4|5|6|...      <-------|----  Writes
Partition 2  |0|1|2|3|4|5|6|7|8|...  <-------|
    
Old -----------------------> newKfaka写入消息】

顺序访问和随机访问的性能不同, 随机访问时,需要小号磁头寻道和盘片旋转等待的时间;

SSD使用的是半导体闪存介质,随机访问和顺序访问的差异不大

 硬盘/吞吐		顺序写		随机写		顺序读		随机读
   SATA			125M	   548K		  124M  	466K
   SSD			592M  	   549M		   404M		505M
   
   【使用fio测试工具,每次访问4KB工具】测试开发机磁盘访问速度数据

RocketMQ

RocketMQ吸取了Kafka中多Partition消息文件会导致随机写的教训,采用的是单一消息文件 Commit Log, 将所有Topic的消息在物理上全部顺序追加到Commit Log文件中。

上述操作可以能增加消息写入的吞吐量,但是消费方在消费历史【操作系统Page Cache,正在发生IO条件为未命中Page Cache,实时消费基本不会引入IO】消息时候,会引入随机读。

RocketMQ是一主多从架构,主写从读,只有主节点提供写操作,从节点比较空闲,RocketMQ将历史消息消费通过重定向到从节点 , 来缓解随机读

无论是Kafka还是RocketMQ,都存在一个约束: 一个Partition只能绑定在一个Consumer上

因此: 消费者集群上限是Partition的数目;Partition的均衡性可能导致消费组个别机器的负载高、积压多。

eg: 一个Tpic(cfeng.fx.kafka.example)设置了3个partition(0,1,2),如果消费组(kafka.example.group)初始化两台机器,一台消费者消费一个partition,另一个消费者消费两个partition;   这个时候,如果消费能力不够,那么通过水平扩容消费者的方案 ❌;   此时Kafka | RocketMQ 只能通过 增加partition来进行Rebalance,但Rebalance之后只能对新生产的消息生效, 原本积压的消息不会被Rebalance;  可能会破环消息的顺序性,同时清理积压会对新的消息有积压耗时

partition 1  | | | | | | | | | | |  --------     Consumer 1
partition 2  | | | | | | | | | | |  --------     Consumer 2
partition 3  | | | | | | | | | | |  --------     Consumer 3

生产者通过选定某个字段(如tenant_id)作为Partition Key来决定将消息投递到哪个Partition,因此Partition Key会影响消费速度

eg: 比如一个Partition Key分布不均匀时,就会出现某些Counsmer的消费速度达不到生产速度,也就是消费能力不足,导致消息积压

partition 1  | | | |                --------     Consumer 1
partition 2  | | | | | 			    --------     Consumer 2
partition 3  | | | | | | | | | | | | --------     Consumer 3

这里就发现 Consumer 3 的消费能力不足,出现消息积压,而Consumer 1和2则相对空闲

QMQ Intro

最近cfeng了解架构的时候,就经常浏览github寻找相关的资料进行辅助的study,在探索消息队列的时候,就在gitee上看到了qunar开源的QMQ【其和Hermes的区别就是Hermes是以MySQL作为消息持久化存储,而QMQ则是以磁盘文件进行存储】

QMQ相比其他的MQ比较小众,这里也就简单的探究一下这款MQ产品

事务消息 && 生产者消息可靠投递

一些业务比如订单类型业务对于可靠性的要求很高,一些场景如业务系统宕机或网络暂时不可用时,也需要确保消息可靠投递 — 如何解决?

QMQ的解决方案: 生产者侧引入持久化存储【MySQL、MongoDB…】,发送消息之前,先将消息持久化到存储中,之后再异步化发送消息,当Broker返回消息发送成功的结果之后,将消息从持久化存储中del,当生产者突然宕机,那么负责补发消息的watch dog会代理消息发送的工作

在这里插入图片描述

QMQ同时支持事务消息,依赖的是存储的本地事务,实现分布式事务还可以通过两阶段提交 Two-phase Commit ,但是两阶段提交的对于本地事务来说: 交互过多,流程复杂,性能较低, 并且业务系统大多依赖MySQL进行存储

延迟消息

这是很多MQ都支持的一个特性,比如超时30分钟未支付,订单取消就可以使用延迟MQ进行实现

定时重试

某些业务系统特定的流程,也就是状态机,只有当某个前置条件满足时才会消费这条消息,条件队列, 这个时候不能直接丢弃这种消息, QMQ可以设置定时重试的功能,让业务定时重新进行消费

同机房生产与消费

生产者采用同机房投递的策略,这样可以避免跨机房流量的产生; 消费者默认多机房消费; (消费者不用关心生产者机房部署结构)核心链路的业务支持单元化,只是消费本单元内的消息,可以实现单元隔离

消息检索追踪

消息检索追踪是非常必要的,应该实现离线任务按照时间回溯选择性重发、端到端耗时的长尾问题排查、未消费问题的排查重发、死信重发…

按照时间端筛选消息
记录每条消息的消息ID、创建时间、接收时间、broker组、详细信息,支持重发等操作

也就是MQ具有良好的消息治理功能

同时QMQ还支持广播消息、Server随意扩容等多种特性,再Spring中使用也是annotation化,非常便捷

QMQ架构

QMQ服务端包含3个核心组件: Meta Server、 Broker、 Delay

  • Meta Server : 元信息管理服务, 用于消息路由控制下发,维持Broker和Server的心跳, 还有上下线挂历、消费者进度管理… 当Meta Server检测到Broker或者Delay的心跳失联,那就标记下线

  • Broker是QMQ存储核心, 用于接收消息并持久化到磁盘文件中,创建消息索引,管理消费进度,响应拉取请求。Broker实现HA采用的是主从模式, Master能接收读写请求, (仿照的PacificA实现主从切换…当Master宕机,自动选举新的Master继续服务

  • Delay 是接收延迟消息并持久化到本地磁盘,当超过延迟时间后,消息将被投递到Broker。 Delay的HA也是采用的主从模式,副本保证消息的灾备。

    可以看出延迟消息是剥离的单独的服务【RocketMQ是集成在Broker的逻辑中,RabbitMQ也是在Broker的逻辑中,但是是增加了死信交换机和死信队列】
    QMQ考虑的因素:
    1. 延迟和实时是两种消息类型,隔离可以不互相影响,提高可靠性
    2. 在达到延迟时间时,消费者路由可能发生迁移,如果逻辑耦合在Broker中,那么就需要进行重定向,【单一职责最好】
    
    RabbitMQ模型
    
    					  RabbitMQ broker
    					--------------------------
    producre 1 ---->     |  exchange1  ---> quwuw1 |---> consumer1,2.
    								|    ....   |
    producer 2 ---->     |  exchange2  ---> queue2 |  ---> consumer n
                          -------------------------
    

在这里插入图片描述

QMQ 存储模型

之前提到过Kafka和RocketMQ的存储模型中的Parition缺点,QMQ采用的是独特的无序消费存储模型, 同时有序模型和二者是相同的

在这里插入图片描述

  • Message Log 存储所有Topic的消息,消息顺序写入此文件中, 避免发生类似Kafka多partition文件造成文件随机写性能下降的问题
  • Consumer Log 是以Topic为维度组织的Message Log的索引文件。索引记录固定长度,记录这个Topic的第X条消息在Message中的物理偏移量和消息大小 【感觉类似OS中的存储】

QMQ的无序存储模型中 不存在Q与单一Consumer的绑定关系,而是一个消费者组(consumer group)中的消费者合力消费一个Q,所以消费者组是支持动态扩容的

当没有了单一的consumer和Q的绑定关系:
每一个消费者的ACK和pull都是离散的,所以不能通过Q的ACK和pull(offset)来管理消费者的消费进度
QMQ 抽象一层Pull Log: 记录Consumer在Consumer Log中的offset, 当Consumer重启后,读取pull Log即可定位进行消费

当消费者拉取积压过久的消息,没有命中Page Cache时(👆提到),就会产生读磁盘操作,对于文件系统负担过重。 QMQ采用的时类似RocketMQ所有消息顺序写入Message Log,索引文件对应的物理偏移基本是块离散的,【一个物理块可能是多个消息Topic】 QMQ就给Message Log进行排序,排序后的Message Log再增加索引文件 ----- 相同主题Topic的消息是块连续,可以充分利用OS的预读特性,提升效率

后面Cfeng会结合QMQ的源码进行详细的分析,这里只是见到那提及QMQ整体上的架构,和RabbitMQ相比,可能更好的适配java生态🎄

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/190980.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

带你用uniapp从零开发一个仿小米商场_9. 轮播图组件封装及使用

导航栏有了,接下来就是轮播图了,轮播图如下, 因为uniapp 官方自己有轮播图,所以这里就不自己写了,直接使用uniapp的轮播图二次开发就好 uniapp的轮播图组件叫swiper ,感兴趣的朋友可以点击链接,直接去看官方文档,也可以看我这里实操 用hbuilderX编译uniapp的代码有一个好处…

FO-like Transformation

参考文献&#xff1a; [RS91] Rackoff C, Simon D R. Non-interactive zero-knowledge proof of knowledge and chosen ciphertext attack[C]//Annual international cryptology conference. Berlin, Heidelberg: Springer Berlin Heidelberg, 1991: 433-444.[BR93] Bellare M…

枚举的第一行

2023年11月26日 问题: 好奇enum的所声明的枚举类的第一行是什么 从java技术卷1中第五章5.6中,了解是枚举类的实例 验证 错误信息: 解释: 此时只有有参构造 在这个枚举类里不能使用空,大概意思是说不能使用空参创建实例 校验 在原有的基础上创建一个无参构造 结果:不再报错,第…

常见树种(贵州省):019滇白珠、杜茎山、苍山越桔、黄背越桔、贵州毛柃、半齿柃、钝叶柃、细枝柃、细齿叶柃木、土蜜树、山矾、胡颓子、檵木

摘要&#xff1a;本专栏树种介绍图片来源于PPBC中国植物图像库&#xff08;下附网址&#xff09;&#xff0c;本文整理仅做交流学习使用&#xff0c;同时便于查找&#xff0c;如有侵权请联系删除。 图片网址&#xff1a;PPBC中国植物图像库——最大的植物分类图片库 一、滇白珠…

电路 buck-boost相关知识

BUCK-BOOST 文章目录 BUCK-BOOST前言一、DC-DC工作模式电容电感特性伏秒积平衡原理 二、BUCK电路三、BOOST电路四、BUCK-BOOST电路总结 前言 最近需要用到buck-boost相关的电路知识&#xff0c;于是便写下这篇文章复习一下。 一、DC-DC 在学习buck-boost电路之前我们先来看一…

steam/csgo搬砖项目真能月入过万吗?到底真的假的

steam/csgo搬砖第三课之如何出售 steam搬砖核心原理是什么&#xff1f;为什么会有差价产生&#xff1f;buff不是更低价吗&#xff1f;很多小白会有这些疑问&#xff01; steam搬砖指的是通过买卖csgo游戏装备赚钱的。 玩过游戏的应该就很清楚&#xff0c;像绝地求生&#xff…

新的centos7.9安装jenkins(二)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 接上一节文章。 这个版本默认git也安装好了&#xff0c;所以全局配置这个不需要了。 maven安装3.9.3版本…

第一百八十一回 如何绘制阴影效果

文章目录 1. 概念介绍2. 使用方法2.1 SegmentedButton2.2 ButtonSegment 3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 1. 概念介绍 我们在本章回中介绍的SegmentedButton组件是一种分段式按钮&#xff0c;它把多个按钮连接成一组显示&#xff0c;组内再对不同的按钮进…

231126 刷题日报

1. 高楼扔鸡蛋 O(N*logN) 2. 698. 划分为k个相等的子集 没做出来&#xff0c;和划分两个子集不同 3. 300. 最长递增子序列 LIS petencie sorting 没看懂&#xff0c;明天看吧 4. 518. 零钱兑换 II 完全背包问题&#xff1a;每个物品数量是无限的 注意&#xff1a;dp的定义…

STM32F103C8T6_PWM引脚

可以看到&#xff1a;一共可以产生4 x 416路PWM信号&#xff1a;每个TIMER4路PWM&#xff0c; PA0,PA1,PA2,PA3,PA8,PA10,PA11; PA共7个 PB0,PB1,PB6,PB7,PB8,PB9,PB14; PB共7个

PTA NeuDS-数据库题目集

一.判断题 1.在数据库中产生数据不一致的根本原因是冗余。T 解析&#xff1a;数据冗余是数据库中产生数据不一致的根本原因&#xff0c;因为当同一数据存储在多个位置时&#xff0c;如果其中一个位置的数据被修改&#xff0c;其他位置的数据就不一致了。因此&#xff0c;在数据…

Jmeter接口测试快速入门 以飞致云平台为例

接口测试快速入门 以飞致云平台为例-CSDN博客 飞致云电商平台可以做接口测试练习。快速了解如何测试接口&#xff0c;如何做关联 系统基地址&#xff1a;https://gz.fit2cloud.com/ 接口测试快速入门 以飞致云平台为例-CSDN博客 博文中介绍了如何在swagger页面上进行接口测试。…

文本转语音:微软语音合成标记语言 (SSML) 文本结构和事件

​ SSML 的语音服务实现基于万维网联合会的语音合成标记语言版本 1.0。 ​ 语音服务支持的元素可能与 W3C 标准不同。 每个 SSML 文档是使用 SSML 元素&#xff08;或标记&#xff09;创建的。 这些元素用于调整语音、风格、音节、韵律、音量等。 下面是 SSML 文档的基本结构…

基本数据结构二叉树(1)

目录 1.树概念及结构 1.1树的概念 1.2 树的相关概念 1.3 树的表示 1.4 树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09; 2.二叉树概念及结构 2.1概念 2.2现实中的二叉树&#xff1a; 2.3 特殊的二叉树&#xff1a; 2.5 二叉树的存储结构 2. 链式存…

事件委派+自定义属性+编程式导航实现路由跳转及传参

当我们页面中有许多a标签需要实现点击跳转到同一个页面并携带不同的参数时&#xff0c;我们就可以使用事件委派自定义属性编程式导航 的方式&#xff0c;用最小的内存实现路由跳转的最大效率。 为什么我们不用router-link 进行跳转&#xff1f; 要知道&#xff0c;我们页面中…

Django之ORM

ORM全称对象关系映射 作用&#xff1a;通过python面向对象的代码简单快捷的操作数据库&#xff0c;但是封装程度太高&#xff0c;有时候sql语句的效率偏低&#xff0c;需要自己写sql语句 类----->表 对象--->记录 对象属性--->记录某个字段对应的值 写在models.p…

4.前端--HTML标签-表格列表表单【2023.11.25】

1.表格 1.1表格的作用 表格的作用&#xff1a;表格主要用于显示、展示数据 1.2表格的基本格式 <table><tr><td>单元格内的文字</td><td>单元格内的文字</td>...</tr>... </table><table> </table> 是用于定义表…

WebSocket协议在java中的应用

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

关于 raw 图像的理解

1、问题背景 在图像调试过程&#xff0c;当发现一个问题时&#xff0c;很多时候都要通过 dump raw图像来分析&#xff0c;如果raw图像上有&#xff0c;那就排除了是 ISP的处理导致。 下一步就是排查 sensor 或者镜头&#xff0c;这样可以有效的帮我们定位问题所在。 但遇到过…

ChatGPT化身“AI间谍”:你在网上说的每句话都将被监控

大多数人使用 ChatGPT 就是用来聊天或者辅助学习、办公。 然而现在一些“间谍软件”公司正在探索如何使用ChatGPT和其他新兴的AI来监视社交媒体上的用户。 其中一家由俄罗斯企业家创立的Social Links的公司正使用 ChatGPT 作为助手&#xff0c;监控着用户在Facebook、Instagr…