怎么设计秒杀系统?

秒杀系统需要考虑哪些要素?

  • 要能支持高并发
  • 用户体验要好,不要返回异常信息
  • 对系统要友好(针对秒杀可以做业务上的隔离,单独把秒杀系统部署到独立的集群服务器上;可动态配置业务参数,比如商品金额,库存数量)
  • 避免高并发请求第三方系统

流量倒三角

用户的请求量是非常大的,需层层过滤(过滤掉无用的或重复的行为),最终有限的流量到达核心业务层。

动静分离或预热

在APP真正秒杀前,将要请求访问的页面资源缓存到客户端或CDN中,这样的话,在未来并发请求的时候,用户请求的是动态数据,而不是请求的静态数据,就不会因为请求数据量大,IO瓶颈等问题导致出现用户连接不上的异常。

隔离恶意请求

比如使用一些小工具,挂起多个线程疯狂抢购的恶意行为,可以采用nginx结合lua脚本以及通过redis限流,判断用户的有效性来隔离恶意请求。

用户的抢购状态

根据不同的用户抢购状态,定义好不同的处理路径

接入层要根据redis中的用户标识来判断是新进来秒杀的请求还是恶意的还是等待付款的请求。

如果是新进的用户,对商品库存进行扣减,如果能成功扣减,就代表这个用户抢到了这个商品。

请求经过nginx负载均衡到service服务,然后进行数据库加锁(串行化)进行扣减操作。

如果将扣减的行为落库,在高并发下,很容易出现数据库连接超时。

将数据库替换成redis

并发调用redis的本地方法decr减1,redis内部依然是串行化,单线程,减少了内核间线程切换的损耗。

redis底层用到了epoll,不需要阻塞遍历网络IO(数据到达->产生事件->处理数据)。

扣减成功即秒杀成功,但这还不是最终结果,因为还没有扣款。

nginx调用redis判断该商品是否还有库存,如果没有,则过滤掉后续对该商品的秒杀请求。

为了降低对服务层的冲击,接入层nginx可以有多个,通过LBS负载。

接入层nginx访问redis查看商品是否还有库存,如果没有,则直接更新客户端页面的js,客户端就没有必要再发起请求到服务器了。

service扣减成功后,然后进入订单交易流程,下单成功返回给用户秒杀成功提示,然后页面跳转进入扣款流程。

性能瓶颈

  • 对数据库的操作是串行化的,串行化就会产生性能瓶颈,所以需要将串行化的过程异构化。
  • 调用第三方支付,依赖第三方的可靠性,为了降低对外部系统的依赖,使用自有资金,比如花呗、京东白条。

将同步修改成异步(通过消息队列)

service服务通过MQ异步调用订单服务,将超出订单服务处理能力的流量放到MQ中,再由订单服务异步消费处理,这也是削峰的过程。

订单系统生成订单,给用户返回请求成功。

订单服务下单成功之后,也会往MQ中发一条消息,购买付款服务消费这条消息。

订单系统下了单,发送订单MQ消息,付款服务消费该消息,用户在点击付款跳转的页面可以看到这个订单信息。

用户确认订单信息之后,页面跳转进行购买付款的操作,通过接入层分流进入付款购买服务,付款购买服务查看订单的状态是否可以进行购买。

用户付款的时候,调用付款服务,付款服务产生一个MQ消息,再通过第三方支付服务消费消息再进行扣款处理。

猜你喜欢

转载自blog.csdn.net/qq_16485855/article/details/130164118
今日推荐