首页 > 其他分享 >消息队列简单了解

消息队列简单了解

时间:2023-04-18 16:34:24浏览次数:29  
标签:消费 服务 请求 队列 主题 了解 消息 简单

消息队列简单了解

这消息队列虽然用起来好像很简单,但概念乱七八糟的,还是记一下吧。

作用

消息队列( MessageQueue,下称 MQ )的三大作用:解耦、异步、削峰;

解耦

假设现在的一个应用包含多个微服务,其中的 A 服务处理完一个请求后,需要将数据发送给 B、C、D 服务,原本的做法是在代码中硬编码发送数据,这样造成了 A 与其他系统的强耦合。哪天 B 服务不需要这个数据了,除了修改 B 服务的代码,还要改 A 服务;哪天新增了一个 E 服务需要这个数据,还要在 A 服务中添加发送数据到 E 服务的代码。如果服务越来越多,或者数据越来越复杂,这样的强耦合是很难接受的。

此时就可以使用 MQ 达到解耦的目的:A 服务将数据作为消息发送给 MQ ,当某个服务需要这个数据时,直接从 MQ 中获取就可以了。通过增加 MQ 这个中间件,解除了 A 服务与其他服务直接的耦合关系。

异步

还是这个应用,假设 A 服务收到用户的请求后,需要调用 B、C、D 服务处理这个请求,都处理完才能返回,这样就导致 这个请求的处理时间 = A + B + C + D。并且 A 作为一个转发者,自身的处理时间是很短的,可能会出现 50ms + 300ms + 300ms + 400ms = 1050ms,一个请求要走1秒,作为一个 WEB 应用,这样的延迟也是挺难接受的。

此时使用 MQ ,可以实现异步处理请求,达到降低延迟的目的:A 服务接受到请求,将消息发送到 MQ ,只要发送到 MQ 成功,就可以应答这个请求成功了。而具体处理这个请求的 B、C、D 服务,则可以同时去 MQ 中取到这个消息,处理请求内容,此时它们是异步的,只需要 400ms 就可以处理完(取最大的)。而对于用户而言,这个请求好像只处理了 50ms,太快勒。

削峰

换一个应用,这个应用中的 A 服务接受用户请求,这个请求需要查询数据库,平时没什么问题。但某次搞活动,晚上八点开始抢东西,一堆用户搁那疯狂刷新,不仅人多,请求次数也多。A 服务收到请求就直接到数据库中查询,压力给到了数据库。以 MySQL 来说,每秒处理 2000 个查询已经压力很大了,再大数据库就要顶不住崩溃了,但用户的请求数量可远大于 2000 个。

此时可以使用 MQ 达到削峰的目的:用户的请求发送到 MQ 保存起来(是有顺序的,保证了用户抢东西的请求先后顺序仍一致),A 服务为了照顾数据库的并发能力,每秒只取 2000 个请求到数据库中进行查询,这样虽然消息队列会积压很多请求,但保证了数据库不会崩溃,并且后续也会把积压的请求处理完。

缺点

万物皆有其优缺点,一个应用使用了消息队列享受了它的好处,也要承受它的坏处:

  1. 消息队列降低了系统的耦合度,但也降低了系统可用性。在解耦的例子中,一旦作为中间件的消息队列出了问题,那 A 服务和其他服务直接的联系直接断掉了,系统几乎是崩溃了。
  2. 消息队列提供了系统的复杂程度。引入了消息这个概念,就要处理诸如消息重复消费、消息丢失、消息顺序等等问题。
  3. 消息队列存在一致性隐患。在异步的例子中,A 服务将消息存入队列,应答返回成功。但在 B、C、D 服务中,可能 B、C 服务执行成功,D 服务出现问题失败了,此时应该数据回滚,但又已经告知用户请求成功,这可咋整。

模型

队列模型

消息队列最初就真的只是一个队列:维护一个存放消息的先进先出(FIFO)队列,生产者生产消息,将消息入队;消费者消费消息,将消息出队。

但这种简单的实现自然是存在问题:多个生产者可以将消息存到同一消息队列中,由于先进先出策略,消费消息的顺序和消息入队的顺序一致;但如果存在多个消费者消费同一消息队列,则它们属于竞争关系,一条消息被一个消费者消费出队后,其他消费者就消费不到了。

