当前位置: 首页 > 科技观察

面试官问我:秒杀场景怎么设计?

时间:2023-03-21 21:27:50 科技观察

前段时间在公众号读者交流群中,有读者提出了关于并发场景的问题:从读者的描述中可以看出,高并发处理的经历在面试中占据了举足轻重的地位。关于高并发相关的面试题一直是热门的面试题,因为这样的面试题更能直观的反映应聘者的技术水平和深度。如何解决高并发场景下的问题永远不会过时。在我之前的工作经历中,做过营销相关的项目,接触过关于门票闪购的高并发场景,可以算是最热门的高并发场景之一。下面我简单写下我对秒杀场景的一些理解,仅供大家参考,欢迎大家留言指正或补充。高并发的核心要素是什么?高并发是指同时有大量的用户请求同时到达服务器,服务器需要在有限的资源内处理这些请求,并以最快的速度响应用户的请求。在秒杀场景下,我们需要提升服务端在大量并发请求的过程中的处理性能。在处理过程中,数据处理不能避免错误。同时,整个秒杀链路需要满足高可用,即在秒杀过程中,服务不能突然掉链,需要完成秒杀场景Activity的生命周期。我们可以总结出秒杀场景的三个核心要素:高性能;一致性;和高可用性。如何提高性能?秒杀场景的核心问题是如何解决海量请求带来的性能问题,那么我们如何在资源有限的情况下最大化服务器访问的性能呢?根据我以往的经验,我大致总结了以下几点:热点数据处理、流量调峰、资源隔离、服务器优化。热点数据处理1.什么是热点数据?在我的理解中,热点数据是指用户请求数量非常多的数据。在秒杀场景下,热点数据就是秒杀的商品数据。这些热点请求会占用大量的服务器资源。如果不对数据进行处理,会严重占用资源,影响系统的性能,影响其他业务。热点数据可以分为“静态热点数据”和“动态热点数据”。2.静态热点数据静态热点数据是指可以预先预测的热点数据。比如本文提到的闪购场景,需要参与此次闪购的商家需要提前注册,将闪购商品录入热点分析系统。业务系统这次预加载了提前录入的热点数据,甚至将数据放在了本地缓存中。这样做的好处是可以有效缓解缓存集群的压力,避免在流量集中时缓存集群被压垮。可能有人会问如何更新本地缓存?我的做法是将热点数据录入热点分析平台,在本地订阅热点数据,根据订阅规则更新本地缓存。3.动态热点数据动态是指无法提前预测哪些数据是热点,需要通过数据进行采集分析,或者通过大数据平台进行预测。我的做法是在网关平台搭建一个异步日志采集系统,用于采集日志,采集商品请求的日志,处理后发送到热点分析平台。热点分析平台分析计算这些热点商品的热点数据处理,后台可以通过订阅这些热点数据来识别哪些商品是热点数据。流量削峰是在服务器资源固定的情况下,表示处理能力出现峰值。如果请求没有得到处理,很可能在流量高峰的那一刻使服务器不堪重负,但流量高峰并不存在很长时间。实际上,服务器的处理能力大部分时间是闲置的,那我们能不能把高峰集中的请求分散到其他时间呢?1、消息队列除了解耦和异步的场景,消息队列最大的作用场景是使用由于流量调峰,面对海量的流量请求,可以将这些请求数据以异步的方式存储在消息队列中,而消息队列一般可以存储大量的消息,消息会被消费者订阅消费,从而将峰值平均分配给其他时间处理。上面说了,消息队列就像我们平时看到的蓄水池。洪水来临时,阻拦蓄水,减少对下游的影响,避免洪水的灾害。目前有大量优秀的开源消息队列框架,如RocketMQ、Kafka等,而我在中通的时候主要负责消息平台的搭建和维护。队列在“防洪”中起到了很大的作用!2、除了利用消息队列“保存”请求达到调峰的目的外,还可以在用户发起请求前对用户进行一些验证操作,如答题、输入验证码等.,这个应答机制,除了防止买家在秒杀过程中使用作弊脚本外,秒杀场景中最重要的操作就是将请求分散到各个时间点,秒杀场景一般都是集中在某个点上,比如如0:00,如果没有应答机制,几乎所有的流量都会在0:00流入服务器,如果有应答机制,可以延迟用户的请求,从而可以将请求分发到各个时间点有目的的。如何保持一致性?秒杀场景本质上是在大量买家同时请求购买的情况下,能够准确的卖出商品。在秒杀的高并发读写请求过程中,需要保证商品不会“超卖”,因为秒杀的商品数量是固定的,但是会有成千上万的用户同时下单进货、减量在减库存的过程中如何保证商品数量的准确性是非常重要的。减库存方案分析我在做闪购项目的时候,分析了几种减库存的方法,这里简单分析一下。1、下单减少库存。只要买家完成订单,产品库存将立即扣除。这种方法最简单,也最准确。通常,可以利用数据库的交易能力来保证下订单时库存减少的准确性。但需要考虑买家下单后不付款的情况。2、付款后减库存是指买家下单后,库存不会立即减少,而是在用户付款后实际减少库存,否则库存会一直留给其他买家。但是因为只是在付款的时候减少了库存,如果并发量比较高,可能会出现买家下单后无法付款的情况,因为商品可能已经被别人买了。库存扣款仅在买家下单并完成付款后进行。这种方式的好处是可以避免出现买家不付款实际卖不了那么多产品的情况,但是这种方式会造成用户体验。不好,因为这样会导致部分用户在付款的时候可能会买到商品,导致付款失败。3.预扣库存这种方法综合了以上两种方法的优点。买家下单时,预扣库存只会保留一定的时间,比如10分钟。如果买家在此期间不付款,则库存将自动释放,其他买家可以继续抢购。这种方式需要买家在付款前查看商品库中是否有预定。如果没有保留,则再次尝试保留。扣缴不成的,不得再缴纳;如有预约,将在付款完成后进行实扣。股票行动。但是,扣存库存仍不能彻底解决存货扣减环节存在的问题。例如,一些买家可以在发布的那一刻立即再次下单,这相当于无限期地保留库存。因此,我们还需要记录用户下单的次数。如果连续下单次数超过一定次数,或者下单次数超过支付次数,用户的下单请求将被拦截。总结:一般来说,最简单的方法就是使用下单的方式来减少库存(我之前的项目就是这么用的)。我最初的考虑是因为在秒杀场景中,产品的性价比通常很高。秒杀就是创造一个只有少数买家才能购买的A场景。一般来说,买家只需要“秒”就可以拿到商品,极少数情况下会有退款。即使出现少量退款,实际售出的产品也会高于数据。如果太小,也可以通过交替来解决。如何降低库存?去库存行动应该在哪里进行?下面我来分析一下几种减库存的实现方式:如果环节涉及的逻辑比较简单,比如下单减库存,最简单最好的方式是利用数据库的本地事务机制来减库存下单时清点,比如使用whereinventory>0,不满足则回滚;将库存数量值放在缓存中,比如Redis,做持久化处理。需要注意的是,如果扣除存货的逻辑很复杂,比如在扣除存货后同一个交易中还需要做一些其他的事情,那么就不能使用第二种方法,只能使用第一种方法在数据库层面进行操作,保证他们在同一个事务中。面对这种情况,可以隔离数据库中的热点数据,将这些热点产品放在单独的数据库中。如何实现高可用?最后,为了保证秒杀系统的高可用,必须对系统进行彻底的处理,使系统在极端情况下仍然可以运行。通常的方法包括服务降级、服务限流和请求拒绝。.ServiceDegradation当请求量达到系统的承受能力时,需要关闭系统的一些非核心功能,将尽可能多的资源留给秒杀的核心环节。比如在秒杀系统中,还有其他一些非核心功能。我们可以在系统中设计一些动态的开关,比如网关层的路由开关,在最外层直接拒绝这些非核心的请求。另一种是通过简化页面展示的数据,降低用户体验来换取核心环节的稳定运行。服务限速的目的是通过限制并发访问/请求或一个时间窗口内的请求的速率来保护系统。常用的有QPS限速,用户请求排队限速,需要设置一个过期时间。一旦超过过期时间,就会被丢弃。这样做是为了让用户请求达到快速失败的效果。这个机制也和RocketMQ中的应用有关。RocketMQ代理会对客户端请求进行排队和限制。当请求在队列中超过过期时间,将被丢弃,客户端快速失败并进行第二轮重试。拒绝请求如果服务降级和服务限速都不能解决问题,最后的办法就是直接拒绝用户请求,比如直接向用户返回“服务器正忙,请稍后再试”等提示。它只会在服务器过载时启动,因此只会短时间不可用。由于此时服务仍在稳定运行,当负载下降时可以快速恢复正常服务。本文转载自微信公众号《后端进阶》,可通过以下二维码关注。转载本文请联系后端高级公众号。