概述
限流:通过配置sentinel解决
队列、异步
通过加锁sychronized或者lock来说定扣减优惠券这一步的化,出现的问题是:sychronized作用范围是单个jvm实例,对于集群分布就失效了,且单机jvm加锁之后变成串行效率下降
可以用分布式锁,但是分布式锁过于笨重性能下降。
有时为了解决ABA问题,还需要加上一个版本号字段,然后判断版本号是否相同。
扣减库存的多种sql适用场景
第一种 : update product set stock=stock-1 where id = 1 and stock>0
第二种: update product set stock=stock-1 where stock=#{原先查询的库存} and id = 1 and stock>0
第三种 :update product set stock=stock-1,versioin = version+1 where id = 1 and stock>0 and
version=#{原先查询的版本号}
核心是解决超卖问题,防止库存为负数:
对于方案1 :id是主键索引的前提下,如果每次只是减少一个库存,则可以才采用,只做数据安全的校验,可以有效减库存,性能更高,避免大量无效sql,只要有库存就可以操作成功
场景: 高并发场景下的取号器,优惠券发放扣减库存
方案2:使用业务自身的条件作为乐观锁,但是存在ABA问题,对比方案3 的好处是不用增加version版本号,如果只是扣减库存且不关心ABA问题,则可以采用。
方案3:增加版本号主要是为了解决ABA 问题,数据读取后,更新前数据被人篡改过,version只能做递增。
场景:商品秒杀,优惠券方法,需要记录库存操作前后的业务。
个人超领优惠券
领取优惠券的过程中,校验和保存到数据库两步没有加分布式锁,导致个人超领优惠券;
实现分布式锁的方法有mysql、redis、zookeeper
分布式锁的框架redisson
分布式锁https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95
使用分布式锁插件
1、导入一俩到common模块
<!--分布式锁-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.10.1</version>
2、配置分布式锁,在commoon中
@Configuration
@Data
public class APPConfig {
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private String redisPort;
@Value("${spring.redis.password}")
private String redispwd;
/**
* 配置分布式锁的redisson
* @return
*/
@Bean
public RedissonClient redissonClient(){
Config config = new Config();
// 单机方式
config.useSingleServer().setPassword(redispwd).setAddress("redis://"+redisHost+":"+redisPort);
// 集群模式
// config.useClusterServers().addNodeAddress("127.0.0.1:7004", "127.0.0.1:7001");
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
}
3、使用分布式锁
@GetMapping("lock")
public JsonData testLock(){
// 分布式锁与这个以及一样
// ReentrantLock reentrantLock = new ReentrantLock();
// reentrantLock.lock();
// reentrantLock.unlock();
RLock lock = redissonClient.getLock("lock:coupon:1");
// // 阻塞等待时间
// lock.lock(10, TimeUnit.SECONDS);
lock.lock();
//业务逻辑
try{
log.info("加锁成功,处理业务逻辑"+Thread.currentThread().getId());
TimeUnit.SECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
log.info("解锁成功");
lock.unlock();
}
return JsonData.buildSuccess();
}
redisson如何解决过期时间小于业务的执行时间:
采用看门狗的方式;
看门狗的检查锁的超时时间是30s。
// 多个线程进入会阻塞,等待锁释放 有看门狗,默认30s
rlock.lock();
// 加锁10s钟过期,没有watch dog 功能
rlock.lock(10,TimeUnit.SECONDS);
项目中设置事务的时候,先在启动类中开启事务管理,然后再需要事务的方法上面添加事务的注解。
最后
以上就是爱听歌小蚂蚁为你收集整理的高并发下如何解决超卖问题的全部内容,希望文章能够帮你解决高并发下如何解决超卖问题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复