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

高并发抢购系统,架构解密...

时间:2023-03-23 10:22:39 科技观察

背景大家好,本文介绍一个很经典的大厂面试经常被问到的问题,就是瞬间高并发抢购的问题。一般来说,各大厂商开发的系统经常会遇到电商闪购、景区门票高并发抢购、特色商品(如口罩)高并发抢购、高并发抢购等系统。ticketrushing类似于12306。所以经常问这种高并发抢购的问题。这时候如果你们不能给出系统在高并发场景下可能遇到的全套问题,以及你们相应的架构设计和解决方案,基本面试可能就凉了。那么今天就手把手的带大家来分析一下。假设在特殊物品紧缺的场景下,1分钟内需要抢购10万个口罩等特殊物品。这个时候可能会有几十万人在这个时候涌入抢购,这个时候系统可能会遇到什么问题,我们应该如何设计架构来解决这样的问题呢?首先,在业务架构设计中分析此类问题时,我们不应该考虑瞬时高并发有多高。首先要画出一个基本的业务架构图来实现这种特殊商品的购买,同时把业务流程分析清楚。看下面的图片。想要搭建商品抢购系统,就必须要有抢购系统。这个抢购系统,就得依赖商品系统。毕竟抢购过程中需要读写商品数据,还得依赖库存系统。库存抵扣,你要靠价格系统计算出商品的当前进货价,你得靠营销系统来核实商品进货的折扣。最终还是要靠鉴权、风控、拦截等基础系统来决定这次抢购能否执行。所以一个抢购其实涉及的系统很多,一个完整的基本高并发抢购系统图的基本业务架构。如下图1所示:图1:高并发抢购系统业务架构设计网络拓扑架构设计另外,我们还要搞清楚你的??抢购请求是如何一步步到达你的抢购系统的。我们还需要把这个工作流程画出来。一般来说,我们的APP移动端通过域名向后台发起请求,这个域名会通过DNS解析得到我们SLB负载均衡系统的ip地址。然后请求会发送到我们的SLB负载均衡系统,然后SLB负载均衡系统会把请求平均分配给我们后端的API网关系统,再由API网关系统把流量分配给我们的购买系统。所以大致如下图2所示:图2:高并发抢购网络拓扑设计好。可以面对面试官的时候,可以大致画出上面的一套业务架构图和生产部署网络拓扑图。出来之后,我们可以向大家保证,虽然面试官此时面无表情,但他内心真实的反映应该是这样的:小弟可以,大多数人一听到这个问题立马就懵了,但是这小子其实知道从分析业务架构和网络拓扑架构入手。但是大家不要太兴奋。成功分析完这道题你就刚刚完成了八千里的西游,剩下的十万里你还要继续走下去!一路走来,大家很快就会遇到形形色色的妖魔鬼怪!把自己振作起来,然后一起往下看。秒杀业务的流量高峰往往会出现在这里。下一步我们应该分析的是日常流量和抢购流量之间的区别。这是什么意思?先说说日常交通吧。购买各种商品,系统的大概流量应该是每秒请求多少次。这个问题不好说,因为不同的公司其实是不一样的,但是我们可以取一个比较中间的值。整个系统通常需要每秒1000个请求。这是一个比较中肯的价值。不高也不低。如下图3所示:图3:每日并发抢购系统业务流量情况一般来说,如果你的抢购系统和它所依赖的各个系统部署在2台以上的机器上,这种每秒1000个请求常规流量,各个系统的兄弟齐心协力共同扛起阻力,依旧没有太大的问题。但要举办这样的活动,某款特产限量10万份,大家特别需要。然后,极限就是每天早上10:00开始抢,每次都有几十万人红着眼睛盯着手机屏幕准备抢他,他志在必得。这时候,交通会是什么样子呢?注意,重头戏来了。一般来说,根据一般的抢购经验,往往你的10万件商品会在1分钟内售罄,而根据80/20法则,80%的商品在20%的时间内售罄。也就是说,10s内可能有8万件商品被抢购一空,而这8万件商品的流量已经达到了80%的人群。假设共有50万人参与抢购,即10s内有40万人发起抢购请求。8w件商品已售罄。此时每秒的请求数应该是40w/10s=4w/sQPS。下面看图4:图4:高并发抢购系统的业务流量。不知道大家看到上面的图是什么感觉呢?别糊涂啊,面试官听得津津有味,我们赶紧继续聊,要不这时候停下你会瞪我的!那么这个时候如果你的抢购系统发起的请求数量达到每秒4w,你觉得会发生什么?很简单,系统肯定会卡死,网络带宽爆满,CPU使用率达到90%以上,数据库负载过高,下游依赖频繁超时。所有这些问题都可能发生。你要问为什么?那是因为你的系统是常规部署的,可以抵抗每秒1000个请求,他们不是设计来抵抗你每秒4w个请求的。架构设计优化那么这次的问题涉及到一个点,就是你的抢购系统如何能够抵抗每秒40000个请求?为了解决这个问题,我们不得不利用面试官打瞌睡的时间。我会教你一些武术秘诀。一般情况下4核8G的机器开200个线程来处理请求。如果要调用其他服务或者访问数据库,基本上单机每秒可以抗1000个请求。并发抢购系统性能瓶颈分析不过要注意敲黑板划重点。并不是说你4核8G的机器每秒只能抗1000个请求。关键问题是它需要调用其他服务。而且,他还需要访问数据库。正是因为这种通过网络访问外部系统,所以他每秒抗拒的请求数比较少。下面看图5:图5:并发抢购系统的性能瓶颈。大家应该都知道,像Redis、RocketMQ这样的中间件系统,经过深度优化,往往单机抗几万甚至几万QPS都没有问题。深度优化是什么意思?总之,每次请求的时候最好根据自己的内存来读写数据,然后直接返回。不要只是通过网络访问外部系统。在这种情况下,你的并发往往可以提高几个数量级。如下图6所示:图6:并发购买系统架构深度优化并发购买系统架构优化那么,一般来说,在这种场景下,有3种非常强大的优化方式,即大大减少对外部服务调用的依赖;尽量将数据直接写入缓存,然后异步写入DB;尝试先将数据缓存在系统JVM内存中,本地读取返回。在这里我可以举一些例子。比如特价商品的固定价格抢购,是否可以省略对价格系统和营销系统的调用?毕竟价格是固定的,没有打折之说。风控、鉴权这些通用的操作,能不能预加载到API网关层面让他去执行,把这种通用的逻辑从我们的业务系统中去掉?这不会同时减少对4个系统的调用。再比如扣库存,库存系统能不能把数据同步到Redis,我们直接在Redis同步扣库存,然后异步发送MQ消息给库存系统的DB扣库存?对于大量的数据查询,是否可以将商品数据缓存在Redis中,同时将所有热门商品数据提前加载到抢购系统的JVM内存中进行本地缓存?优化后的抢购系统大致如下图7所示:图7:并发抢购系统架构的缓存优化。看上面的图片。优化后,我们的抢购系统不再直接调用任何服务。他在读取商品数据时,先从自己的JVM本地缓存中读取预缓存的数据,几乎是纯内存操作,然后扣除库存写入Redis。对于库存系统甚至订单系统数据库扣库存和下单都是通过MQ异步进行的。基本上,系统优化到这个程度,主要是给抢购系统多部署几台机器,让它能够承受每秒几万的高并发请求。但是这个时候结束了吗?当然不是。这个时候,系统还存在很多问题。我们还得一步步继续分析,进一步优化。①高并发抢购系统缓存击穿问题的分析与解决方案首先分析第一个问题,即抢购系统JVM本地缓存中商品数据缓存击穿。我们放在抢购系统的JVM本地缓存中的数据,一般是需要设置一个过期时间的,因为如果一直缓存在JVM中,商品数据会在你不知情的情况下发生变化。那么假设我们设置一个30分钟的过期时间,每30分钟过期一次。过期后,抢购系统要检查Redis中的商品数据缓存。如果没有找到,就要调用产品系统的接口去数据库中查询。如图8:图8:高并发买单系统-缓存数据过期问题那么当你的买单系统中本地缓存过期时,此时本地缓存是没有数据的,那么Redis中的缓存可能会在此时不可用这个时候,就在这个非常危急的关头,大量的请求进来了。这个时候,大量的请求在本地缓存中没有找到,Redis中也没有,然后呢?然后当然就完了,因为这些请求会涌入商品系统,让商品系统从数据库中查询,直接把商品系统打垮。如图9:图9:高并发抢购系统——缓存击穿问题所以这个时候,我们往往需要对这种本地缓存做一个特殊的设计,即对于本地缓存,不要使用这个方法让它自动过期,然后request过来的时候,没法再去读商品系统里搜索的模式,而是用抢购系统定时自动刷新本地缓存。也就是说,你可以在抢购系统里开一个后台线程,让他每隔30分钟自动查看Redis中最新的缓存数据,或者查看商品系统中最新的缓存数据,然后刷新本地缓存,这样就可以避免说自动过期后突然有大量请求在缓存中找不到而涌入商品系统。如图10所示:图10:高并发买单系统-缓存自动刷新机制②高并发买单系统数据不一致的分析及解决方案我们再来看下一个比较常见的问题,就是缓存与DB不一致,用于扣库存.场景可能发生在以下情况。也就是说,你在Redis中扣完库存后,你通过MQ异步发消息让库存系统扣掉DB中的库存,而对方的库存系统还没有扣完DB中的库存。这个时候你突然因为异常回滚了这一次扣库存,这时候在Redis中恢复扣库存,然后给MQ发消息恢复扣库存。如图11所示:图11:高并发抢购系统-数据不一致问题(1)但是此时,Redis中的库存恢复了,但是库存系统DB中就不一定了,因为当库存系统从MQ获取消息,速度很快。可能是乱序获取的,即先获取恢复库存的消息。这时库存系统一般会判断之前是否有过本次抢购的库存扣减日志。如果没有,他就不会恢复库存,然后得到库存扣减的消息。库存,但恢复库存的消息永远没有机会被处理。如图12所示:图12:高并发抢购系统-数据不一致问题(2)那么上面会导致什么呢?会导致在Redis中扣减库存,然后恢复,但是库存系统的DB先拿到恢复的库存指令,但是什么也没做,再拿到扣减库存指令,却扣掉了库存。这个时候缓存和DB里面的库存是不一致的。因此,为了解决这个问题,通常会实现MQ顺序消息,即将同一个急单的多条盘点操作指令发送到MQ的一个partition中,使其有序,盘点系统必须按顺序执行获取后,先执行库存扣减指令,再执行库存恢复指令。如图13所示:图13:高并发抢购系统-MQ时序消息总结,今天的文章到此结束,给大家讲讲我们在大厂经常遇到的高并发抢购系统的架构设计与实现。优化过程,以及缓存崩溃和数据乱序不一致的分析和解决方案。希望看完之后,大家在以后的面试中遇到此类问题时,能够有理有据地一步步分析,让面试官看到大家的淡定如水、一丝不苟的应变能力。