消息队列高手课
李玥
美团高级技术专家
52199 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 42 讲
进阶篇 (21讲)
消息队列高手课
15
15
1.0x
00:00/00:00
登录|注册

03 | 消息模型:主题和队列有什么区别?

Exchange模块
分区
消费位置
消费组
队列
消息可以被多个订阅者消费
主题
订阅者
发布者
生产者入队,消费者出队
消息严格有序
先进先出
并行消费实现
Kafka
RocketMQ
RabbitMQ
Kafka
RocketMQ
发布-订阅模型
队列模型
思考题
消息队列产品
消息模型

该思维导图由 AI 生成,仅供参考

你好,我是李玥。这节课我们来学习消息队列中像队列、主题、分区等基础概念。这些基础的概念,就像我们学习一门编程语言中的基础语法一样,你只有搞清楚它们,才能进行后续的学习。
如果你研究过超过一种消息队列产品,你可能已经发现,每种消息队列都有自己的一套消息模型,像队列(Queue)、主题(Topic)或是分区(Partition)这些名词概念,在每个消息队列模型中都会涉及一些,含义还不太一样。
为什么出现这种情况呢?因为没有标准。曾经,也是有一些国际组织尝试制定过消息相关的标准,比如早期的 JMS 和 AMQP。但让人无奈的是,标准的进化跟不上消息队列的演进速度,这些标准实际上已经被废弃了。
那么,到底什么是队列?什么是主题?主题和队列又有什么区别呢?想要彻底理解这些,我们需要从消息队列的演进说起。

主题和队列有什么区别?

在互联网的架构师圈儿中间,流传着这样一句不知道出处的名言,我非常认同和喜欢:好的架构不是设计出来的,而是演进出来的。 现代的消息队列呈现出的模式,一样是经过之前的十几年逐步演进而来的。
最初的消息队列,就是一个严格意义上的队列。在计算机领域,“队列(Queue)”是一种数据结构,有完整而严格的定义。在维基百科中,队列的定义是这样的:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

