消息中间件常见知识点

029443e864c547c598d343976f7df9ab.gif一:消息队列的主要作用是什么?

 

1.消息队列的特性:

 

业务无关,一个具有普适性质的消息队列组件不需要考虑上层的业务模型,只做好消息的分发就可以了,上层业务的不同模块反而需要依赖消息队列所定义的规范进行通信。FIFO,先投递先到达的保证是一个消息队列和一个buffer的本质区别。容灾,对于普适的消息队列组件来说,节点的动态增删和消息的持久化,都是支持其容灾能力的重要基本特性。性能,这个不必多说了,消息队列的吞吐量上去了,整个系统的内部通信效率也会有提高。

 

2.为什么需要消息队列:

 

当系统中出现“生产“和“消费“的速度或稳定性等因素不一致的时候,就需要消息队列,作为抽象层,弥合双方的差异。“ 消息 ”是在两台计算机间传送的数据单位。消息可以非常简单,例如只包含文本字符串;也可以更复杂,可能包含嵌入对象。消息被发送到队列中,“ 消息队列 ”是在消息的传输过程中保存消息的容器 。

 

使用场景:

 

业务系统触发短信发送申请,但短信发送模块速度跟不上,需要将来不及处理的消息暂存一下,缓冲压力。就可以把短信发送申请丢到消息队列,直接返回用户成功,短信发送模块再可以慢慢去消息队列中取消息进行处理。

调远程系统下订单成本较高,且因为网络等因素,不稳定,攒一批一起发送。

任务处理类的系统,先把用户发起的任务请求接收过来存到消息队列中,然后后端开启多个应用程序从队列中取任务进行处理。

3.使用消息队列有什么好处(消息队列作用):

 

异步:假设你有一个系统调用链路,是系统A调用系统B,一般耗时20ms;系统B调用系统C,一般耗时200ms;系统C调用系统D,一般耗时2s。用户一个请求过来巨慢无比,因为走完一个链路,需要耗费:2220ms,如果业务流程支持异步化的话,是不是就可以考虑把系统C对系统D的调用抽离出去做成异步化的,不要放在链路中同步依次调用。这样,实现思路就是系统A -> 系统B -> 系统C,直接就耗费220ms后直接成功了。然后系统C就是发送个消息到MQ中间件里,由系统D消费到消息之后慢慢的异步来执行这个耗时2s的业务处理。通过这种方式直接将核心链路的执行性能提升了10倍。

解耦:假设你有个系统A,这个系统A会产出一个核心数据,现在下游有系统B和系统C需要这个数据。那简单,系统A就是直接调用系统B和系统C的接口发送数据给他们就好了。但是现在要是来了系统D、系统E、系统F、系统G,等等,十来个其他系统慢慢的都需要这份核心数据呢?那么负责系统A的就要被烦死了,然后如果要是某个下游系统突然宕机了呢?系统A的调用代码里是不是会抛异常?那系统A的同学会收到报警说异常了,结果他还要去care是下游哪个系统宕机了。所以在实际的系统架构设计中,如果全部采取这种系统耦合的方式,在某些场景下绝对是不合适的,系统耦合度太严重。并且互相耦合起来并不是核心链路的调用,而是一些非核心的场景(比如上述的数据消费)导致了系统耦合,这样会严重的影响上下游系统的开发和维护效率。因此在上述系统架构中,就可以采用MQ中间件来实现系统解耦,系统A就把自己的一份核心数据发到MQ里,下游哪个系统感兴趣自己去消费即可,不需要了就取消数据的消费。

消峰:假设有一个系统,平时正常的时候每秒可能就几百个请求,正常处理都是OK的,在高峰期一下子来了每秒钟几千请求,弹指一挥间出现了流量高峰,此时我们就可以用MQ中间件来进行流量削峰。所有机器前面部署一层MQ,平时每秒几百请求大家都可以轻松接收消息。一旦到了瞬时高峰期,一下涌入每秒几千的请求,就可以积压在MQ里面,然后那一台机器慢慢的处理和消费。等高峰期过了,再消费一段时间,MQ里积压的数据就消费完毕了。这个就是很典型的一个MQ的用法,用有限的机器资源承载高并发请求,如果业务场景允许异步削峰,高峰期积压一些请求在MQ里,然后高峰期过了,后台系统在一定时间内消费完毕不再积压的话,那就很适合用这种技术方案。

4.消息队缺点:

 

