首页 > 其他分享 >通过消息队列MQ实现组件解耦

通过消息队列MQ实现组件解耦

时间:2022-10-13 13:31:26浏览次数:48  
标签:消费者 队列 处理 MQ 消息 组件 生产者

当业务系统的规模扩大时,也会增加系统架构的复杂度,在架构设计时对系统进行分层与解耦能够避免多个组件之间的性能不足、负载高、任务处理堆栈长及组件故障等风险。

        系统进行纵向分层可以实现前后端的分离,如前端展示层、前端逻辑层、后端逻辑层、后端数据库层等,层与层之间通过API调用或函数调用的方式进行请求与响应;系统进行横向分层时按照不同业务类型等因素来划分,如新零售场景中的商品展示、订单处理、支付系统、物流系统等。

​        横向为技术方案、纵向为业务场景,如下图所示。


通过消息队列MQ实现组件解耦_消息队列


图  纵向业务场景与横向技术方案分离


@ 架构坏味道

系统组件紧耦合导致扩展难度大、组件可用性低,以及生产者和消费者互相等待会导致效率低等问题。


@ 最佳实践

将系统组件按照功能拆分,通过消息队列进行解耦,实现异步处理。




生产-消费原理

        系统中的组件互相调用要避免紧耦合,背后的原理就是生产-消费原理。生产者持续生产商品,消费者消费商品,如果是紧耦合关系,消费者每生产一个商品就要串行等待消费者来消费,两者的生产和消费效率必须保持高度一致,如果生产速度快而消费者还没消费完,会造成生产者等待;如果生产速度慢而消费者已经完成任务处理,会造成消费者等待。解耦之后,生产者无须等待消费者消费,将生产的商品放到缓冲区中,消费者按照自己的节奏来消费商品,不受生产者的效率影响,只有缓冲区没有商品时才会影响消费者,生产-消费原理如图6-5所示。


通过消息队列MQ实现组件解耦_解耦_02


图  生产-消费原理

        生产-消费原理说明的是因生产者与消费者处理任务的时长不同、处理任务的能力不同等原因导致的生产过剩或消费过剩的现象,该原理并不复杂,却能够形象地表明解耦系统组件的必要性,可通过解耦来降低生产者和消费者之间的耦合/依赖关系。

实现异步解耦

        为了避免业务逻辑链过长,避免任何一个环节出现故障、超时、错误都会影响整个业务逻辑的准确性,可把长链转换成多个功能职责单一的任务,不同任务之间相互调用并互相隔离,从而实现系统组件上的解耦。例如用户上传图片的功能,用户上传照片、对图片大小进行裁剪、对图片进行压缩、添加水印、将图片存储到对象存储中、将MetaData写入MongoDB,这些都可以封装为功能职责单一的逻辑。


        解耦使得组件之间不再互相依赖,使得任何一层方便扩展。当对图片进行裁剪、压缩、添加水印等处理操作而引发服务器负载高时可分别单独扩展,任何一步操作相互独立,无须等待。每个处理任务的功能单一化,先加载数据,再按照预定算法进行处理,然后将数据存储,即可完成单个处理任务。


        如下图所示,业务系统(生产者)的请求在消息队列中排队,并按照FIFO(First In FirstOut)的原则将消息推送给消费者,消息队列在其中起到了前后端请求解耦、缓存消息的作用。

通过消息队列MQ实现组件解耦_服务器_03


图  通过消息队列实现异步解耦

实现削峰填谷

        根据生产-消费原理,解耦后的系统组件可以实现削峰填谷的效果,如图6-7所示,负责生产的组件无须关注消费者的状态,当有任务时,生产者先处理任务,之后将任务传送到消息队列中,生产者继续生产任务。消费者按照任务优先级处理或按序处理,在消息队列中可能会有堆积的任务,消费者根据消息顺序持续处理,实现业务的削峰填谷。因为已经与生产者实现了解耦,所以不会影响生产者对前端请求的响应。


        当前端流量有高并发情况时,会给后端服务节点及系统带来瞬时的高负载,当系统没有足够的防护措施时,会导致系统崩溃或服务器宕机,此时可通过消息队列解耦实现缓存前端请求的效果,实现削峰填谷,后端服务节点与系统可以保持在稳定负载下处理任务。


通过消息队列MQ实现组件解耦_消息队列_04


图  通过消息队列实现削峰填谷