消息队列中的主题和队列有着不同的概念和功能。最初的消息模型是队列模型,遵循先进先出的原则,适合单一消费者的场景。随着需求的变化,发布-订阅模型应运而生,允许一份消息被多个订阅者接收,实现了消息的多播功能。现代的消息队列产品大多采用发布-订阅模型,但RabbitMQ依然坚持使用队列模型,并通过Exchange模块实现了多个消费者的问题。RocketMQ使用的消息模型是标准的发布-订阅模型,但也有队列的概念,通过多个队列实现多实例并行生产和消费。Kafka的消息模型和RocketMQ基本一致,使用分区来实现队列的功能。了解主题和队列的区别以及不同消息模型的特点对于选择合适的消息队列产品和设计消息系统至关重要。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《消息队列高手课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(221)

  • 最新
  • 精选
  • 发条橙子 。
    置顶
    老师, 初学者有一些疑问的地方 ,希望老师可以帮忙解答 😁 Rocket mq的模型图有些没有看懂 , 模拟下场景;比如生产者是商品中心发送商品状态的更新(主题)消息(比如下架),那商品中心有多台机器就对应多个producer 。消费者组有两个,分别是导购中心 和 活动中心。 疑问一 :图中主题的队列是有多少个消费者组就有多少个队列么,是根据我们配置的消费者组数,mq自动增加主题队列个数么 疑问二 :看到图中每个producer的消息都往所有的队列中添加一条消息,每个消费者组消费自己的队列,但没有看懂这个队列是如何支持 “当水平扩展消费者机器” 可以加快消息的处理 。 每个消费组应该都是按照队列等前一条处理完了,才能去处理下一条(ps:这样来看 ,rb mq也是这个样子,如何通过水平扩展机器来加快消息的处理) 疑问三 : 图中队列的消费位置有点没看懂,我看是全剧唯一的,这是为什么,每个队列不能都是从0到1么

    作者回复: A1: 不是,消费者组和队列数没有关系,你这个例子中消费者组的数量是2个。队列数量可以根据数据量和消费速度来合理配置。RocketMQ和Kafka都可以支持水平扩容队列数量,但是都需要手动操作。 A2:producer会往所有队列发消息,但不是“同一条消息每个队列都发一次”,每条消息只会往某个队列里面发送一次。 对于一个消费组,每个队列上只能串行消费,多个队列加一起就是并行消费了,并行度就是队列数量,队列数量越多并行度越大,所以水平扩展可以提升消费性能。 A3:每队列每消费组维护一个消费位置(offset),记录这个消费组在这个队列上消费到哪儿了。

    2019-07-27
    30
    132
  • linqw
    RocketMQ业务模型的理解,老师有空帮忙看下哦 1、主题(topic)中有多个队列(队列数量可以水平进行扩容),生产者将其消息发送给主题中的某个队列(根据一定的路由规则,比如取模之类的),主题不保证消息的有序,只有队列中的消息才是有序的。 2、从主题中的所有队列中取出消息给所有消费组进行消费,消息只能被消费组中的一个线程进行消费,有点类似线程池的形式,工作线程消费来自不同队列的消息,感觉这也是RocketMq,低时延的原因,不同队列中的消息可以同时被消费,并且消费组的线程也可以并发的消费不同的消息。 3、由于主题中的一个队列都会被多个消费组进行消费,为此需要为每个消费组的消费的不同队列为此一个下标(每个消费组可以一直消费队列中的消息,无需等待其他消费组的确认),主题中的队列消息是有序的,为此需要等到所有消费组对此条消息进行确认,才能从队列中移除,感觉每个消费组的队列下标,可以一个队列维护一个CurrentHashMap来为此每个消费组的下标,这样的话可以防止锁的竞争。 课后习题:尝试回答下课后习题,感觉队列可以维护一个全局的下标,消费队列时,使用CAS进行下标的获取,由于不保证消息消费的有序,这样的话可以并发的消费消息,由于有全局下标,不会出现获取队列的空洞消息。

    作者回复: 总结的非常到位! 课后作业也完成的非常好! 小红花走起!

    2019-07-30
    11
    133
  • Geek_de6f9a
    老师你好,想请问一下消费的顺序问题。 对于有的消息,需要保证顺序性,比如交易状态和im消息。像im消息还要保证唯一性。 Q1: rocketmq,一个消费组在一个主题下的多个队列并发消费就无法保证消息的顺序性。这种该如何处理? Q2: 客户端和mq要保持一种重试的机制,如果在网络延迟出现问题的时候,前面的消息一直未收到ack响应,若不做任何处理,后面的就会阻塞,还是重试之后放弃,若是不能发生丢失的信息该如何处理。 Q3: 如何保证消息的唯一性,在重试的过程中,第一条消息已经发送,未收到ack,则进行第二次重试。此时网络故障恢复,则客户端会收到两条消息,客户端如何保证消息的唯一性。

    作者回复: A1:按照订单ID或者用户ID,用一致性哈希算法,计算出队列ID,指定队列ID发送,这样可以保证相同的订单/用户的消息总被发送到同一个队列上,就可以确保严格顺序了。 A2:会有一个超时,超时之前会阻塞,超时之后就解除锁定,允许其他消费者来拉消息,由于消费位置没变,下次再有消费者来这个队列拉消息,返回的还是上一条消息。 A3:这个问题我在后面的课中会专门来讲。

    2019-07-28
    15
    78
  • a、
    今天的思考题,我觉得应该是,把消息队列的先进先出,改成数组的随机访问,用offset来控制消息组具体要消费哪条消息,mq不主动删除消息,消息有过期时间,如果到了过期时间,只能确认不能重新该消费,只保留最大可设置天数的消息。超过该天数则删除,还要维护客户端确认信息,如果有客户端没确认,需要有重发机制。不知道这个想法对不对?

    作者回复: 现代的消息队列大多就是这么实现的。

    2019-07-27
    4
    61
  • 陈泽坛
    可以这样理解吗?请老师解答: 主要是rocketmq的部分。 生产者允许多生产者同时生产消息,每条消息只会被主题中的某条队列接收,消费组内的消费者竞相消费所有队列,消费者会根据消费组在队列上的数来记录已消费位置,做到的就是队列上的有序,但是有可能整个topic下,是无序的。有可能图中的4要先被消费,但是另一队列中的3还没被消费。 所以如果需要有序,就需要发送到同一条队列中去了。

    作者回复: 非常正确!

    2019-07-30
    3
    48
  • flyamonkey
    不要求严格顺序的话,应该是可以做到单个队列并行的,但这种情况下消息的消费可能就是个出队操作,而非等待消费端的ack后再出队了,这样势必会造成消息的丢失,所以需要有一定的补偿机制,如消息的重传和持久化等。个人见解,不知道是不是准确,还请老师指点~

    作者回复: 没错!具体可以看一下RocketMQ的并行消费的实现。

    2019-07-27
    4
    35
  • 君莫笑
    老师,我有几个问题,就是rocket MQ模型图上,1、某一个消费组中的各个消费者可以消费某一个主题中的多个队列吗;2、如果可以,消费者拉取消息的时候是完全随机消费某一个队列还是可以指定策略呢?3、如果可以,那是不是主题下的每个队列都要对应给每一个消费者(注意不是消费组)维护一个offset来记录当前消费者消费位置呢?(或者是每个消费者对应每个队列维护呢),求解答

    作者回复: A1:可以。 A2:有消费策略的,当然随机也是一种消费策略。 A3:不是。首先,不同的消费组,消费位置是完全独立的,互不干扰。同一个消费组内:消息队列为每个队列维护一个消费位置(而不是给消费者实例)。因为,我们关心的是整个消费组能消费到全部队列的消息就可以了,不关系组内每个消费者消费多少消息,同一条消息,给A消费消费,还是给B消费者消费,是无所谓的。

    2019-07-31
    9
    23
  • 渔夫
    老师讲得真好!我有几个问题想问下老师: 1. rocket mq 和 kafka 同样处理能力的情况下,哪个开销比较小,相差多吗? 2. 如果要保障消息有序,生产者通过负载hash固化发送到某一个队列,此时一个消费组中多个消费者就没什么意义了吧,因为只能从一个队列取数据 3. 多个消费组的消费速度不一样,队列又是所有消费组共享的,这似乎有些不妥,实践中什么比较好的解法,请老师教我

    作者回复: A1:这个我没有测试过,你可以自己测试一下。 A2:有意义,比如我们通过一个主题来传输一个多库MySQL实例的binlog,这个是必须严格有序的。但是,不用真的全局有序,只要更新同一个库的操作保证有序就行了。一条更新B库和一条更新A库的Binlog,就不需要严格有序。这样我们可以以库名为key进行hash,确保同一个库的消息都路由上同一个队列上就可以了。 3. 正常情况下,多个消费组,他们的消费速度的上限就是生产速度(你消费再快也得等着消息生产出来),下限也是生产速度(否则就会出现消息积压),所以正常情况下,所有消费组的消费速度都应该和生产速度差不多。 异常情况就是有的消费组会出现消息积压,如何解决积压的问题,我们后面会专门讲到。

    2019-07-30
    7
    17
  • 我丢了一只小凳子
    老师您好,消费空洞是指消息消费失败之后无法再次消费吗

    作者回复: 这里指的是,在一个队列(分区)中,前面的消息没消费成功,而后面的消息都消费了。

    2020-02-05
    2
    14
  • ly
    老师您好,关于rocketmq的那张图有几个疑问: consumergourp中的某个consumer是和某个具体的queue一一关联绑定的么?还是说某consumer每次都随机从某queue消费,另外如果是一一关联的话,那某个consumer挂了,那关联的那个queue的消息该由哪个consumer来接替消费呢? 另外product发给topic的消息是否是被topic随机分配到某个queue中的?还是说product必须指定发到哪个queue中?

    作者回复: 第一个问题,consumer和queue不是强关联的,但是在任何一个时刻,某个queue在同一个consumer group中最多只能有一个consumer占用。 第二个问题,producer和queue不需要关联,简单点儿说,就是发到哪个queue都可以。RocketMQ的默认策略是轮询选择每个queue。

    2019-07-27
    4
    13
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部