高并发系统设计十五-消息队列:秒杀时如何处理每秒上万次的下单请求

1、场景分析

在项目中遇到一些存在高并发写请求的场景,例如秒杀抢购。

比如6.18,活动从0:00开始,仅限前 200 名,那秒杀即将开始时,后台会显示用户正在疯狂的刷新 APP

或者浏览器来保证自己能够尽早的看到商品

对于这种情况,你应该考虑什么呢?

  • 当秒杀开始前,用户在不断的刷新页面,系统应该如何应对高并发的读请求呢?
  • 在秒杀开始时,用户瞬间向系统请求生成订单,扣减库存,系统应该如何应对高并发的写请求呢?
1.1、系统应该如何应对高并发的读请求
  • 使用缓存策略将请求挡在上层中的缓存中
  • 能静态化的数据尽量做到静态化
  • 加入限流(比如对短时间之内来自某一个用户,某一个IP、某个设备的重复请求做丢弃处理)
1.2、系统应该如何应对高并发的写请求

生成订单,扣减扣除,用户这些操作是不经过缓存直达数据库的。如果在 1 s 内,有 1 万个数据连接同时到达,系统的数据库会濒临崩溃。如何解决这个问题呢?我们可以使用 消息队列

2、消息队列

消息队列的作用:

  • 削去秒杀场景下的峰值写流量
  • 通过异步处理简化秒杀请求中的业务流程
  • 解耦,实现秒杀系统模块之间松耦合
2.1、削去秒杀场景下的峰值写流量

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

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

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

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

先处理主要的业务逻辑,采用异步处理次要的业务逻辑。

比如说,主要的流程是生成订单、扣减库存;次要的流程可能是我们在下单购买成功之后会给用户发放优惠券,会增加用户的积分。

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

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

将秒杀数据同步给数据团队,有两种思路:

  • 使用 HTTP 或者 RPC 的方式来同步调用,即提供一个接口,实时将数据推送给数据服务

    • 整体系统的耦合度较高,如果其中一个服务有问题,可能会导致另一个服务不可用
    • 数据服务需要的数据字段如果发生变化,秒杀服务需要同步修改
  • 使用消息队列

    将数据全部发送给消息队列,然后数据服务订阅这个消息队列,接收到数据。

3、其他问题

引入消息队列的同时也会引入新的问题,需要新的方案来解决,这就是系统设计的挑战,也是系统设计独有的魅力,而我们也会在这些挑战中不断提升技术能力和系统设计能力。

  • 同步流程和异步流程的边界在哪里?
  • 消息是否会丢失,是否会重复?
  • 请求的延迟如何能够减少?
  • 消息接收的顺序是否会影响到业务流程的正常执行?
  • 如果消息处理流程失败了之后是否需要补发?

你可能感兴趣的:(高并发系统设计,java)