「 高并发系统设计 」如何用好消息队列?

「 高并发系统设计 」如何用好消息队列?

参考&鸣谢

消息队列:秒杀时如何处理每秒上万次的下单请求?

关于消息队列你必须知道的知识 古明地盆


一、前言

高并发系统设计的三个核心目标:性能、可用性和可扩展性。
在性能方面,我们一直聚焦于系统的查询性能,主要原因在于我们通常遇到的场景都是读多写少的,尤其是在系统的初期。

举例来说,在社区系统初期,可能只有少量种子用户在生成内容,而大多数用户处于“围观”状态。在这个阶段,整体流量相对较小,写流量可能只占整体流量的百分之一。因此,即使整体查询每秒达到 10000 次,写请求也只有每秒 100 次,优化写请求的性能可能并不是最高效的选择。

然而,随着业务的发展,可能会遇到一些高并发写请求的场景,比如秒杀抢购活动。在这种情况下,用户会疯狂刷新APP或浏览器,导致读请求仍然非常高。那么,应该采取哪些措施呢?

考虑到用户查询的是少量的商品数据,属于查询的热点数据,可以采用缓存策略,将请求尽量挡在上层的缓存中。静态化能够实现的数据,如商城的图片和视频数据,可以静态化以命中CDN节点缓存,减少Web服务器的查询量和带宽负担。同时,Web服务器如Nginx可以直接访问分布式缓存节点,避免请求到达业务服务器(如Tomcat)。

此外,可以引入一些限流策略,比如对于短时间内来自同一用户、同一IP或同一台设备的重复请求进行丢弃处理。通过这些方式,可以将请求尽量挡在数据库之外,稍微缓解读请求的压力。

然而,在秒杀活动开始的时刻,用户会向电商系统请求生成订单、扣减库存等写操作,这些操作是直达数据库而不经过缓存的。在1秒钟内,可能会有1万个数据库连接同时达到,系统的数据库面临崩溃的风险。为了解决这个问题,引入消息队列成为一种有效的解决方案。


二、对消息队列的理解

消息队列看作暂时存储数据的一个容器,认为消息队列是一个平衡低速系统和高速系统处理任务时间差的工具。

想象一下古代的臣子们频繁去朝见皇上,陈述国家大事,等着皇上做出决策。由于大臣众多,如果他们同时去找皇上,你一言我一语,皇上肯定会应接不暇,陷入混乱。为了解决这个问题,后来演变为臣子们在午门等待,依次被召见进大殿商议国事,从而有效缓解了皇上处理事务的压力。在这个比喻中,午门就类似于消息队列,临时容纳臣子,平衡处理的压力,有序地进行任务。

实际上,我们在许多组件中都能观察到消息队列的身影:

  • 在Java线程池中,我们使用队列来暂时存储提交的任务,等待有空闲的线程处理这些任务;
  • 在操作系统中,中断的下半部分也会使用工作队列来实现延后执行;
  • 在实现一个RPC框架时,通常会将从网络上接收到的请求写入队列,然后启动若干个工作线程来处理。

综上所述,队列在系统设计中扮演着重要的角色,是一种常见的组件。


三、消息队列的应用

削去秒杀场景下的峰值写流量

刚才提到,在秒杀场景下,短时间之内数据库的写流量会很高,那么依照我们以前的思路应该对数据做分库分表。如果已经做了分库分表,那么就需要扩展更多的数据库来应对更高的写流量。但是无论是分库分表,还是扩充更多的数据库,都会比较复杂,原因是你需要将数据库中的数据做迁移,这个时间就要按天甚至按周来计算了。

而在秒杀场景下,高并发的写请求并不是持续的,也不是经常发生的,而只有在秒杀活动开始后的几秒或者十几秒时间内才会存在。为了应对这十几秒的瞬间写高峰,就要花费几天甚至几周的时间来扩容数据库,再在秒杀之后花费几天的时间来做缩容,这无疑是得不偿失的。

**所以,我们的思路是:**将秒杀请求暂存在消息队列中,然后业务服务器会响应用户“秒杀结果正在计算中”,释放了系统资源之后再处理其它用户的请求。

我们会在后台启动若干个队列处理程序,消费消息队列中的消息,再执行校验库存、下单等逻辑。因为只有有限个队列处理线程在执行,所以落入后端数据库上的并发请求是有限的。而请求是可以在消息队列中被短暂地堆积,当库存被消耗完之后,消息队列中堆积的请求就可以被丢弃了。

img

这就是消息队列在秒杀系统中最主要的作用:**削峰填谷,**也就是说它可以削平短暂的流量高峰,虽说堆积会造成请求被短暂延迟处理,但是只要我们时刻监控消息队列中的堆积长度,在堆积量超过一定量时,增加队列处理机数量,来提升消息的处理能力就好了,而且秒杀的用户对于短暂延迟知晓秒杀的结果,也是有一定容忍度的。

**这里需要注意一下,**我所说的是“短暂”延迟,如果长时间没有给用户公示秒杀结果,那么用户可能就会怀疑你的秒杀活动有猫腻了。所以,在使用消息队列应对流量峰值时,需要对队列处理的时间、前端写入流量的大小,数据库处理能力做好评估,然后根据不同的量级来决定部署多少台队列处理程序。

