精华内容
下载资源
问答
  • 下单减库存,如何解决并发减库存问题1. 减库存一般下单减库存的流程大概是这样的:1、查询商品库存。这里直接查的Redis中的库存。2、Redis中的库存减1。这里用到的Redis命令是:incrby -13、扣减数据库中的库存。...

    下单减库存,如何解决高并发减库存问题

    1. 减库存

    一般下单减库存的流程大概是这样的:

    1、查询商品库存。这里直接查的Redis中的库存。

    2、Redis中的库存减1。这里用到的Redis命令是:incrby -1

    3、扣减数据库中的库存。这里用数据库乐观锁,不用额外加锁

    4、异步刷新Redis中的库存

    5、定时扫描超时未支付的交易,库存加回去

    总结一下这个流程就是:先减redis库存,再减数据库库存,最后刷新redis库存

    用到的Redis命令可能:DECR key  或者  INCRBY key -1

    更新数据库的SQL可能是这样的:

    update 商品库存表 set 库存 = 库存 - 1 where 商品ID = xxx and 库存 > 0;

    或者

    update 商品库存表 set 库存 = 库存 - 1 where 商品ID = xxx and version = xxx;

    用乐观锁是一种比较好的方式,而且一遍ID字段都有索引,可以充分利用MySQL行级锁

    这种方式还有一个比较巧妙的地方是,利用redis的单线程来操作库存,而且又是原子命令,可以避免并发问题

    同时,先减redis库存后可以防止后续因库存不足而造成下单失败

    最后,数据库更新完以后,再通过MQ异步刷新缓存,可以使得redis中的库存误差不会太大

    交易系统会定时扫描超时未支付的订单,然后用MQ异步通知订单和商品中心,将订单关闭,库存再放回去

    2. 加锁

    加锁(比如:基于Redis的分布式锁)

    MQ可以把并行转成串行,但是并不能很好的解决并发访问的问题,只能靠锁

    加锁会影响性能,但是影响不大。假设我们用Redisson分布式锁,操作redis只需要几毫秒,因此这点儿损耗不是什么大问题。都是这么玩儿的,不加锁还能怎么办呢。

    3. 内存缓存

    在cms管理后台修改数据后,同步或异步刷新redis缓存,同时利用zookeeper刷新内存缓存,这样就可以不用等到需要用的时候再从redis中同步。

    一定要避免redis大key,最常见的就是hash key,设置的时候不注意,一不小心里面就几千个field了,这对查询非常不利,可以取模进行分片。

    一定要避免HGETALL命令,利用Pinpoint可以帮助我们分析每个请求在每个操作所消耗的时候,从而有助于我们优化

    数据迁移用Canal

    https://redis.io/commands/incr

    相关文章暂无相关文章

    展开全文
  • 0){//生成订单...sql2:库存-1}当没有并发时,上面的流程看起来是如此完美,假设同时两个人下单,而库存只有1个了,在sql1阶段两个人查询到的库存都是>0的,于是最终都执行了sql2,库存最后变为-1,超售了,要么...

    我们知道数据库处理sql是一条条处理的,假设购买商品的流程是这样的:

    sql1:查询商品库存

    if(库存数量 > 0)

    {

    //生成订单...

    sql2:库存-1

    }

    当没有并发时,上面的流程看起来是如此完美,假设同时两个人下单,而库存只有1个了,在sql1阶段两个人查询到的库存都是>0的,于是最终都执行了sql2,库存最后变为-1,超售了,要么补库存,要么等用户投诉吧。

    解决这个问题比较流行的思路:

    1.用额外的单进程处理一个队列,下单请求放到队列里,一个个处理,就不会有并发的问题了,但是要额外的后台进程以及延迟问题,不予考虑。

    2.数据库乐观锁,大致的意思是先查询库存,然后立马将库存+1,然后订单生成后,在更新库存前再查询一次库存,看看跟预期的库存数量是否保持一致,不一致就回滚,提示用户库存不足。

    3.根据update结果来判断,我们可以在sql2的时候加一个判断条件update ... where 库存>0,如果返回false,则说明库存不足,并回滚事务。

    4.借助文件排他锁,在处理下单请求的时候,用flock锁定一个文件,如果锁定失败说明有其他订单正在处理,此时要么等待要么直接提示用户"服务器繁忙"

    本文要说的是第4种方案,大致代码如下:

    //阻塞(等待)模式

    //非阻塞模式

    采用哪种方式,看并发数量吧。

    展开全文
  • 背景:高并发情况下,商品出现超卖的情况。最终目标:保证数据的最终一致性。Contrrler 层框架 : Spring MVC第一次尝试:最初的时候,发现Spring MVC是一个单例多线程的Controller框架。它在多线程同时访问的时候会...

    背景:高并发情况下,商品出现超卖的情况。

    最终目标:保证数据的最终一致性。

    Contrrler 层框架 : Spring MVC

    第一次尝试:最初的时候,发现Spring MVC是一个单例多线程的Controller框架。它在多线程同时访问的时候会出现线程不安全的情况。经过分析,发现如果不建立 成员变量 的话,线程不安全的情况是不会出现的。如果需要建立成员变量,解决这个问题可以通过ThreadLocal 来解决这个问题。 ThreadLocal 可以存储 独属于 线程的变量。(PS:说了这么多还是没解决这个问题)

    第二次尝试:发现不是Spring MVC的问题后,开始使用 Java1.5新特性中的Lock锁来解决这个问题。保证同一时期,只有一个线程可以进行写的操作。(暂时解决了问题)

    第二次尝试失败原因:后续订单量又一步的增长,发现又出现了超卖的情况。细查之后,发现是因为有多个 tomcat 容器,多个tomcat之间的锁不同步导致。

    第三次尝试:分布式同步锁。在经过大量的资料查询后,分布式锁无法满足一致性(Consistency)、可用性(Availability)和分区容错性,最多只能满足其中两项。所以,建议各位在程序设计之初就要做出取舍。在互联网这个行业中,我所接触的项目中大多都牺牲了 系统的强一致性,从而来换取 系统的可用性(但是系统一定要确保 数据的最终一致性)。为了确保 数据的最终一致性,分布式同步锁就这样诞生了。

    目前有一下几种方案:

    1,基于缓存实现分布式锁

    基于缓存实现的分布式锁,在性能上是非要好的,并且集群部署

    使用 setNX 来存储 锁的超时时间戳

    语法:

    SETNX key value

    setNX 解析:

    将 key 的值设为 value ,当且仅当 key 不存在。

    若给定的 key 已经存在,则 SETNX 不做任何动作。

    SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写

    返回值:

    设置成功,返回 1 。

    设置失败,返回 0 。

    问题一-死锁:如果一个持有锁的客户端失败或崩溃了不能释放锁

    问题一-解决方案:可以根据 锁的超时时间戳 来判断是否发生了,如果当前时间大于 lock的值,说明该锁已经失效,可以重新使用。但是要注意,发生这种情况不能 只del 然后 setNX。因为这样的话,当多个线程检测到超时后,就会去 del 该锁,然后持有他。

    问题二-多线程持有锁-解决方案:getSET

    语法:

    GETSET key value

    将指定的key设置指定的value值,并且返回之前存储的value值。当没有返回值时,返回 null

    假设现在 A1 服务器已经发生了死锁问题。这时 A2 服务器 setNX操作返回0, A2服务器 get操作检查是否超时。如果没超时就继续等待重试。

    如果已超时,就通过 getSET 重新设置超时时间,如果 A2服务器拿到的是未超时的值。说明在此之前 A3服务器 先一步进行了 getSET 操作,那么 A2服务器继续等待重试。

    注意:当持有锁的 A1 服务器准备 del 的时候,一定要再次检查一下 锁是否超时。如果已超时就不必要解锁了。

    2,基于Zookeeper实现分布式锁

    基于zookeeper临时有序节点可以实现的分布式锁。

    注意:基于 Zookeeper 实现的 分布式锁 有效的解决了 死锁这个问题。但是在性能上是不如 缓存锁的,而且需要对Zookeeper的原理有所了解。其次,使用Zookeeper也有可能出现问题。由于网络抖动,客户端与Zookeeper的连接断了,这时Zookeeper就会以为客户端挂了,就会删除锁节点。这时就会产生并发问题。

    3,基于 数据库实现分布式锁

    要实现分布式锁,最简单的方式可能就是直接创建一张锁表,然后通过操作该表中的数据来实现了。

    当我们要锁住某个方法或资源时,我们就在该表中增加一条记录,想要释放锁的时候就删除这条记录。

    总结:以上几种方案其实都无法做到完美。

    从 实现复杂度来说:Zookeeper与Redis差不多、最为复杂的是数据库

    从 性能角度来说:Redis最好、其次Zookeeper、最差为数据库

    从 可靠性来说:Zookeeper最好、其次Redis、最差为数据库

    个人建议,在使用分布式锁中 不要去使用 数据库的方式来进行操作。操作数据库需要一定的开销,并且行级锁不一定靠谱。

    关于Zookeeper实现的分布式锁,由于本人不是很了解Zookeeper,所以介绍的不是很详细。如果有兴趣的同学可以自己研究一下。(我会告诉你们,我用的就是 redis分布式锁吗 ^_^)

    PS:转载请注明出处

    展开全文
  • 一个下单的小示例(上代码,没加事务的时候):class IndexController extends Controller {public function index(){$stock = M('stock');$log = M('log');$condition['id'] = 1;if($stock->where($condition)->...

    一个下单的小示例(上代码,没加事务的时候):

    class IndexController extends Controller {

    public function index(){

    $stock = M('stock');

    $log = M('log');

    $condition['id'] = 1;

    if($stock->where($condition)->getField('stock_left') > 0) {

    $stock->where($condition)->setDec("stock_left");

    $data['op'] = 1;

    $log->add($data);

    } else {

    echo "已经没剩余了";

    }

    }

    }

    库存默认有100个:

    bVya0n

    日志表:

    bVya0w

    Apache ab工具并发一下:

    ab -n 1200 -c 1200 -w http://localhost/queue/index.php >> D:/1.html

    结果出并发问题(很自然的):

    bVya1j

    然后加了事务控制之后:

    class IndexController extends Controller {

    public function index(){

    $stock = M('stock');

    $log = M('log');

    $condition['id'] = 1;

    M()->startTrans();

    if($stock->where($condition)->getField('stock_left') > 0) {

    $res1 = $stock->where($condition)->setDec("stock_left");

    $data['op'] = 1;

    $res2 = $log->add($data);

    if($res1 !== false && $res2) {

    M()->commit();

    } else {

    M()->rollback();

    }

    } else {

    echo "已经没剩余了";

    }

    }

    }

    再测试并发一下:

    ab -n 1200 -c 1200 -w http://localhost/queue/index.php >> D:/1.html

    结果呢,输出的结果没问题(但是真的解决了并发问题吗?):

    bVya2q

    很多人说了用Redis队列来做,具体实施我还是有点不太清楚,请大家帮忙

    展开全文
  • ThinkPHP其实并不支持分布式缓存功能,这可以从官方提供的CacheMemcache.class.php文件中看到:if(empty($options)){$options=array('host'=>'127.0.0.1','port'=>11211,'timeout'=>false,'persistent'=>...
  • 这里我把淘宝下单并发解决方案的个人理解分享一下。我不是淘宝技术人员,本文只是写自己的理解,所以肯定是会有一些出入的。在session中牧劳为我们介绍了淘宝下单部分的技术方案变迁,我不介绍变迁,而只对现有...
  • 介绍如何在高并发状况下确保数据正确。在高并发请求下容易参数两个问题1.数据出错,导致产品超卖。2.频繁操作数据库,导致性能下降。测试环境Windows7apache2.4.9php5.5.12php框架 yii2.0工具 apache bench (a...
  • 在多个用户同时发起对一个商品的下单请求时,先查询商品库存,再修改商品库存,会出现资源竞争问题,导致库存...强制性的让下单的过程等待5秒,再等待的同时,另外一个用户也去提交相同产品的订单,这样就可以实现并发
  • 一个下单的小示例(上代码,没加事务的时候):class IndexController extends Controller {public function index(){$stock = M('stock');$log = M('log');$condition['id'] = 1;if($stock->where($condition)->...
  • java高并发并发:当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,...
  • 并发下如何保证单例模式的线程安全性呢?如何保证序列化后的单例对象在反序列化后任然是单例的呢?什么是单例模式?在文章开始之前我们还是有必要介绍一下什么是单例模式。单例模式是为确保一个类只有一个实例,并...
  • 重点研究自己不太擅长的技术:分布式、高并发、大数据量、数据库优化、高性能、负载均衡等。个人看法:不是很赞同。只看“最优解”、“最佳实践”,并不是“最佳实践”。看看不太妥的方法,也能促进思考。前几篇文章...
  • 查询了下Mysql 关于高并发的处理的资料,在这记录一下。高并发大多的瓶颈在后台数据逻辑处理,在存储,mysql的正常的优化方案如下:1、代码中sql语句优化2、数据库字段优化,索引优化3、加缓存,redis/memcache等4、...
  • 方案一:如果没有并发,订单号只在一个线程内产生,那么由于程序是顺序执行的,不同订单的生成时间戳正常不同,因此用时间戳+随机数(或自增数)就可以区分各个订单。如果存在并发,且订单号是由一个进程中的多个线程...
  • 扣减库存问题的解决 针对恶意用户下单的情况,我这里简单罗列了如下几种解决方案: (1)我们可以为经常提交订单之后不付款的用户添加对应的标签,当这些用户下单时,进行特殊处理,例如不扣减库存等(具体可以根据...
  • 浅谈高并发解决方案

    2021-08-08 03:22:51
    浅谈高并发解决方案 什么是高并发? 高并发(High Concurrency)通常是指通过设计保证系统能够同时并行处理很多请求。 通俗来讲,高并发是指在同一个时间点,有很多用户同时的访问同一 API 接口或者 Url 地址。它...
  • 本文实例讲述了PHP使用文件锁解决并发问题。分享给大家供大家参考,具体如下:新建一个.txt文件,文件中什么都不用写。【一】.阻塞(等待)模式:(只要有其他进程已经加锁文件,当前进程会一直等其他进程解锁文件)//...
  • 如何解决并发,秒杀问题

    万次阅读 多人点赞 2018-06-27 22:46:54
    问题2、“控制了10w个肉鸡,手里有10w个uid,同时发请求” 这个问题怎么解决哈? 答:上面说了,服务层写请求队列控制 问题3:限制访问频次的缓存,是否也可以用于搜索?例如A用户搜索了“手机”,B用户搜索“手机”...
  • 当没有并发时,上面的流程看起来是再正常不过了,假设同时两个人下单,而库存只有1个了,在sql1阶段两个人查询到的库存都是>0的,于是最终都执行了sql2,库存最后变为-1,超售了,这不是我们想要的结果吧。...
  • 然而,作为活动商品,库存肯定是很有限的,如何控制库存不让出现超买,以防止造成不必要的损失是众多电子商务网站程序员头疼的问题,这同时也是最基本的问题。从技术方面剖析,很多人肯定会想到事务,但是事务是控制...
  • 比如在下定单时我们要锁定商品表,如果下单的人非常多,就会导致商品表一直是锁定的状态,那么整个网站所有的要读商品表的功能都会阻塞无法读出商品,把整个网站拖慢了。 而文件锁只是锁定了一个跟网站没有关系的...
  • python 中如何解决并发问题

    千次阅读 2019-01-23 16:34:44
    例如:id为16的商品的库存为10,两人同时购买,每人买5件,如果产生并发问题,两人下单都成功,但是库存变成了5 解决办法: 悲观锁: 当查询某条记录时,即让数据库为该记录加锁,锁住记录后别人无法操作,使用...
  • php解决并发问题

    2021-02-08 22:29:42
    我们通常衡量一个Web系统的吞吐率的指标是QPS(Query Per Second,每秒处理请求数),解决每秒数万次的高并发场景,这个指标非常关键。举个例子,我们假设处理一个业务请求平均响应时间为100ms,同时,系统内有20台...
  • 订单并发处理思路

    2021-02-12 18:10:30
    简单分析一下业务:每个客户端下单,服务器在数据库上面都相应的执行两个操作,第一步把库存表某条库存信息update更新一下,同时在订单表中insert添加一个记录某某客户预定了某某商品的信息。这里有个事务和行级锁的...
  • 你的项目是如何处理重复请求/并发请求的?对于一些用户请求,在某些情况下是可能重复发送的,如果是查询类操作并无大碍,但其中有些是涉及写入操作的,一旦重复了,可能会导致很严重的后果,例如交易的接口如果重复...
  • 找工作时,经常能在招聘信息上看到这么一条:有构建大型互联网服务及高并发经验者,优先。但对中小公司的程序员来说,高并发似乎遥不可及——公司业务不需要,用户量级不够,老板说用不上高并发架构设计...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 20,476
精华内容 8,190
关键字:

如何解决同时下单的并发