在目前的消息队列产品中,RabbitMQ 是少数来在坚持使用队列模型的产品之一,它提供 Exchange 模块,位于生产者和消费者之间。生产者无需关注将消息发给哪个队列,而是直接将消息发给 Exchange,由 Exchange 上配置的策略再决定将消息队列发送到哪个队列中。

发布-订阅模型

发布-订阅模型的出现就是为了解决队列模型中遇到的多个消费者都消费所有信息的问题。在发布-订阅模型中,发送消息的叫做发布者,接收消息的叫做订阅者,存放消息的容器叫做主题。发布者将消息发送到主题中,订阅者需要先订阅主题才能收到消息。

对应队列模型,发布者就是生产者,订阅者就是消费者,主题就是队列,没有本质区别,最大的区别就是主题里的消息是可以被消费多次的。当发布-订阅模型中的订阅者只有一个时,它就和队列模型差不多了。因此,发布-订阅模型是兼容队列模型的。

RocketMQ 使用的消息模型就是标准的发布-订阅模型,并再次加入了队列(和队列模型的队列,都是数据结构中的队列,但作用不一样...)的概念;Kafka 采用的也是发布-订阅模型,与 RocketMQ 相比,只是队列的概念换成了分区

RocketMQ

简单记一下 RocketMQ 里的概念。

Message

Message(消息)就是要传输的信息。一条消息必须有一个主题(Topic),主题就是这个消息的分类(比如这篇东西有一个随笔分类),一般,相同业务的消息的主题就是一样的。

消息还有一个可选的标签(Tag),标签就是这个消息的记号,可以用于查找消息(比如我这篇东西也有一个标签)。一般,一个主题下的消息根据目的不同就有不同的标签,如请求消息、应答消息。

Topic

Topic(主题)可以理解为消息的分类,它是消息的第一级分类,一条消息必须有一个 Topic 。

主题与生产者和消费者的关系没有限制,对于一个主题,可能有 0-N 个生产者向其发送消息,一个生产者也可以同时向不同的主题发送消息;一个主题也可以被 0-N 个消费者订阅。

Tag

Tag (标签)如其名,就是一个标签,它是消息的第二级分类,使用户可以灵活的管理消息,一条消息可以没有标签。

使用标签,同一业务的消息都在一个主题中,但可以通过标签区分这些消息:如订单消息可以分为订单创建、订单支付等。

Group

在 RocketMQ 中,消费者组(Consumer Group)就是具体化的订阅者。每个消费者组都会消费它订阅的主题中的每条消息,即多个消费者组订阅一个主题,主题中的每条消息会被多个消费者组都消费一次。但在消费者组内部,每个消费者是竞争关系,一条消息只会被组内的一个消费者消费

Message Queue

这就是之前所说的 RoketMQ 加入的队列(Queue)概念,一个主题下,可以设置多个队列。如果订阅者要获取主题下的所有消息,就要遍历其中的所有队列。

目前看来,应该是每个队列对应了一个消费者组?

几乎所有的消息队列都使用一种“ 请求-确认 ”机制,确保消息不会在传递过程中由于网络或者服务器故障而丢失,具体做法:

  1. 在生产端,生产者先将消息发送给服务器,服务器在收到消息并将其放入到主题或者队列后,给生产者发送确认的响应。
  2. 在消费端,消费者在收到消息并完成自己的业务逻辑后,给服务端发送消息消费成功的确认。

这个机制保证了消息在传递过程中的可靠性,但是引入这个机制后,为了确保消息的有序消费,在某一条消息被成功消费之前,下一条消息是不能被消费的。即每个主题在任意时刻,至多只能有一个消费者在消费,这也就没有办法水平扩展消费者的数量来提升消费端整体性能。

为了解决这个问题,RocketMQ引入了队列的概念,在每个主题中包含多个队列,通过多个队列来实现多实例并行消费消息。RocketMQ只保证消息在队列上是有序消费的,在主题层面是无法保证的。

Offset

在主题中,一条消息可能被多个消费者组消费,因此被消费后消息不会马上删除。因此需要 RocketMQ 为每个消费者组在每个队列上维护一个消费位置(Offset),标记当前消费消息的进度。

