0-3分钟:课程目标与引入
目标
通过本课程,将掌握:
- Redis分布式锁的核心原理:理解
SETNX
、Redisson
等实现方式及其适用场景。 - 锁的安全性与可靠性:解决锁误删、死锁、锁续期等问题,确保高并发下的资源安全。
- 典型应用案例:通过秒杀库存扣减场景,实践分布式锁的完整流程。
实际意义
分布式锁是解决多节点、多线程资源竞争问题的关键技术,适用于秒杀、订单处理、数据一致性保障等高并发场景。Redis因其高性能和原子性操作,成为实现分布式锁的主流方案。
3-15分钟:Redis分布式锁原理详解
1. 基于SETNX的简单锁
- 实现逻辑:
- 加锁:
SET key unique_value NX EX 30
(原子性设置键值并设置过期时间)。 - 解锁:通过Lua脚本验证锁归属后删除(避免误删他人锁)。
- 加锁:
- 代码示例:
// 加锁 Boolean locked = redisTemplate.opsForValue() .setIfAbsent("lock:order_123", "client1", 30, TimeUnit.SECONDS); // 解锁(Lua脚本) String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Collections.singletonList("lock:order_123"), "client1");
- 缺陷:
- 锁续期困难(需额外线程续期)。
- 非可重入锁(同一线程重复获取需特殊处理)。
2. Redisson分布式锁
- 核心机制:
- 看门狗(Watchdog):后台线程自动续期锁(默认30秒续期至1/3时间)。
- 可重入锁:支持同一线程多次加锁,通过计数器实现。
- 代码示例:
RLock lock = redissonClient.getLock("lock:order_123"); try { if (lock.tryLock(10, 30, TimeUnit.SECONDS)) { // 等待10秒,锁持有30秒 // 执行业务逻辑 } } finally { lock.unlock(); }
15-25分钟:典型应用案例——秒杀库存扣减
1. 场景分析
- 问题:高并发下超卖(库存扣减至负数)。
- 解决思路:通过分布式锁确保扣减操作的原子性。
2. 代码实现
- 库存服务类:
@Service public class StockService { @Autowired private RedissonClient redissonClient; @Autowired private StringRedisTemplate redisTemplate; public boolean deductStock(String productId) { RLock lock = redissonClient.getLock("lock:stock:" + productId); try { if (lock.tryLock(5, 30, TimeUnit.SECONDS)) { int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock:" + productId)); if (stock > 0) { redisTemplate.opsForValue().decrement("stock:" + productId); return true; } } return false; } finally { lock.unlock(); } } }
3. 测试验证
- 使用JMeter模拟并发请求:
- 初始库存100,模拟1000个并发请求,验证最终库存是否为0。
- 观察日志是否出现超卖或死锁问题。
25-28分钟:优化与问题解决方案
1. 锁的细粒度优化
- 分段锁:将库存拆分为多个段(如
stock:1001_segment1
、stock:1001_segment2
),降低锁竞争。
2. 高可用方案
- RedLock算法:在Redis集群模式下,需向多数节点获取锁(需权衡一致性与性能)。
- 争议点:Redis作者与分布式系统专家对RedLock的争议(推荐优先使用单节点锁+故障转移)。
28-30分钟:总结与练习
课程总结
- 核心原则:
- 原子性:加锁、解锁操作必须原子(Lua脚本或Redisson)。
- 容错性:锁自动释放(过期时间)与客户端唯一标识。
- 选型建议:优先使用Redisson,避免手动实现锁的复杂性。
练习题
- 基础实现:使用
SETNX
和Lua脚本实现一个简单的分布式锁,并测试多线程并发场景。 - Redisson实践:在Spring Boot项目中集成Redisson,为订单创建接口添加分布式锁。
- 问题复现:故意移除锁的过期时间,模拟死锁场景,观察系统行为。
拓展学习推荐
- 官方文档:
- 书籍:《数据密集型应用系统设计》第9章(分布式事务与锁)。
- 高级主题:
- 对比ZooKeeper与Redis的分布式锁优缺点。
- 研究Seata框架的AT模式如何解决分布式事务。
通过本课程,可深入理解Redis分布式锁的实现细节,并具备在高并发场景下保障数据一致性的实战能力。