订阅型、队列型消息队列

        消息队列分为订阅型和队列型,这两种类型的消息队列分别有不同的特性和使用场景。

订阅型消息队列

一个或多个消息生产者在一个主题中发布消息,一至多个订阅者均会收到相同的订阅消息,每个订阅者互相独立。订阅型消息队列用于处理互不相关的任务,比如用户上传图片后的图片裁剪、图片MetaData信息抽取和存储,它们之间并没有依赖关系。



队列型消息队列

消息生产者将消息放置到消息通道中,并且消息之间有先后顺序,消息消费者按照先进先出(First In First Out,FIFO)原则来获取数据。消息仅用于消费一次,即消费一次后会在消息队列中移除该消息。适合串联进行的任务,比如为图片添加水印、图片压缩等,这些任务之间有先后顺序,不可并行。​


        在队列型消息队列中,消息有先后顺序,消费者按照顺序消费数据,不过存在以下几种可能,消息队列中的消息顺序和真正需要处理的顺序不一致,如消费者按照Step1、Step2、Step3的顺序来处理,但是消息队列中关于图片image0001的Step3的消息早于Step2,这就需要消费者能够按照业务顺序来选择消息,将未消费的Step3消息设置为未消费状态,并在一段时间后重试读取和处理Step3消息。如果消费者读取消息后就标记为“已读”或“删除”,则可能会在处理消息失败时丢失该消息,消费者处理完一个消息任务时应向消息队列发送“消息消费成功”的响应,这时在消息队列中将该条消息标记为“完成”,避免对该条消息进行重复处理。


        常见的开源版本的消息队列有RabbitMQ、RocketMQ、Kafka等,云服务商也提供了基于这些开源版本的消息队列进行封装的产品,云平台版本与开源版本互相兼容,支持大部分功能和命令。









标签:消费者,队列,处理,MQ,消息,组件,生产者
From: https://blog.51cto.com/u_15651456/5753287

相关文章

  • JAVA并发之阻塞队列浅析
    JAVA并发之阻塞队列浅析背景因为在工作中经常会用到阻塞队列,有的时候还要根据业务场景获取重写阻塞队列中的方法,所以学习一下阻塞队列的实现原理还是很有必要的。(PS:不深......
  • RabbitMQ基本概念
    视频参考:https://www.bilibili.com/video/BV1Et411Y7tQ?p=85&vd_source=c85b4a015a69e82ad4f202bd9b87697f博客参考:https://blog.csdn.net/xiangjunyes/article/details/1......
  • vue-8 组件
    importVuefrom'vue'//全局部引入importElementUIfrom'element-ui'////按需引入import{Row,Button}from'element-ui'import'element-ui/lib/theme-chalk/i......
  • Vue动态组件 表格
    Vue组件数据源//这里是HTML内容这里通过下面的引入框架结构把数据源传到框架中还有匹配项<Mytable:configList="configList":configData="configData"></Mytable>......
  • React Hook:无用渲染-PureComponent-shouldCompoent-函数组件
    过渡技术1.1无用的渲染组件是构成React视图的一个基本单元。有些组件会有自己本地的状态(state),当它们的值由于用户的操作而发生改变时,组件就会重新渲染。在一个React......
  • Element UI tree组件总结
    tree组件折叠//关闭弹窗时,折叠组织树(耗时操作)for(vari=0;i<this.$refs.tree.store._getAllNodes().length;i++){this.$refs.tree.store._getAllNodes()[i......
  • ajax 请求队列解决方案并结合elementUi做全局加载状态
    全本下载地址ajax文件入口可发送blob文档流,form表单与通常json解决方案结合消息队列(messagelist)与elementUi(Loading)制作请求加载方案拥有post默认请求......
  • Vue3组件间传值
    12种方式1.父组件./father.vue点击查看代码<template><h1>father:</h1><h3>子组件传过来的:{{abc}}</h3><inputtype="text"ref="inp"v-model="msg"......
  • W10 启动 RabbitMQ 教程
       启动服务   1.进入rabbitmq的安装sbin目录下cmd进入命令窗口          2.cmd输入命令rabbitmq-server.bat,如图启动成功    ......
  • RabbitMQ如何保证消息的可靠性
    如何确保RabbitMQ消息的可靠性对于生产者,开启生产者确认机制,确保生产者的消息能到达队队列对于mq,开启持久化功能,确保消息未消费前在队列中不会丢失对于消费者,开......