秒杀与超卖的 性能解决之路

一、秒杀带来了什么?

秒杀或抢购活动一般会经过【预约】【抢订单】【支付】这3个大环节,而其中【抢订单】

这个环节是最考验业务提供方的抗压能力的。



抢订单环节一般会带来2个问题:

  1、高并发

  比较火热的秒杀在线人数都是10w起的,如此之高的在线人数对于

网站架构从前到后都是一种考验。

 

 2、超卖

  任何商品都会有数量上限,如何避免成功下订单买到商品的人数不

超过商品数量的上限,这是每个抢购活动都要面临的难题。



二、如何解决?

首先,产品解决方案我们就不予讨论了。我们只讨论技术解决方案

1、前端

面对高并发的抢购活动,前端常用的三板斧是【扩容】【静态化】【限流】

  A:扩容

  加机器,这是最简单的方法,通过增加前端池的整体承载量来抗峰值。

  

B:静态化

  将活动页面上的所有可以静态的元素全部静态化,并尽量减少动态元素。通过CDN来抗峰值。

  

C:限流

  一般都会采用IP级别的限流,即针对某一个IP,限制单位时间内发起请求数量。

  或者活动入口的时候增加游戏或者问题环节进行消峰操作。

  

D:有损服务

  最后一招,在接近前端池承载能力的水位上限的时候,随机拒绝部分请求来保护活动整体的可用性。



2、后端

那么后端的数据库在高并发和超卖下会遇到什么问题呢?

主要会有如下3个问题:(主要讨论写的问题,读的问题通过增加cache可以很容易的解决)

  I:  首先MySQL自身对于高并发的处理性能就会出现问题,一般来说,MySQL的处理

性能会随着并发thread上升而上升,但是到了一定的并发度之后会出现明显的拐点,

之后一路下降,最终甚至会比单thread的性能还要差。

  II:   其次,超卖的根结在于减库存操作是一个事务操作,需要先select,然后insert,最

后update -1。最后这个-1操作是不能出现负数的,但是当多用户在有库存的情况下

并发操作,出现负数这是无法避免的。

  III:  最后,当减库存和高并发碰到一起的时候,由于操作的库存数目在同一行,就会出现

争抢InnoDB行锁的问题,导致出现互相等待甚至死锁,从而大大降低MySQL的处理性

能,最终导致前端页面出现超时异常。



针对上述问题,如何解决呢? 我们先看眼淘宝的高大上解决方案:

  I: 关闭死锁检测,提高并发处理性能。

  II:修改源代码,将排队提到进入引擎层前,降低引擎层面的并发度。

  III:组提交,降低server和引擎的交互次数,降低IO消耗。



解决方案1:

将存库从MySQL前移到Redis中,所有的写操作放到内存中,由于Redis中不存在锁故

不会出现互相等待,并且由于Redis的写性能和读性能都远高于MySQL,这就解决了高并发

下的性能问题。然后通过队列等异步手段,将变化的数据异步写入到DB中。

优点:解决性能问题

缺点:没有解决超卖问题,同时由于异步写入DB,存在某一时刻DB和Redis中数据不一致的风险。



解决方案2:

引入队列,然后将所有写DB操作在单队列中排队,完全串行处理。当达到库存阀值的时候

就不在消费队列,并关闭购买功能。这就解决了超卖问题。

优点:解决超卖问题,略微提升性能。

缺点:性能受限于队列处理机处理性能和DB的写入性能中最短的那个,

另外多商品同时抢购的时候需要准备多条队列。



解决方案3:

将写操作前移到MC中,同时利用MC的轻量级的锁机制CAS来实现减库存操作。

优点:读写在内存中,操作性能快,引入轻量级锁之后可以保证同一时刻

只有一个写入成功,解决减库存问题。

缺点:没有实测,基于CAS的特性不知道高并发下是否会出现大量更新失败?

不过加锁之后肯定对并发性能会有影响。



解决方案4:

将提交操作变成两段式,先申请后确认。然后利用Redis的原子自增操作(相比较MySQL的

自增来说没有空洞),同时利用Redis的事务特性来发号,保证拿到小于等于库存阀值的号的人都

可以成功提交订单。然后数据异步更新到DB中。

优点:解决超卖问题,库存读写都在内存中,故同时解决性能问题。

缺点:由于异步写入DB,可能存在数据不一致。另可能存在少买,也就是如果拿到号的人

不真正下订单,可能库存减为0,但是订单数并没有达到库存阀值。

原文地址:https://www.cnblogs.com/changyu521/p/11765575.html

时间: 2024-10-08 10:29:26

秒杀与超卖的 性能解决之路的相关文章

关于秒杀和超卖的性能问题

一.秒杀带来了什么? 秒杀或抢购活动一般会经过[预约][抢订单][支付]这3个大环节,而其中[抢订单]这个环节是最考验业务提供方的抗压能力的. 抢订单环节一般会带来2个问题: 1.高并发 比较火热的秒杀在线人数都是10w起的,如此之高的在线人数对于网站架构从前到后都是一种考验. 2.超卖 任何商品都会有数量上限,如何避免成功下订单买到商品的人数不超过商品数量的上限,这是每个抢购活动都要面临的难题. 二.如何解决? 首先,产品解决方案我们就不予讨论了.我们只讨论技术解决方案 1.前端 面对高并发的