比如你的秒杀商品有 1000 件,处理一次购买请求的时间是 500ms,那么总共就需要 500s 的时间。这时,你部署 10 个队列处理程序,那么秒杀请求的处理时间就是 50s,也就是说用户需要等待 50s 才可以看到秒杀的结果,这是可以接受的。这时会并发 10 个请求到达数据库,并不会对数据库造成很大的压力。


通过异步处理简化秒杀请求中的业务流程

其实,在大量的写请求“攻击”你的电商系统的时候,消息队列除了发挥主要的削峰填谷的作用之外,还可以实现异步处理来简化秒杀请求中的业务流程,提升系统的性能。

你想,在刚才提到的秒杀场景下,我们在处理购买请求时,需要 500ms。这时,你分析了一下整个的购买流程,发现**这里面会有主要的业务逻辑,也会有次要的业务逻辑:**比如说,主要的流程是生成订单、扣减库存;次要的流程可能是我们在下单购买成功之后会给用户发放优惠券,会增加用户的积分。

假如发放优惠券的耗时是 50ms,增加用户积分的耗时也是 50ms,那么如果我们将发放优惠券、增加积分的操作放在另外一个队列处理机中执行,那么整个流程就缩短到了 400ms,性能提升了 20%,处理这 1000 件商品的时间就变成了 400s。如果我们还是希望能在 50s 之内看到秒杀结果的话,只需要部署 8 个队列程序就好了。

经过将一些业务流程异步处理之后,我们的秒杀系统部署结构也会有所改变:

img

解耦实现秒杀系统模块之间松耦合

除了异步处理和削峰填谷以外,消息队列在秒杀系统中起到的另一个作用是解耦合。

比如数据团队对你说,在秒杀活动之后想要统计活动的数据,借此来分析活动商品的受欢迎程度、购买者人群的特点以及用户对于秒杀互动的满意程度等等指标。而我们需要将大量的数据发送给数据团队,那么要怎么做呢?

**一个思路是:**可以使用 HTTP 或者 RPC 的方式来同步地调用,也就是数据团队这边提供一个接口,我们实时将秒杀的数据推送给它,但是这样调用会有两个问题:

整体系统的耦合性比较强,当数据团队的接口发生故障时,会影响到秒杀系统的可用性。

当数据系统需要新的字段,就要变更接口的参数,那么秒杀系统也要随着一起变更。

这时,我们可以考虑使用消息队列降低业务系统和数据系统的直接耦合度。

秒杀系统产生一条购买数据后,我们可以先把全部数据发送给消息队列,然后数据团队再订阅这个消息队列的话题,这样它们就可以接收到数据,然后再做过滤和处理了。

秒杀系统在这样解耦合之后,数据系统的故障就不会影响到秒杀系统了,同时,当数据系统需要新的字段时,只需要解析消息队列中的消息,拿到需要的数据就好了。

img

异步处理、解耦合和削峰填谷是消息队列在秒杀系统设计中起到的主要作用,其中,异步处理可以简化业务流程中的步骤,提升系统性能;削峰填谷可以削去到达秒杀系统的峰值流量,让业务逻辑的处理更加缓和;解耦合可以将秒杀系统和数据系统解耦开,这样两个系统的任何变更都不会影响到另一个系统,

如果你的系统想要提升写入性能,实现系统的低耦合,想要抵挡高并发的写流量,那么你就可以考虑使用消息队列来完成。


四、小结

在高并发系统设计中,消息队列是一个重要的工具,用于解决性能、可用性和可扩展性等核心目标。在处理高并发写请求的场景,特别是秒杀活动等涌入大量写流量的情况下,消息队列发挥了关键作用。

  1. 削峰填谷: 消息队列通过将秒杀请求暂存在队列中,实现了对瞬时写高峰的削平,从而降低了数据库的写入压力。这确保了系统在高并发写入时能够更好地处理请求,避免数据库崩溃的风险。
  2. 异步处理: 通过异步处理,可以将业务流程中的主要和次要逻辑分开处理,提升系统性能。例如,在秒杀场景中,将发放优惠券、增加用户积分等次要逻辑异步处理,加速主流程的执行,缩短用户等待时间。
  3. 解耦合: 消息队列帮助实现系统模块之间的松耦合,特别在数据系统与秒杀系统之间。通过将购买数据发送到消息队列,数据团队可以订阅消息,实现数据的解耦,避免系统直接调用接口导致的紧耦合问题。

总体而言,消息队列在高并发系统设计中的应用,不仅有效应对瞬时写入高峰,还通过异步处理和解耦合提升系统整体性能和可维护性。


速记

消息队列作用:异步、解耦、削峰

异步:将主逻辑和次逻辑分离,异步处理次逻辑。如秒杀系统主要的流程是生成订单、扣减库存;次要的流程可能是我们在下单购买成功之后会给用户发放优惠券,会增加用户的积分。通过次逻辑异步执行提高主逻辑的响应速率。

解耦:数据团队只需要订阅了订单的消息Topic,即可拿到对应的订单信息,无需在订单创建的时候调用数据团队的接口。与此同时,如果数据团队接口变更,也无需改动创建订单接口,实现业务解耦。

削峰:将秒杀请求暂存在消息队列中,然后业务服务器会响应用户“秒杀结果正在计算中”,释放了系统资源之后再处理其它用户的请求

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FrozenPenguin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值