这个标记表明之前的消息已经被消费,而之后的都没有被消费。当消费了一条新消息后,位置就会加一。Offset 就是 Queue 的下标。

标签:消费,服务,请求,队列,主题,了解,消息,简单
From: https://www.cnblogs.com/qiyuanc/p/Back8.html

相关文章

  • Python实现搭建-简单服务器教程
    Python动态服务器网页(需要使用WSGI接口),基本实现步骤如下:1.等待客户端的链接,服务器会收到一个http协议的请求数据报2.利用正则表达式对这个请求数据报进行解析(请求方式、提取出文件的环境)3.提取出文件的环境之后,利用截断取片的方法将文件名转化为模块名称4.使用m=__import__(......
  • 性能测试了解服务架构
    软件架构与部署性能测试软件服务架构一般分为,最外层lvs-nginx-tomcat-redis-mysqlmermaidgraphLRlvs-->nginx主1-->tomcat1-->redis1-->mysql1nginx主1-->tomcat2-->redis1lvs-->nginx主2-->tomcat3-->redis2-->mysql2nginx主2-->tomcat4-->redis2本文永久更新地址:......
  • 微信小程序实现简单登录界面和登录功能
    微信小程序实现简单登录界面和登录功能问题背景客户端开发和学习过程中,登录功能是一个很常见的场景。本文将介绍,微信小程序开发过程中是如何实现登录界面和登录功能的。问题分析话不多说,直接上代码。(1)index.js文件,代码如下:Page({/***页面的初始数据*/data:{......
  • 9.x - 13.0 postgresql 分区表新特性及简单用法
    一、分区表定义与意义1.分区表的定义把一个大的物理表分成若干个小物理表,并使得这些小物理表在逻辑上可以被当成一张表来使用。主表/父表/MasterTable主表是创建子表的模板,是一个正常的普通表,一般主表并不存任何数据。子表/分区表/ChlidTable/PartitionTable子表继承并属于一......
  • 体验Rabbitmq强大的【优先级队列】之轻松面对现实业务场景
         说到队列的话,大家一定不会陌生,但是扯到优先级队列的话,还是有一部分同学是不清楚的,可能是不知道怎么去实现吧,其实呢,,,这东西已经烂大街了。。。很简单,用“堆”去实现的,在我们系统中有一个订单催付的场景,我们客户的客户在tmall,taobao下的订单,t......
  • 15天玩转redis —— 第十一篇 让你彻底了解RDB存储结构
        接着上一篇说,这里我们来继续分析一下RDB文件存储结构,首先大家都知道RDB文件是在redis的“快照”的模式下才会产生,那么如果我们理解了RDB文件的结构,是不是让我们对“快照”模式能做到一个心中有数呢??? 一:RDB结构剖析首先呢,我们要对RDB文件有一个概念性的认识,......
  • 2. python 变量和简单类型
    一、注释python允许在任何地方插入空字符串与注释,但不能插入到标识符和字符串中间python注释有两种形式单行注释:以#开头的一行多行注释:被三个单引号或双引号括起来的多行#这是一行注释'''这也是一行注释用三个单引号注释可多行内容'''"""这还是一行注释用三个双引号注释......
  • 用双链表实现双端队列
    //双链表publicstaticclassNode<V>{publicVvalue;publicNode<V>last;publicNode<V>next;publicNode(Vv){value=v;last=null;next=null;}}//双端队列前后皆可进出publicstaticclassMyDequ......
  • 2.-4-17--栈与队列--插松枝
     人造松枝加工场的工人需要将各种尺寸的塑料松针插到松枝干上,做成大大小小的松枝。他们的工作流程(并不)是这样的:每人手边有一只小盒子,初始状态为空。每人面前有用不完的松枝干和一个推送器,每次推送一片随机型号的松针片。工人首先捡起一根空的松枝干,从小盒子里摸出最上面的......
  • jumpserver部署及简单功能使用
    @目录一、极速部署二、用户管理三、添加资产四、资产分配五、使用资产一、极速部署建议安装环境项目机器配置操作系统备注jumpserver4核/16G内存/200G硬盘centos/rhel7.*保证是干净的系统具体机器配置安装需求来定,如果只是部署实验下,那可适当的把机械配置往......