RocketMQ在秒杀时的应用

目录

一、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已经挂掉了。

已标记关键词 清除标记
相关推荐
秒杀”这一业务场景在如今已经不是什么新鲜名词,它本质上属于短突发性高并发访问问题,业务特点如下: 1. 定触发,流量在瞬间突增 2. 秒杀请求中常常只有部分能够成功 3. 秒杀商品数量往往有限,不能超卖,但能接受少卖 4. 不要求立即返回真实下单结果 秒杀场景下,短突发大流量的访问很容易对系统造成较大的访问压力,因此我们需要采取一定的措施对系统进行改造或者定制。 解决的思路就是“异步化”。而 RocketMQ 恰恰是实现业务异步化、削峰填谷的利器。 本篇 Chat 就是围绕高并发秒杀的实战场景,通过图解、编码、案例分析等方式对 RocketMQ 如何在实战中落地做一个较为详细的讲解。主要内容如下: 1. 了解“秒杀”业务的特点; 2. 学习“秒杀”业务的流程; 3. 分析“秒杀”业务的解决方案; 4. 使用 RocketMQ 进行“秒杀”收单; 5. 使用 RocketMQ 进行“秒杀”发单; 6. 自定义消息协议; 7. RocketMQ 集群搭建及管控台 console 的使用等。 --- 作者介绍: 李伟,Apache RocketMQ 北京社区联合发起人, RocketMQ 社区 Python 客户端负责人。对分布式系统设计和研发有丰富经验,对消息队列有深刻理解。目前在VIPKIP担任架构师,负责 VIPKID 消息平台的探索、研发和创新。 武文良,Apache RocketMQ 社区核心贡献者,高阳捷迅后端高级工程师。在电商充值、支付等核心交易链路研发经验丰富,尤其擅长商品秒杀等高并发场景系统设计与开发。 *当前内容版权归码字科技所有并授权显示,盗版必究。[阅读原文](http://gitbook.cn/gitchat/activity/5d1d6171bdaa30360df3b138)*
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页