Redis分布式锁解决优惠券超卖
Redis 是一个开源的内存数据结构存储,它是一个独立的数据库/缓存服务
Redisson 是一个基于 Redis 的 Java 客户端框架,它在 Redis 基础上提供了分布式对象和服务
面试官,我是这样解决优惠券超卖的:
1. 核心思路:用Redis的SETNX命令实现分布式锁
2. 具体做法:
- 用户领取优惠券时,先生成一个锁的key,比如:`coupon:lock:1001`
- 用`SET lock_key user_id NX EX 10`命令尝试获取锁
- NX:只有锁不存在时才能设置(互斥)
- EX 10:10秒后自动过期(防止死锁)
- 这个命令是原子的,保证设置值和过期时间一起完成
3. 业务处理:
- 如果拿到锁,就查询库存、扣减、发券
- 如果没拿到锁,直接返回"系统繁忙"
4. 锁续期:
- 启动一个看门狗线程,每隔几秒给锁续期
- 保证业务执行时间不会超过锁的过期时间
5. 释放锁:
- 业务完成后,删除这个key释放锁
- 用Lua脚本保证原子性,只删除自己的锁
这样就能保证同一时间只有一个线程能操作库存,不会超卖。
**面试官,我在项目中用Lua脚本实现分布式锁,主要解决三个问题:**
1. **获取锁的原子性**:
- 用Lua脚本把SETNX和EXPIRE放在一起执行
- 保证设置锁和设置过期时间是原子的
- 脚本:`if redis.call('setnx', key, value) == 1 then redis.call('expire', key, expire)`
2. **释放锁的安全性**:
- 用Lua脚本检查是否自己的锁,然后删除
- 避免误删别人的锁
- 脚本:`if redis.call('get', key) == value then return redis.call('del', key)`
3. **看门狗续期**:
- 用Lua脚本给自己的锁续期
- 保证业务执行时间不会超过锁过期时间
- 脚本:`if redis.call('get', key) == value then return redis.call('expire', key, expire)`
**为什么用Lua**:
- Redis执行Lua脚本是原子的,不会有竞态条件
- 网络开销小,一次网络往返执行多个命令
- 逻辑都在服务端执行,更可靠
更多推荐
所有评论(0)