Bootstrap

【JAVA架构师成长之路】【Redis】第3集:Redis分布式锁原理与案例


0-3分钟:课程目标与引入

目标
通过本课程,将掌握:

  1. Redis分布式锁的核心原理:理解SETNXRedisson等实现方式及其适用场景。
  2. 锁的安全性与可靠性:解决锁误删、死锁、锁续期等问题,确保高并发下的资源安全。
  3. 典型应用案例:通过秒杀库存扣减场景,实践分布式锁的完整流程。

实际意义
分布式锁是解决多节点、多线程资源竞争问题的关键技术,适用于秒杀、订单处理、数据一致性保障等高并发场景。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_segment1stock:1001_segment2),降低锁竞争。
2. 高可用方案
  • RedLock算法:在Redis集群模式下,需向多数节点获取锁(需权衡一致性与性能)。
  • 争议点:Redis作者与分布式系统专家对RedLock的争议(推荐优先使用单节点锁+故障转移)。

28-30分钟:总结与练习

课程总结

  • 核心原则
    • 原子性:加锁、解锁操作必须原子(Lua脚本或Redisson)。
    • 容错性:锁自动释放(过期时间)与客户端唯一标识。
  • 选型建议:优先使用Redisson,避免手动实现锁的复杂性。

练习题

  1. 基础实现:使用SETNX和Lua脚本实现一个简单的分布式锁,并测试多线程并发场景。
  2. Redisson实践:在Spring Boot项目中集成Redisson,为订单创建接口添加分布式锁。
  3. 问题复现:故意移除锁的过期时间,模拟死锁场景,观察系统行为。

拓展学习推荐

  1. 官方文档
  2. 书籍:《数据密集型应用系统设计》第9章(分布式事务与锁)。
  3. 高级主题
    • 对比ZooKeeper与Redis的分布式锁优缺点。
    • 研究Seata框架的AT模式如何解决分布式事务。

通过本课程,可深入理解Redis分布式锁的实现细节,并具备在高并发场景下保障数据一致性的实战能力。

;