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

08 | 答疑解惑(一) : 网关如何接收服务端的秒杀结果?

进阶篇将学习消息队列的实现技术
基础篇学习完成后,已具备使用消息队列的能力
学习消息队列的难点在宏观架构层面
实现局部严格顺序的方式
主题层面无法保证严格顺序,只有在队列上才能保证消息的严格顺序
处理消息空洞的方式
JMQ实现思路:多个消费者同时消费队列中的消息
消费位置和消费者无关
消费组、消费者和队列的对应关系
生产者对应到队列的方式灵活
主题MyTopic创建5个队列,分布到2个Broker中
网关如何接收后端服务的秒杀结果:使用RPC方式返回秒杀结果,保存结果并通知处理APP请求的线程
示例中的简单方案:使用Java语言处理APP请求,等待后端处理,查询秒杀结果并返回响应
网关接收后端服务秒杀结果的多种实现方式
实际生产环境中的秒杀系统复杂多样
写在最后
如何保证消息的严格顺序?
如何实现单个队列的并行消费?
详解RocketMQ和Kafka的消息模型
网关如何接收服务端的秒杀结果?
消息队列高手课总结

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

你好,我是李玥。
我们的“消息队列高手课”专栏自从上线到现在,同学们的学习热情和参与度都非常高。每一节课都有很多同学留言评论,这些留言里有总结知识分享收获的,有提出精彩问题的,还有给自己加油打气立 Flag 的,竟然还有说老师长得像黄渤的。我又仔细去看了一下配图,还是真挺像的。下次老师和极客时间的设计师小姐姐说一样,让她们照着吴彦祖来 P 图。
同学们每一条的留言我都认真看过,大部分留言我都给出了回复。在基础篇的最后一节课,我来统一解答一下大家都比较关注的一些问题。

1. 网关如何接收服务端的秒杀结果?

在《01 | 为什么需要消息队列?》这节课里面,我们举了一个秒杀的例子,这个例子是用来说明消息队列是如何来实现异步处理的。课后很多同学留言提问,网关在发送消息之后,是如何来接收后端服务的秒杀结果,又如何来给 APP 返回响应的呢?
在解答这个问题之前,我需要先说一下,实际生产环境中的秒杀系统,远比我们举的这个例子复杂得多,实现方案也是多种多样的,不是说一定要按照我们这个例子的方式来实现。
在这个例子中,网关接收后端服务秒杀结果,实现的方式也不只一种,这里我给大家提供一个比较简单的方案。
比如说,用 Java 语言来举例子:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入介绍了消息队列处理、并行消费等技术内容,对于想要了解消息队列处理和并行消费的读者具有一定的参考价值。作者详细解释了网关如何接收服务端的秒杀结果,并通过Java代码展示了处理方案。此外,文章还详解了RocketMQ和Kafka的消息模型,以及如何实现单个队列的并行消费。在保证消息的严格顺序方面,作者提出了一些实现方法,强调了在学习消息队列的过程中要保持一定的高度,掌握消息队列宏观层面上的实现原理和最佳实践。在“基础篇”结束后,作者表示在“进阶篇”中将把学习重点从“如何使用”转为“如何实现”,并鼓励读者坚持学习,多思考,多练习,成为真正的高手。整体而言,本文内容丰富,涵盖了消息队列处理和并行消费等技术内容,适合对消息队列技术感兴趣的读者阅读学习。

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