系统可用性降低:系统引入的外部依赖越多,越容易挂掉,本来就是A系统调用BCD三个系统的接口就好了,人ABCD四个系统好好的,偏加个MQ进来,万一MQ挂了,整套系统崩溃了。

系统复杂性提高:硬生生加个MQ进来,怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序性?

一致性问题:A系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是BCD三个系统那里,BD两个系统写库成功了,结果C系统写库失败了,这数据就不一致了。

 

二:如何保证消息队列的高可用?

1.RabbitMQ高可用

 

单机模式:Demo级别的,生产环境不会使用

 

普通集群模式:

 

 

 

 

 

 

 

同时部署多台RabbitMQ服务器,当生产者将消息发送到RabbitMQ的集群中时 ,消息会存在元数据(类似于消息的描述信息)+消息数据,收到消息的MQ会将消息的元数据信息同步到其他的节点上,当消费者从任意一台服务器上获取消息时,如果当前服务器存在该消息的数据信息就获取成功,否则就会根据元数据信息从其他节点上获取消息数据,这样做并没有保证MQ的高可用,因为存在消息数据的服务器挂掉,消息一样不存在,这样做只能保证MQ的吞吐量比较大。

 

采用镜像集群模式:

 

 

 

 

 

 

 

你创建的queue,无论元数据还是queue里的消息都会存在于多个实例上,然后每次你写消息到queue的时候,都会自动把消息到多个实例的queue里进行消息同步。 这样的话,好处在于,你任何一个机器宕机了,别的机器都可以用。坏处在于

 

性能开销大,消息同步所有机器,导致网络带宽压力和消耗很重!

没有扩展性,如果某个queue负载很重,你加机器,新增的机器也包含了这个queue的所有数据,并没有办法线性扩展你的queue  

开启镜像集群模式:rabbitmq有很好的管理控制台,在后台新增一个策略,这个策略是镜像集群模式的策略,指定的时候可以要求数据同步到所有节点的,也可以要求就同步到指定数量的节点,然后你再次创建queue的时候,应用这个策略,就会自动将数据同步到其他的节点上去了。

 

2.kafka的高可用

 

 

 

 

 

 

 

kafka一个最基本的架构认识:多个broker组成,每个broker是一个节点;你创建一个topic,这个topic可以划分为多个partition,每个partition可以存在于不同的broker上,每个partition就放一部分数据。

 

这就是天然的分布式消息队列,就是说一个topic的数据,是分散放在多个机器上的,每个机器就放一部分数据。kafka 0.8以前,是没有HA机制的,就是任何一个broker宕机了,那个broker上的partition就废了,没法写也没法读,没有什么高可用性可言。kafka 0.8以后,提供了HA机制,就是replica副本机制。每个partition的数据都会同步到其他机器上,形成自己的多个replica副本。然后所有replica会选举一个leader出来,那么生产和消费都跟这个leader打交道,然后其他replica就是follower。写的时候,leader会负责把数据同步到所有follower上去,读的时候就直接读leader上数据即可。只能读写leader?很简单,要是你可以随意读写每个follower,那么就要care数据一致性的问题,系统复杂度太高,很容易出问题。kafka会均匀的将一个partition的所有replica分布在不同的机器上,这样才可以提高容错性。

 

写数据的时候,生产者就写leader,然后leader将数据落地写本地磁盘,接着其他follower自己主动从leader来pull数据。一旦所有follower同步好数据了,就会发送ack给leader,leader收到所有follower的ack之后,就会返回写成功的消息给生产者。(当然,这只是其中一种模式,还可以适当调整这个行为)

 

消费的时候,只会从leader去读,但是只有一个消息已经被所有follower都同步成功返回ack的时候,这个消息才会被消费者读到。

 

三:高并发情况下消息队列满了如何防止消息丢失?

其实这个防止消息丢失,每种MQ都要从三个角度来分析:生产者弄丢数据、消息队列弄丢数据、消费者弄丢数据,以RabbitMQ为例:

 

1.生产者丢数据:

 

从生产者弄丢数据这个角度来看,RabbitMQ提供transaction和confirm模式来确保生产者不丢消息。transaction机制就是说,发送消息前,开启事务(channel.txSelect()),然后发送消息,如果发送过程中出现什么异常,事物就会回滚(channel.txRollback()),如果发送成功则提交事物(channel.txCommit())。然而缺点就是吞吐量下降了。因此,生产上用confirm模式的居多。一旦channel进入confirm模式,所有在该信道上面发布的消息都将会被指派一个唯一的ID(从1开始),一旦消息被投递到所有匹配的队列之后,rabbitMQ就会发送一个Ack给生产者(包含消息的唯一ID),这就使得生产者知道消息已经正确到达目的队列了.如果rabiitMQ没能处理该消息,则会发送一个Nack消息给你,你可以进行重试操作。

 

