热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

RocketMQ在秒杀时的应用

目录一、RocketMQ是什么二、broker和nameserver2.1Broker2.2NameServer三、MQ在秒杀场景下的应用3.1利用MQ进行异步操作3.

目录

一、RocketMQ是什么

二、broker和nameserver

2.1 Broker

2.2 NameServer

三、MQ在秒杀场景下的应用

3.1 利用MQ进行异步操作

 3.2 削峰填谷

四、面试题

问1:任何一台 Broker 突然宕机了怎么办?那不就会导致 RocketMQ 里一部分的消息就没了吗?这就会导致 MQ 的不可靠和不可用,这个问题怎么解决?

问2:如果Broker宕了,NameServer是怎么感知到的?



一、RocketMQ是什么

消息中间件的发展:

第一代以ActiveMQ为代表,遵循JMS(java消息服务)规范                                                                                                 

第二代以RabbitMQ为代表是一个有Erlang语言开发的AMQP(高级消息队列协议)的开源实现                                               

第三代以kafka为代表,是一代高吞吐、高可用的消息中间件,以及RocketMQ

RocketMQ物理部署结构如下:

几个概念术语:

producer:消息生产者,生产者的作用就是将消息发送到 MQ,生产者本身既可以产生消息,如读取文本信息等。也可以对外提供接口,由外部应用来调用接口,再由生产者将收到的消息发送到 MQ

producer group: 生产者组,简单来说就是多个发送同一类消息的生产者称之为一个生产者组。

consumer : 消息消费者,简单来说,消费 MQ 上的消息的应用程序就是消费者

consumer group : 消费者组,和生产者类似,消费同一类消息的多个 consumer 实例组成一个消费者组.Consumer实例 的集合。

Topic : Topic 是一种消息的逻辑分类,比如说你有订单类的消息,也有库存类的消息,那么就需要进行分类,一个是订单 Topic 存放订单相关的消息,一个是库存 Topic 存储库存相关的消息。

Broker : Broker 是 RocketMQ 系统的主要角色,其实就是前面一直说的 MQ。Broker 接收来自生产者的消息,储存以及为消费者拉取消息的请求做好准备。

Message : Message 是消息的载体。一个 Message 必须指定 topic,相当于寄信的地址。Message 还有一个可选的 tag 设置,以便消费端可以基于 tag 进行过滤消息。

Tag : 标签可以被认为是对 Topic 进一步细化。一般在相同业务模块中通过引入标签来标记不同用途的消息。

Name Server : Name Server 为 producer 和 consumer 提供路由信息。

 

二、broker和nameserver

2.1 Broker

如下图,我们看看broker是什么,可以看到,每个broker都有一个或多个 Topic(Broker和Topic是多对多的关系),下图的MessageQueue是一个存放消息的队列,一边去存放消息,一边去消费消息。

2.2 NameServer

nameserver提供的路由功能,如下图,例如:

1.Broker 一开始是得向 NameServer注册的,注册的信息包括Broker的ip,Broker负责的消息的Topic,有多少个queue等。

2. 而Producer(生产者)则是会通过NameServer找到Broker,并向Broker中的消息队列(queue)放入消息,如果queue有多个,则会通过轮询的方式来放入消息。

3. 而Consumer(消费者)则是通过NameServer抓取信息,以Topic为单位抓取的,NameServer会返回对应Topic的Broker给Consumer,然后Consumer就可以去Broker上抓取对应的消息了。过程是,Consumer会对Broker上的两个queue分别建立长连接, 如果有消息的话,直接拉走,如果没有消息,Consumer就会长轮询等待,直到有消息放入queue。

4. 当Consumer消费完消息后,Consumer要回复一个信息给对应的queue,告诉queue该消息已经被消费,那么queue就会把该消息删除。

5. 当一个queue被多个Consumer消费的时候,就会出现同步问题,就会有一个锁竞争的问题,因此RocketMQ使用了以queue为单位,平均地分配到各个Consumer,即N个queue就对应N个Consumer,即一个queue就有一个Consumer。所以一个好的中间件,Consumer group中Consumer的数量应该近乎于跟对应的queue的数量相等。Consumer的数量若比queue的数量多,则会有Consumer消费不到消息,若比queue数量少,则会有一个Consumer消费多个消息。

 

三、MQ在秒杀场景下的应用

3.1 利用MQ进行异步操作

对于一个电商APP而言,每卖掉了一个商品,就要扣减掉商品的库存,而且一旦用户成功支付了,还需要将订单的状态更新成待发货。

在完成这些最核心的功能后,其实是有很多事情要做的,比如上图红色的部分。如果这些动作都以同步方式来完成,根据线上系统的一般统计,多个子步骤全部执行完毕,加起来大概需要1秒~2秒的时间。