全部留言(97)

  • 最新
  • 精选
  • 大龄小学生
    置顶
    老师,一图胜千言,来点图吧。

    作者回复: 你要的图来了。我在文中补充了一个流程图,便于同学们理解。

    2019-08-08
    3
    42
  • linqw
    学习完网关答疑篇,写下自己的理解和疑惑,老师有空帮忙看下哦 1、秒杀的理解: APP--发送秒杀请求--》网关(也是RPC服务端,和配置中心保持长连接,比如nacos,将其路由和配置信息定时的发送给配置中心,配置中心对其进行管理,定时的清除宕机的网关路由信息,如超过一定时间没有接收到网关的心跳包)--》将其APP请求做一定的封装,增加网关id和网关实例中唯一的请求id发送给消息队列,为了保证消息不丢失,网关对其发送消息出现的异常进行处理,如超时异常,直接返回秒杀失败,网关发送消息的这个过程中可能涉及到分布式事务,使用消息队列的分布式事务进行处理,然后网关需要等待一段时间,等待秒杀服务端使用RPC调用网关实例的接收秒杀结果,为此创建一个新对象,将其请求id做为key,新对象做为value放入CurrentMap中,调用新对象的超时wait方法进行等待秒杀结果--发送封装的APP请求,包含网关id和请求id--》消息队列接收APP请求消息,为了保证消息不丢失,开启Sync_Flush参数将消息保存到磁盘,并且为了防止一台机器磁盘出问题,集群需要2台机器都有消息才确认请求--从消息队列中拉取消息--》秒杀服务端,为了低延迟执行风控、预占库存,拿到消息中网关id,从本地路由中查询网关id的实例信息,如果获取不到调用网关实例时,需先从配置中心获取到网关的路由信息,秒杀服务端也需和配置中心保持长连接,定时的从配置中心拉取网关的路由信息,保存到本地,使用RPC调用网关实例的接收秒杀结果的方法,为了保证消息不丢失,先执行消费逻辑,再响应消息队列,如果根据网关id获取不到网关实例,或者确认消息队列超时或出现异常,秒杀服务端回滚事务,此过程也涉及到分布式事务,为了防止消费重复消息,接口的幂等性,将请求id和网关id做为唯一键。也为了防止消息积压,消息队列中的主题队列和消费组中的消费者一一对应,保证消息被快速消费。 2、秒杀异步,APP发送请求给网关,网关接收请求后将请求做一定的封装(包括请求id,网关id,账户id),然后发送到消息队列中,响应APP请求,无需等待后需的流程,然后秒杀成功以否直接返回,后续流程处理完使用短信的形式告知用户是否秒杀成功,不知道这样做法是否可行。 3、最近在撸rocketmq的源码,搞了namesrv、logging、logappend模块,想成为commiter,立个flag,等后续JMQ出来,撸其源码,也想成为commiter,道阻且长,持续进化。

    作者回复: 我认真的看了同学的对于秒杀的理解,技术上都没什么问题。 从业务角度,老师有一些不同的看法。 对于秒杀这种场景,宏观上的设计应该是倾向于利用有限的资源处理短时间内海量的请求,保证服务不宕机。有少量请求处理出错(注意是后端错误,用户不可见)或消息丢失,是可以接受的。 毕竟秒杀拼的就是运气,某个用户秒杀请求在处理的时候丢失,和处理成功但没秒到,对于用户来说都是运气不好而已。 基于这样的设计理念,很多保证数据可靠性的做法都可以牺牲掉,用于换取系统更大的吞吐量比较划算。

    2019-08-08
    2
    68
  • 滴流乱转小胖儿
    mq界,吴彦祖老师你好,感谢分享

    作者回复: 谢谢你,蔡徐坤同学。

    2019-08-08
    8
    38
  • 摩云神雕
    请教下老师,topic的partition数 是根据什么确定的? 我理解partition的设置 是为了一个消费组中多个消费者并行消费的, 那么partition数根据什么设定呢? 根据消费者数 和 broker机器的性能吗 假设我现在的kafka有 3个broker节点, 创建了一个topic, partition值设为5, 然后我的一个消费组中有5个消费者, 正好一个消费者 消费一个partition, 后续, 这个消费组 我又想加2个消费者, 呢partition数 也调成7 是吧? 但是, 我这个topic 可能被好几个消费组消费的, 你消费组A扩展了消费者数, 想扩展partition数, 但是 我消费组B没这个需求啊, 怎么办? 这个topic是消费组A、B、C、D大家共同订阅的, 就因为 你A组加了几个消费者, 我就去改这个topic的partition数吗? 这里没太想通; 另外,在生产环境中 改了partition数,会造成什么影响?

    作者回复: 多个消费组的时候,确实有你说的问题,partition数量需要兼顾所有消费者。一般的做法都是照顾消费最慢的那个消费组,按照它的速度和消费者数量来确定partition数量。 大部分MQ都支持动态扩容,增加分区数量,分区数量变更后,会重新分配消费者和分区对应关系,对生产基本没什么影响。

    2019-09-20
    6
    30
  • 虢國技醬
    "同一个消费组内,每个队列只能被一个消费者实例占用" 我在想:如果队列只有两个Q1和Q2,但是G1中有三个消费者实例C1,C2和C3;那会不会有一个消费者实例一直在偷懒(没有干活的机会,😂)。 对于这种情况会报错?还是说内部会有机制队列的占用是换着分配给消费者实例的(不是某个实例一直占用)?

    作者回复: 是的,这时候就会有一个消费者没有干活的机会。 至于,如何分配队列与消费者的关系,不同的消息队列处理也不一样,有的消息队列是绑定队列与消费者,这样有一个消费者一直闲着,其它二个一直干活。 也有的消息队列是分时绑定,也就是你干一会儿,我干一会儿,但任何时刻,都会有一个消费者处于闲着的状态。

    2019-09-05
    2
    25
  • 木木木
    关于有序性还有疑惑,即使采用了一致性hash,无论扩容还是缩容队列,对分配相邻队列的用户部分还是有影响的,难道要等这些队列消费完了,阻止生产者发消息吗?感觉不具有可操作性

    作者回复: 扩容后只需要等一会儿,确保扩容之前的消息都消费完成了(不确定的话可以等久一点儿也没关系)再消费新分区的数据就可以了,生产不需要停。 因为一致性哈希可以保证单调性:如果已经有一些内容通过哈希分派到了相应的分区中,又有新的分区加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到原有的或者新的分区中去,而不会被映射到旧的分区集合中的其他分区

    2019-08-20
    20
  • 大魔王汪汪
    看了几期,感觉分布式消息队列的设计方案和分布式存储系统的设计方案很类似,如果再加上事务处理,存储细节方案应该更像了

    作者回复: 同学那不是像,消息队列就是个分布式存储系统。

    2019-08-08
    2
    13
  • Liam
    秒杀这个案例中,超时之后不需要补偿机制吗,对于下游服务来说很可能以及成功了

    作者回复: 这个案例中,你说的这种情况是有可能存在的。 是否需要补偿,也无所谓对错,总体效果是一样的。秒杀的目的就是从众多秒杀用户中公平的选择n个用户,补偿或不补偿,影响的只是这n个用户是谁的问题。 所以这是一个架构选择的问题。 我建议是不用补偿,按失败处理,锁定的库存超时未支付后会自动释放,好处是比较简单。

    2019-08-14
    2
    11
  • 大白先生
    老师,在秒杀场景中,后端服务通过调用onResult方法来放入秒杀结果,有没有可能有一种情况,就是秒杀成功了,但是获取mutex是空,这样的活,会不会前段接收了秒杀失败的提示,但是库存扣减成功了

    作者回复: 会有这种情况。但无需特殊处理。 一般秒杀成功后,还有后续的支付流程。 有些用户秒杀成功也不会支付。你说的这种情况与“秒杀成功不支付”一并处理就行了。一般都是有一个支付超时,超过这个时限还没支付,就取消这个秒杀资格,自动释放库存。

    2019-08-09
    2
    11
  • 托尼斯威特
    刚开始学习 RocketMQ. Consumer可以register的MessageListener 有两种: MessageListenerOrderly 和 MessageListenerConcurrently. 这和老师讲的, RocketMQ 每个queue只要一个单线程消费者矛盾吗?

    作者回复: 首先强调一下,并不是“每个队列只要一个单线程消费者”,而是“每个队列只能被一个消费者实例占用。” rocketMQ的MessageListenerConcurrently,和我们上面讲的内容也不矛盾,它这个并行消费是完全在客户端实现的。大致的原理就是: 1. 客户端从服务端的某个队列读取一批消息; 2. 分发给客户端的多个线程消费; 3. 都消费成功后,给服务端返回消费成功确认。

    2019-11-04
    5
    10
收起评论
显示
设置
留言
97
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部