目录
- 限购问题
- 问题:活动产品,每个用户购买不能超过1个?
- 解决方案:Java锁(单机)
- 解决方案:分布式锁(集群)
- Redis实现分布式锁问题?
- setnx
- 锁超时释放
- 使用 redisson 来实现分布式锁
- 总结
限购问题
限购问题是生活中很常见的,如某某手机限购不能超过几台,商品搞活动时每人购买不能超过1件…
这种问题看似很简单,但一个处理不好,就会出现超买问题
问题:活动产品,每个用户购买不能超过1个?
线程1进来先校验A客户是否下单过,此时是没有,在还未来得及生成订单,线程2进来校验A客户是否下单过,由于线程1事务还未提交,所以线程2的校验是通过的,最终两个线程都能提交,导致超买了;
解决方案:Java锁(单机)
以客户和产品的维度来加锁,使校验和生成订单成为一个原子操作;
解决方案:分布式锁(集群)
分布式锁可以使用Redis、Zookeeper、数据库方式来实现;
Redis实现分布式锁问题?
setnx
设置redis锁时,避免程序挂了,使锁释放不了,需要设置过期时间;
为避免设置锁后还来不及设置过期时间就挂了,需要锁和过期时间同时设置;
锁超时释放
线程1获取锁后,执行的时间太久,锁提前失效了,线程2又获取到锁进来,之后线程1执行完了,释放锁,此时的锁是线程2的锁,由于线程1释放了锁,线程3又能进来了,此时需要判断是自己的锁才能释放;
由于线程2获取锁进来,线程1事务还没有提交,导致两个线程最终都能提交,此时需要判断是自己的锁才能释放并且提交事务,如果不是则进行回滚;
使用 redisson 来实现分布式锁
redisson解决的问题
- 可重入锁:在锁里面再上一次锁
- 重试获取锁:获取锁时设置一个超时时间,在这个时间内,如果锁被释放了,可以尝试再次获取
- 锁续时:业务执行时间过长时,锁自动续时
- 主从一致:redis在做主从时,从节点同步锁可能有点慢,主节点突然就挂了,由于从节点还未来得及同步锁,就被选为做主节点,其他线程再进来又能获取到锁;redisson多主多从机制解决,设置锁时向多主写,在加锁时需要每对主从节点都没有才能加锁成功
总结
限购问题需要先校验再生成一条新的数据,使用单纯的数据库乐观锁是解决不了的,这种场景就需要使用悲观锁来处理