分布式锁实现方案对比与最佳实践

目录

  1. 分布式锁的应用场景
  2. 常见的锁实现方案
  3. Redisson实现分布式锁的最佳实践
  4. 方案对比与选择建议

分布式锁的应用场景

在分布式系统中,常常需要控制对共享资源的访问。典型的应用场景包括:

  1. 缓存击穿防护:防止大量请求同时查询数据库
  2. 库存扣减:确保商品库存操作的原子性
  3. 防重复提交:避免表单重复提交
  4. 定时任务互斥:确保定时任务只被一个节点执行

常见的锁实现方案

1. 本地锁 synchronized

public class LocalLockExample {
    
    
    public synchronized void doSomething() {
    
    
        // 业务逻辑
    }
}

特点:

  • 只能在单机环境下使用
  • JVM级别的锁
  • 无法解决分布式环境下的并发问题

2. 基于Redis的抢占式锁(SET NX + Lua)

public class RedisLockExample {
    
    
    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    
    /**
     * 尝试获取分布式锁
     */
    public boolean tryLock(String lockKey, String requestId, int expireTime) {
    
    
        String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, 
                                SET_WITH_EXPIRE_TIME, expireTime);
        return LOCK_SUCCESS.equals(result);
    }
    
    /**
     * 释放分布式锁
     */
    public boolean releaseLock(String lockKey, String requestId) {
    
    
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                       "return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey), 
                                 Collections.singletonList(requestId));
        return Long.valueOf(1L).equals(result);
    }
}

特点:

  • 使用Redis的原子操作实现
  • 需要自己处理锁的超时和续期
  • 可能存在锁超时被释放的问题

3. Redisson分布式锁

public class RedissonLockExample {
    
    
    private final RedissonClient redisson;
    
    public void doWithLock() {
    
    
        RLock lock = redisson.getLock("myLock");
        try {
    
    
            // 尝试加锁,最多等待30秒,锁定后10秒自动解锁
            boolean isLocked = lock.tryLock(30, 10, TimeUnit.SECONDS);
            if (isLocked) {
    
    
                // 业务逻辑
            }
        } catch (InterruptedException e) {
    
    
            Thread.currentThread().interrupt();
        } finally {
    
    
            lock.unlock();
        }
    }
}

特点:

  • 实现了可重入锁
  • 支持自动续期(看门狗机制)
  • 提供了丰富的锁类型(公平锁、读写锁等)
  • 实现了跨平台的分布式锁

Redisson实现分布式锁的最佳实践

双重检验机制 + Redisson锁

public class OptimizedRedissonLock {
    
    
    private final RedissonClient redisson;
    private final RedisTemplate<String, String> redisTemplate;
    
    public Map<String, Object> getDataWithLock() {
    
    
        // 第一次检查缓存
        String cacheData = redisTemplate.opsForValue().get("cacheKey");
        if (!StringUtils.isEmpty(cacheData)) {
    
    
            return JSON.parseObject(cacheData);
        }

        // 获取分布式锁
        RLock lock = redisson.getLock("myLock");
        try {
    
    
            boolean isLocked = lock.tryLock(30, TimeUnit.SECONDS);
            if (!isLocked) {
    
    
                throw new RuntimeException("获取锁失败");
            }
            
            // 第二次检查缓存
            cacheData = redisTemplate.opsForValue().get("cacheKey");
            if (!StringUtils.isEmpty(cacheData)) {
    
    
                return JSON.parseObject(cacheData);
            }
            
            // 查询数据库
            Map<String, Object> dbData = queryDatabase();
            
            // 放入缓存
            redisTemplate.opsForValue().set("cacheKey", 
                JSON.toJSONString(dbData), 1, TimeUnit.DAYS);
                
            return dbData;
        } catch (InterruptedException e) {
    
    
            Thread.currentThread().interrupt();
            throw new RuntimeException("获取锁被中断");
        } finally {
    
    
            if (lock.isHeldByCurrentThread()) {
    
    
                lock.unlock();
            }
        }
    }
}

看门狗机制说明

Redisson的看门狗机制是一个自动延期机制:

  1. 原理

    • 默认锁的有效期为30秒
    • 如果业务未完成,会自动延长锁的有效期
    • 每隔10秒(默认值)自动续期
  2. 配置方式

Config config = new Config();
config.setLockWatchdogTimeout(30000); // 设置看门狗超时时间,单位:毫秒

方案对比与选择建议

特性 synchronized Redis SET NX Redisson
实现难度 简单 中等 简单
分布式支持 不支持 支持 支持
可重入性 支持 需自行实现 支持
自动续期 不需要 需自行实现 支持
锁超时处理 不需要 需自行处理 自动处理
性能 中等 中等
可靠性 一般

选择建议

  1. 单机应用:使用synchronized即可

  2. 简单分布式场景

    • 性能要求不高
    • 锁定时间短
    • 可以使用Redis SET NX方案
  3. 复杂分布式场景

    • 需要可重入锁
    • 锁定时间不确定
    • 建议使用Redisson