2.消息队列丢数据

 

处理消息队列丢数据的情况,一般是开启持久化磁盘的配置。这个持久化配置可以和confirm机制配合使用,你可以在消息持久化磁盘后,再给生产者发送一个Ack信号。这样,如果消息持久化磁盘之前,rabbitMQ阵亡了,那么生产者收不到Ack信号,生产者会自动重发。那么如何持久化呢,这里顺便说一下吧,其实也很容易,就下面两步:

 

将queue的持久化标识durable设置为true,则代表是一个持久的队列

发送消息的时候将deliveryMode=2

这样设置以后,rabbitMQ就算挂了,重启后也能恢复数据

 

3.消费者丢数据

 

消费者丢数据一般是因为采用了自动确认消息模式。这种模式下,消费者会自动确认收到信息。这时rahbitMQ会立即将消息删除,这种情况下如果消费者出现异常而没能处理该消息,就会丢失该消息。至于解决方案,采用手动确认消息即可。

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何在2024年编写Android应用程序

如何在2024年编写Android应用程序 本文将介绍以下内容: 针对性能进行优化的单活动多屏幕应用程序 🤫(没有片段)。应用程序架构和模块化 → 每个层面。Jetpack Compose 导航。Firestore。应用程序架构(模块化特征驱动…

【C++】STL 容器 - map 关联容器 ③ ( map 容器常用 api 操作 | map 容器迭代器遍历 | map#insert 函数返回值处理 )

文章目录 一、map 容器迭代器遍历1、map 容器迭代器2、代码示例 二、map 容器插入结果处理1、map#insert 函数返回值处理2、代码示例 一、map 容器迭代器遍历 1、map 容器迭代器 C 语言中 标准模板库 ( STL ) 的 std::map 容器 提供了 begin() 成员函数 和 end() 成员函数 , 这…

Seata服务搭建与模式实现

日升时奋斗,日落时自省 目录 1、简述 2、Seata优越性 3、Seata组成 4、Seata模式 4.1、XA 模式 4.2、AT 模式(默认模式) 4.3、TCC 模式 4.4、SAGA 模式 4.5、XA协议 5、Seata服务部署 5.1、文件数据源部署 5.1.1、下载并安装Seata 5.1.2、启动Seata服…

Ts自封装WebSocket心跳重连

WebSocket是一种在单个TCP连接上进行全双工通信的协议,允许客户端和服务器之间进行双向实时通信。 所谓心跳机制,就是在长时间不使用WebSocket连接的情况下,通过服务器与客户端之间按照一定时间间隔进行少量数据的通信来达到确认连接稳定的手…

HarmonyOS4.0系统性深入开发11通过message事件刷新卡片内容

通过message事件刷新卡片内容 在卡片页面中可以通过postCardAction接口触发message事件拉起FormExtensionAbility,然后由FormExtensionAbility刷新卡片内容,下面是这种刷新方式的简单示例。 在卡片页面通过注册Button的onClick点击事件回调,…

数据库中的时间和前台展示的时间不一样,如何保存日期格式的数据到数据库? 如何展示数据库的日期数据到前台

我 | 在这里 🕵️ 读书 | 长沙 ⭐软件工程 ⭐ 本科 🏠 工作 | 广州 ⭐ Java 全栈开发(软件工程师) ✈️公众号 | 热爱技术的小郑 文章底部有个人公众号二维码。回复 Java全套视频教程 或 前端全套视频教程 即可获取 300G 教程资料…

【深入浅出RocketMQ原理及实战】「云原生升级系列」打造新一代云原生“消息、事件、流“统一消息引擎的融合处理平台

打造新一代云原生"消息、事件、流"统一消息引擎的融合处理平台 云原生架构RocketMQ的云原生架构实现RocketMQ的云原生发展历程互联网时期的诞生无法支持云原生的能力 云原生阶段的升级云原生升级方向促进了Mesh以及多语言化发展可分合化的存算分离架构存储分离架构的…

听GPT 讲Rust源代码--library/portable-simd

File: rust/library/portable-simd/crates/core_simd/examples/spectral_norm.rs spectral_norm.rs是一个示例程序,它展示了如何使用Portable SIMD库中的SIMD(Single Instruction Multiple Data)功能来实现频谱规范化算法。该示例程序是Rust源…

跟着cherno手搓游戏引擎【2】:日志系统spdlog和premake的使用

配置: 日志库文件github: GitHub - gabime/spdlog: Fast C logging library. 新建vendor文件夹 将下载好的spdlog放入 配置YOTOEngine的附加包含目录: 配置Sandbox的附加包含目录: 包装spdlog: 在YOTO文件夹下创建…

在Django中配置PostgreSQL

下载并安装PostgreSQL PostgreSQL: Downloads 安装依赖psycopg2 python -m pip install psycopg2 修改Django配置文件settings.py 📌编辑 mysite/settings.py 文件前,先设置 TIME_ZONE 为你自己时区。 LANGUAGE_CODE zh-Hans TIME_ZONE Asia/Shang…

【Elasticsearch源码】 分片恢复分析

带着疑问学源码,第七篇:Elasticsearch 分片恢复分析 代码分析基于:https://github.com/jiankunking/elasticsearch Elasticsearch 8.0.0-SNAPSHOT 目的 在看源码之前先梳理一下,自己对于分片恢复的疑问点: 网上对于E…

【基础】【Python网络爬虫】【12.App抓包】reqable 安装与配置(附大量案例代码)(建议收藏)

Python网络爬虫基础 App抓包1. App爬虫原理2. reqable 的安装与配置reqable 安装教程reqable 的配置 3. 模拟器的安装与配置夜神模拟器的安装夜神模拟器的配置配置代理配置证书 4. 内联调试及注意事项软件启动顺开启抓包功reqable面板功列表部件功能列表数据快捷操作栏 夜神模拟…

WPF+Halcon 培训项目实战 完结(13):HS 鼠标绘制图形

文章目录 前言相关链接项目专栏运行环境匹配图片矩形鼠标绘制Halcon添加右键事件Task封装运行结果个人引用问题原因推测 圆形鼠标绘制代码运行结果 课程完结: 前言 为了更好地去学习WPFHalcon,我决定去报个班学一下。原因无非是想换个工作。相关的教学视…

【java爬虫】股票数据获取工具前后端代码

前面我们有好多文章都是在介绍股票数据获取工具,这是一个前后端分离项目 后端技术栈:springboot,sqlite,jdbcTemplate,okhttp 前端技术栈:vue,element-plus,echarts,ax…

K8s实战入门

1.NameSpace Namespace是kubernetes系统中的一种非常重要资源,它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离。 默认情况下,kubernetes集群中的所有的Pod都是可以相互访问的。但是在实际中,可能不想让两个Pod之间进行互相…

在线智能防雷监控检测系统应用方案

在线智能防雷监控检测系统是一种利用现代信息技术,对防雷设施的运行状态进行实时监测、管理和控制的系统,它可以有效提高防雷保护的安全性、可靠性和智能化程度,降低运维成本和风险,为用户提供全方位的防雷解决方案。 地凯科技在…

排序算法之计数排序

计数排序是一种非基于比较的排序算法,它通过统计数组中每个元素出现的次数,将其按次数从小到大排序。 以下是计数排序的基本步骤: 统计:统计数组中每个元素出现的次数。计数:将每个元素的出现次数存储在另一个数组中…

redisson作为分布式锁的底层实现

1. redisson如何实现尝试获取锁的逻辑 如何实现在一段的时间内不断的尝试获取锁 其实就是搞了个while循环,不断的去尝试获取锁资源。但是因为latch的存在会在给定的时间内处于休眠状态。这个事件,监听的是解锁动作,如果解锁动作发生。会调用…

Android textview展示富文本内容

今天实现的内容,就是上图的效果,通过Span方式展示图片,需要支持文字颜色改变、加粗。支持style\"color:green; font-weight:bold;\"展示。尤其style标签中的font-size、font-weight是在原生中不被支持的。 所以我们今天需要使用自…

病情聊天机器人,利用Neo4j图数据库和Elasticsearch全文搜索引擎相结合

项目设计目的: 本项目旨在开发一个病情聊天机器人,利用Neo4j图数据库和Elasticsearch全文搜索引擎相结合,实现对病情相关数据的存储、查询和自动回答。通过与用户的交互,机器人可以根据用户提供的症状描述,给出初步的可…