22.微型秒杀模型

1.1 关于微型

微型并不是说并发量比较小或者逻辑比较简单。微型的意思是指库存比较小。而库存就是指我们要抢的东西的总量。当库存比较大的时候,架构和逻辑复杂度也会有相应的变化。

1.2 场景分析

我们有100个宝贝,这些宝贝非常抢手,很多人都想得到。但很显然,最终真正得到宝贝的人只有100个。如果出现了超过100个人购买成功了就是超卖,最终超卖的部分只能通过协商解决了。但是从发起购买到购买成功的过程中会有一个支付的过程。必须支付成功才能购买成功。因此如果库存的增减不恰当可能会出现假卖的情况。也就是有可能很多人同一时间购买,但大家都没有付款成功。后面的人来买的话提示没有库存了,事实上这些宝贝还没有卖出去,最终导致想要买宝贝的人没能买到。整个购买模型如下图所示:

这里的关键在于会异步调用第三方支付网站完成支付,在这个过程中,库存应该怎样减?在哪个步骤减?如何处理支付问题等很多问题会影响商品购买流程。

1.3 一种假设

如果我们的网站架构师单实例单库,很多问题会非常简单。我们可以通过加锁,限流,串行化等手段解决。但是这样的网站架构显然不满足高并发,分布式的要求,不能承受较大的点击量。因此,我们的秒杀模型都是基于多实例,分布式,Redis缓存,MySQL分表分库等架构。能够承受较大的并发。

二 几种秒杀模型分析

2.1 在支付前扣减库存

为了防止超卖,我们可以在跳转到第三方支付进行支付之前扣减库存,这样可以有效防止商品因为超卖而导致的退款流程。但是很显然,这样会带来假卖的问题。假如一下子非常多的用户涌进来,他们占完了全部库存,但是迟迟不付款或者支付失败。导致后面的用户点击购买的时候提示没有库存而无法购买。一种稍微好点的办法是在支付成功时统计一下购买成功的总数,用总库存减去购买成功数得到剩余库存做一次修正。这样可以修正某些场景,但是如果有恶意用户,提交很多不支付的订单将库存消耗完(占着茅坑不拉屎),就会导致假卖问题。

2.2 在支付成功后减库存

为了防止2.1模型的假卖问题,我们将扣减库存问题放在支付成功后。这样可以解决假卖问题,但是会带来超卖问题。设想这样一种场景:大量用户点击购买,已经跳转到第三方支付网站进行支付,因为我们还没有获得支付结果,支付网关不会回调我们的支付完成逻辑,因此不会扣减库存。这样可以让无限的用户进入支付环节。最终如果这些用户全部支付成功显然会导致大量超卖的情况。

2.3 排队模型

联系到现实生活的场景,这样的问题最好的办法就是引入排队机制。排在前面的人可以成功购买,后面的人如果没有库存自然无法购买。大家按照时间顺序先后来,如果中间有人放弃,自然有后面的人顶替。这样自然保证了公平,公正。而且也不会出现超卖假卖问题。

这个思路是对的,关键是如何实现的问题。

三 实现排队模型

排队模型里有一个关键问题,就是锁票超时机制。比如我们买电影票,飞机票。都有一个锁票支付机制。超时之后如果没有完成支付则自动释放当前锁定的票资源,重新进入票池给别人购买。这样可以解决占着茅坑不拉屎的问题。

3.1 单实例模型

假如是单实例模型,我们可以将发起的请求全部放入一个数组,这个数组的长度就是宝贝数量(微型的意义在于宝贝数量较少,可以保证这里不会占用太多的空间)。启动一个线程,专门处理那些超时或者中途放弃的用户,以便让新用户能及时进入排队购买。但是假如这个线程挂掉或阻塞了,同样会导致假卖的问题。

因此较好的办法就是设置自动超时的缓存,对于超时的用户自动清除,以便让后来的用户可以进入支付环节。这个缓存可以自己实现,也可以使用Guava。

3.2 多实例分布式模型

显然对于多实例分布式模型设置本地缓存是行不通的。多实例分布式的话可以借助Redis缓存。但是Redis缓存的超时都是以key为基础的。使用哪种缓存结构可以实现我们的需求?

想来想去只有结合两种模式。Hash和String。使用String存放单个的用户,代表排队位。谁先支付完成谁就买到票。使用Hash统计排队人数。每次加入的时候,先遍历Hash,将因为超时失效的String用户剔除掉,这样就自然释放了资源。

类似于这样:任何一个用户进来必须先获得一张入场券,这个入场券的有效时长是设定的超时时间。如果在这个时间内完成了支付,则购买成功。如果没有支付,则超时后下一名购买者进来的时候自动剔除,同时获得这张券。当一个用户购买成功后,释放这张券。每个用户进来的时候,都要保证当前发放的入场券总量不超过库存剩余总量。当发放的券总量等于库存剩余的时候,后面的人自然提示暂时没有空余票,稍后再试。

这样我们就避免了另外开启线程来清除超时释放库存,也有效地在支付前控制了假卖,在很大几率上避免了超卖。但是存在一个问题,因为每个用户进来我们都要循环遍历一遍缓存,清理超时用户。因此库存不宜过大,否则循环耗时太长,用户体验不太好。

四 总结和拓展

对于秒杀模型,可能出现的问题就是假卖和超卖问题。而解决这个问题的办法就是排队和超时机制。如果我们的库存非常大(这样就不需要秒杀了),在最后库存余量不是很大的情况下如果出现高并发没有排队和超时机制同样会出现超卖和假卖问题。为了保险起见,其实在运营手段上也应该采取一些办法,比如本来总共1000件商品,我只买980件,剩余20件用于补给超卖部分。考虑到用户体验和退款等,宁愿少卖也不多卖。当然这些应该根据具体的业务需求来决定。

假如是库存非常大的情况,我们也可以考虑化大为小。在分布式环境下,将其平均分配,每台实例上卖一部分就将库存消化了。也可以引入大型排队系统和超时回调机制。当超时时自动触发一些业务流程。当然这些实现需要我们自己写很多代码,不能依赖Redis等缓存超时机制了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容