项目中遇到的超卖问题及解决办法(使用go做测试工具)

超卖问题:在一个很短的时间内,Mysql的数据状态在 取出,比较,提交,或修改中,另外一个进程访问数据导致的超卖问题. 案例: 1.前端没有做限制,如果用户连续点击签到,那么会有多条数据发送到后端,如果数据状态没有来得及完全修改过来,导致用户的签到数据被多次添加. 2.每天签到用户的前3名用户可以获得一张价值100元的优惠券,如果有多名用户在很短的时间内同时签到,那么就会有多发的问题. 解决案例1:使用数据库的行锁和表锁 DROP TABLE IF EXISTS `crm_concurrency

使用 redis 减少 秒杀库存 超卖思路

由于数据库查询的及插入的操作 耗费的实际时间要耗费比redis 要多, 导致 多人查询时库存有,但是实际插入数据库时却超卖 redis 会有效的减少相关的延时,对于并发量相对较少的 可以一用 1 public function buy($goods_id = 0){ 2 if(!$goods_id){ 3 die("商品不存在!"); 4 } 5 $redis = new Redis(); 6 $redis->connect('127.0.0.1',6379); 7 $stock

如何解决秒杀的性能问题和超卖的讨论

如何解决秒杀的性能问题和超卖的讨论 最近业务试水电商,接了一个秒杀的活.之前经常看到淘宝的同行们讨论秒杀,讨论电商,这次终于轮到我们自己理论结合实际一次了. ps:进入正文前先说一点个人感受,之前看淘宝的ppt感觉都懂了,等到自己出解决方案的时候发现还是有很多想不到的地方其实都没懂,再次验证了“细节是魔鬼”的理论.并且一个人的能力有限,只有大家一起讨论才能想的更周全,更细致.好了,闲话少说,下面进入正文. 一.秒杀带来了什么? 秒杀或抢购活动一般会经过[预约][抢订单][支付]这3个大环节,而其

秒杀的性能和超卖

一.秒杀带来了什么? 秒杀或抢购活动一般会经过[预约][抢订单][支付]这3个大环节,而其中[抢订单]这个环节是最考验业务提供方的抗压能力的. 抢订单环节一般会带来2个问题: 1.高并发 比较火热的秒杀在线人数都是10w起的,如此之高的在线人数对于网站架构从前到后都是一种考验. 2.超卖 任何商品都会有数量上限,如何避免成功下订单买到商品的人数不超过商品数量的上限,这是每个抢购活动都要面临的难题. 二.如何解决? 首先,产品解决方案我们就不予讨论了.我们只讨论技术解决方案 1.前端 面对高并发的

解决redis秒杀超卖的问题

我们再使用redis做秒杀程序的时候,解决超卖问题,是重中之重.以下是一个思路. 用上述思路去做的话,我们再用户点击秒杀的时候,只需要检测,kucun_count中是否能pop出数据,如果能pop出来则证明还有库存,且秒杀成功.而且pop是原子性的,即使很高的并发, 同时有很多用户访问,也是排队一个一个解决(并行转串行). 这样的话,就解决了超卖的问题.至于存入磁盘,我的上一篇文章中有介绍.有需要的朋友可以去看. 这是一个思路,具体的秒杀程序应该还有很多细节需要完善,但是核心问题已经解决了哈.

[转] 基于MySQL的秒杀核心设计(减库存部分)-防超卖与高并发

商品详情页面的静态化,varnish加速,秒杀商品库独立部署服务器这种就略过不讲了.只讨论库存部分的优化 mysql配置层面的优化可以参考我的这篇文章 <关于mysql innodb引擎性能优化的一点心得> 重点设计在数据库层面. 2张表: 第一张:判重表(buy_record),该用户有没秒杀过该商品 字段: id, uid, goods_id, addtime 第二张表:商品表 goods 字段: goods_id   goods_num 方案1: start transaction; s

大型车祸现场,电商秒杀超卖,这个锅到底有谁来背?

背景 小明在一家在线购物商城工作,最近来了一个新需求,需要他负责开发一个商品秒杀模块,而且需求很紧急,老板要求必须尽快上线. 方案 小明一开始是这么做的,直接用数据库锁进行控制,获取秒杀商品数量并加锁,如果数量大于零则成功,否则秒杀失败. @Override @Transactional public Result startSeckilDBPCC_ONE(long seckillId, long userId) { //获取秒杀商品数量并加锁 String nativeSql = "SELEC

redis分布式锁解决超卖问题

1.1 redis事物 1.redis事物介绍 1. redis事物是可以一次执行多个命令,本质是一组命令的集合. 2. 一个事务中的所有命令都会序列化,按顺序串行化的执行而不会被其他命令插入 作用:一个队列中,一次性.顺序性.排他性的执行一系列命令 2.multi 指令基本使用 1. 下面指令演示了一个完整的事物过程,所有指令在exec前不执行,而是缓存在服务器的一个事物队列中 2. 服务器一旦收到exec指令才开始执行事物队列,执行完毕后一次性返回所有结果 3. 因为redis是单线程的,所