有时候在高峰期并发量特别大,服务器的磁盘、IO、CPU的负载会很高,执行SQL语句的性能也会有所下降。因此有的时候甚至需要几秒钟的时间完成上述几个步骤。

那么影响是什么呢?

想象一下,如果你是一个用户,在支付完一个订单之后,界面上会有一个圈圈不停的旋转,让你等待好几秒之后才能提示支付成功。对用户来说几秒钟的时间,会让人非常不耐烦的!

所以首先针对子步骤过多、速度过慢、让用户支付之后等待时间过长的问题,就是订单系统亟需解决的问题!

而解决这个问题的一大利器就是消息中间件,英文全称“Message Queue”,简称MQ。

在引入消息中间件以后,系统A和系统B之间就由同步变为异步通信,而完成这样的一个核心概念就是“消息”

系统A发送消息给MQ后,就认为已经完成了自己的任务;然后系统B根据自己的情况,可能会在系统A投递消息到MQ之后的1秒内,也可能是1分钟之后,也可能是1小时之后,多长时间都有可能。

反正不管是多长时间后,系统B会根据自己的节奏从MQ里获取到一条属于自己的消息,再根据消息的指示完成自己的工作。 

在“异步调用”的整个过程中,系统A仅仅是发个消息到MQ,至于系统B什么时候获取消息,有没有获取消息,系统A是不管的。

举例来说:

在秒杀活动开始前,先把活动商品的库存从数据库中读到redis中,然后用户下单,是从redis中扣减库存的(而不是直接在数据库中扣减库存),然后给MQ发送一个扣减库存的消息,然后消费者在恰当的时候读取这个消息,并从数据库中进行扣减库存的操作。这时候redis的库存往往扣减得速度比数据库快一点,因为数据库是通过MQ异步去扣减的。意思就是说,数据库的库存什么时候去扣减其实是不急的,只要最后能扣减正确就行。

总结:

我们可以让订单系统仅仅完成最核心的功能,然后发送消息到MQ。比如需要进行减库存,就发送一个消息到库存消息队列中,然后库存系统从这个MQ里获取消息再进行处理就可以,把这些很耗时的步骤慢慢执行,从而也实现了系统之间的解耦

在双11大促活动的时候,同样可以让瞬间涌入的大量下单请求到MQ里去排队,然后让订单系统在后台慢慢的获取订单,以数据库可以接受的速率完成操作,避免瞬间请求量过大击垮数据库。


 3.2 削峰填谷

MQ 除了可以使用异步的方式实现系统间的解耦,更可以在双 11 这样的秒杀活动中,通过削峰填谷的方式,处理瞬时间涌入的大量请求。

什么是削峰填谷?

削峰填谷本身是电力行业的概念,电力企业通过必要的技术和管理手段,降低电网的高峰负荷,提高低谷负荷,平滑负荷曲线,提高负荷率,保证电网的稳定运行。

假设一个应用,它能够每秒处理 1000 个请求。如果在第一秒接收到 2000 个请求,而接下来的两秒都没有请求到达。

(1)在第一秒被 2000 个请求直接压垮;

(2)假设第一秒没有被压垮,它在这一秒时间内只能处理 1000 请求,第二第三秒却完全空闲,浪费了系统资源。

红色的部分是超出系统处理能力的部分,可以把红色的那部分消息平摊到后面空闲时去处理,这样既可以保证系统负载处在一个稳定的水位,又可以尽可能地处理更多消息。

针对秒杀的场景,上游发起高并发的下单操作,由于下游处理能力有限,两端速度不匹配。此时我们引入 MQ 可以对流量进行缓冲,并实现削峰填谷。

上游速度很快,每秒发起五万个请求也没关系,它只管往 MQ 中发。下游系统虽然每秒只能处理 1000 个请求,但它完全可以 follow 自己的节奏,每隔一段时间,主动拉取若干条信息,实施限流的效果,保护自身。

3.3  秒杀大闸

为了解决秒杀令牌在活动一开始无限制生成(因为主要用户不停地访问,就会不停地创建令牌),影响系统的性能,提出了秒杀大闸的解决方案;

活动开始前,把预设的令牌数量放到redis中,然后活动开始后,用户调用秒杀接口生成令牌时,生成一个令牌,把redis中的令牌数量减一,直到减为0则不再发放令牌。

主要是为了限制令牌的个数,使其不会无限被生成。


四、面试题

问1:任何一台 Broker 突然宕机了怎么办?那不就会导致 RocketMQ 里一部分的消息就没了吗?这就会导致 MQ 的不可靠和不可用,这个问题怎么解决?

答:

RocketMQ的解决思路是Broker主从架构以及多副本策略。

