扣库存

作者: Goooooooooooal | 来源:发表于2018-11-22 16:12 被阅读0次

1. 事务+锁 只适合单体应用

(1)MySQL默认事务隔离级别为可重复读,即1个事务多次读取同1条记录,返回的结果相同,但这只限于读操作。如果其它事务修改了记录,1个事务多次读取同1条记录,返回结果不同

(2)扣库存是1个复合操作,可以分解为,读取库存的值,对库存值进行减操作,将新增写回数据库

(3)在高并发下,如果不加锁,复合操作不能保证原子性。n个线程执行扣库存操作,线程安全情况下,库存值被-n;但如果不加锁,库存值被减的次数肯定<n

(4)例如线程A,查询DB,得到库存值100,将100-1,再写回DB。在未写入DB时,线程B查询DB,得到的库存值也是100,将100-1,再写回DB。此时库存值应该是98,但实际却是99,丢失1次操作

缺点: 使用JVM锁保证线程安全,只适合单体应用,在分布式下,无法保证

下单即减库存,不会出现超卖,但会出现少卖。对于下单的未付款的订单,超时将库存加回来(定时任务)

2. 事务+分布式锁 适合分布式应用,但是性能差,不使用

分布式系统下,每个应用多实例部署,相互独立,部署在单独的Web容器上,无法使用JVM锁保证线程安全。但是可以使用分布式锁,每个应用在扣库存时,去请求分布式锁,请求到的应用对库存进行减操作

缺点: 每次减库存,都需要请求分布式锁,走1次网络,性能差

3. 分库分表,将库存分为多份,由多个实例的数据库持有。库存总量单独存放在分布式系统的节点上。让多个实例轮询处理请求(使用Ribbon的负载均衡机制;传统方式可以通过对userID进行取余或Hash,将请求路由到对应的数据库和表),也就是轮询的扣库存,当库存扣完时,向库存总量申请,如果还有库存,可以继续扣库存,否则库存为0,不能再卖

(1)减少请求分布式锁的次数
实例扣完库存后,向库存总量申请,使用分布式锁做同步。与每1次扣库存都申请分布式锁相比,减少了请求锁的次数,不用每次都走网络。例如,10000个库存,分成10个实例,每个实例持有500个,扣完时向库存总量申请,最多会请求20次锁;但每次都请求分布式锁,需要请求10000次

(2)根据业务并发数,合理设置超时时间
Feign使用Ribbon和Hystrix,Ribbon和Hystrix都有超时时间。Hystrix默认1s,如果超时会执行fallback;Ribbon的connect超时和read超时默认都是1s

对于1000个线程的并发,经过测试,设置Ribbon read超时为3s, connect超时使用默认1s

高版本Feign默认关闭了重试,会和Ribbon重试冲突
(1)设置Ribbon的read超时时间和connect超时时间;设置1台Server的重试次数,设置最大重试的Server数;设置重试策略
默认情况,GET请求 read超时/connect超时,都会重试; 非GET请求,只对connect超时进行重试

(2)启用Feign的Hystrix,超时时间根据Ribbon重试策略设置;不要出现Ribbon还在重试,而Hystrix超时的情况

设置连接数
show variables like 'max_connections';
set GLOBAL max_connections=1000;

service层事务+synchronized,导致线程不安全

锁加在service层事务方法上,多个线程执行时,1个线程获取锁,其它线程等待。当1个线程执行完,退出同步块时,事务还未提交;MySQL默认事务隔离级别,是可重复读,SELECT结果是事务开始时间点的状态,当此时其它线程执行读取操作,读取的值是旧值,导致2个线程对同1个旧值执行操作,丢失1次操作

解决方式: 将synchronized加在Controller方法中

4. 只使用Redis

  1. Lua脚本,库存>0时,扣库存;库存=0时,不再操作

  2. 应用Redis单线程机制

  3. Redis崩溃,要有应对方案
    最简单的,使用AOF,不使用RDB

相关文章

  • 扣库存

    1. 事务+锁 只适合单体应用 (1)MySQL默认事务隔离级别为可重复读,即1个事务多次读取同1条...

  • SpringCloud微服务实战(七)-消息服务在电商中的实践

    6 商品和订单服务中使用MQ(上) 6.1 同步 在订单生成的时候直接扣库存,这是最初等的方式扣库存,这种方式比较...

  • 并发下的库存如何扣?

    并发下的库存如何扣? 背景 业务反馈,项目出现库存超卖/负值现象。 原因 假设库存为5,用户一次买了1个,于是库存...

  • 扣库存的方案

    扣库存的场景及问题 扣库存是电商系统里一个非常基础的操作。 在业务上,它必须要能达到: 不超卖 重试时,不出现假卖...

  • PHP 高并发情况的简单模拟,thinkphp

    看下面代码,一个简单的减库存模拟. 一,并发扣库存 1.原始数据里面有100个库存 2.下面进行减库存操作,代码如...

  • 库存热点分片扣库存技术实现

    一、背景 库存模块是一个更新数据库密集型的模块,无时无刻不在有库存更新操作,虽然目前线上库存使用了独立Oracle...

  • 超卖——⽅案

    1. ⾸先查询redis缓存库存是否充⾜ 2. 先扣库存再落订单数据,可以防⽌订单⽣成了没有库存的超卖问题 3. ...

  • 并发扣库存问题总结

    无论是日常工作中,还是面试问题中,并发扣库存都是一个很常见的场景,正好业务里有这样的场景,可以对这类问题做一下总结...

  • 2. springCloud Stream 实现异步扣库存

    一.原扣库存逻辑 二.使用SpringCloud Stream 异步下单 order服务 product服务 即可...

  • 如何保证消息的顺序性?

    一、背景 有的时候消费者消费消息是顺序消费的。比如生成一个订单,先扣库存,然后扣款。如果顺序错了,扣了款库存没了,...

网友评论

      本文标题:扣库存

      本文链接:https://www.haomeiwen.com/subject/gxhafqtx.html