Master收到消息后会同步给Slave,这样一条消息就不止一份了,Master宕机了还有slave中的消息可用,保证了MQ的可靠性和高可用新。

 

问2:如果Broker宕了,NameServer是怎么感知到的?

答:

Broker会定时(30s)向NameServer发送心跳

然后 NameServer会定时(10s)运行一个任务,去检查一下各个Broker的最近一次心跳时间,如果某个Broker超过120s都没发送心跳了,那么就认为这个Broker已经挂掉了。


推荐阅读
  • 优化Flask应用的并发处理:解决Mysql连接过多问题
    本文探讨了在Flask应用中通过优化后端架构来应对高并发请求,特别是针对Mysql 'too many connections' 错误的解决方案。我们将介绍如何利用Redis缓存、Gunicorn多进程和Celery异步任务队列来提升系统的性能和稳定性。 ... [详细]
  • 微软Exchange服务器遭遇2022年版“千年虫”漏洞
    微软Exchange服务器在新年伊始遭遇了一个类似于‘千年虫’的日期处理漏洞,导致邮件传输受阻。该问题主要影响配置了FIP-FS恶意软件引擎的Exchange 2016和2019版本。 ... [详细]
  • 深入理解 SQL 视图、存储过程与事务
    本文详细介绍了SQL中的视图、存储过程和事务的概念及应用。视图为用户提供了一种灵活的数据查询方式,存储过程则封装了复杂的SQL逻辑,而事务确保了数据库操作的完整性和一致性。 ... [详细]
  • 本文详细介绍了Grand Central Dispatch (GCD) 的核心概念和使用方法,探讨了任务队列、同步与异步执行以及常见的死锁问题。通过具体示例和代码片段,帮助开发者更好地理解和应用GCD进行多线程开发。 ... [详细]
  • 并发编程 12—— 任务取消与关闭 之 shutdownNow 的局限性
    Java并发编程实践目录并发编程01——ThreadLocal并发编程02——ConcurrentHashMap并发编程03——阻塞队列和生产者-消费者模式并发编程04——闭锁Co ... [详细]
  • 在当前众多持久层框架中,MyBatis(前身为iBatis)凭借其轻量级、易用性和对SQL的直接支持,成为许多开发者的首选。本文将详细探讨MyBatis的核心概念、设计理念及其优势。 ... [详细]
  • Splay Tree 区间操作优化
    本文详细介绍了使用Splay Tree进行区间操作的实现方法,包括插入、删除、修改、翻转和求和等操作。通过这些操作,可以高效地处理动态序列问题,并且代码实现具有一定的挑战性,有助于编程能力的提升。 ... [详细]
  • 利用存储过程构建年度日历表的详细指南
    本文将介绍如何使用SQL存储过程创建一个完整的年度日历表。通过实例演示,帮助读者掌握存储过程的应用技巧,并提供详细的代码解析和执行步骤。 ... [详细]
  • 在使用SQL Server进行动态SQL查询时,如果遇到LIKE语句无法正确返回预期结果的情况,通常是因为参数传递方式不当。本文将详细探讨这一问题,并提供解决方案及相关的技术背景。 ... [详细]
  • 本文介绍如何通过创建替代插入触发器,使对视图的插入操作能够正确更新相关的基本表。涉及的表包括:飞机(Aircraft)、员工(Employee)和认证(Certification)。 ... [详细]
  • MySQL 数据库迁移指南:从本地到远程及磁盘间迁移
    本文详细介绍了如何在不同场景下进行 MySQL 数据库的迁移,包括从一个硬盘迁移到另一个硬盘、从一台计算机迁移到另一台计算机,以及解决迁移过程中可能遇到的问题。 ... [详细]
  • 尽管使用TensorFlow和PyTorch等成熟框架可以显著降低实现递归神经网络(RNN)的门槛,但对于初学者来说,理解其底层原理至关重要。本文将引导您使用NumPy从头构建一个用于自然语言处理(NLP)的RNN模型。 ... [详细]
  • 本题探讨如何通过最大流算法解决农场排水系统的设计问题。题目要求计算从水源点到汇合点的最大水流速率,使用经典的EK(Edmonds-Karp)和Dinic算法进行求解。 ... [详细]
  • 毕业设计:基于机器学习与深度学习的垃圾邮件(短信)分类算法实现
    本文详细介绍了如何使用机器学习和深度学习技术对垃圾邮件和短信进行分类。内容涵盖从数据集介绍、预处理、特征提取到模型训练与评估的完整流程,并提供了具体的代码示例和实验结果。 ... [详细]
  • LeetCode: 实现队列与栈的高级应用
    本文介绍如何使用队列和栈实现特定功能,包括动态维护队列元素并计算其平均值,以及栈操作中的优化技巧。 ... [详细]
author-avatar
Cyndi_lidi_816
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有