一、分布式锁核心原理深度解析

1.1 分布式锁的本质需求

并发请求
共享资源
库存数据
订单创建
账户余额
超卖风险
重复下单
超额扣款

1.2 Redis分布式锁实现原理

// 加锁核心逻辑
SET lock_key unique_value NX PX 30000

// 解锁安全操作
if redis.call('get', KEYS[1]) == ARGV[1] then
    return redis.call('del', KEYS[1])
else
    return 0
end

1.3 Redisson分布式锁优势

特性 原生Redis实现 Redisson实现 优势说明
锁续期 手动实现 自动看门狗 避免业务未完成锁过期
可重入 不支持 支持 同一线程可多次加锁
公平锁 不支持 支持 按请求顺序获取锁
红锁 复杂实现 内置支持 多节点容错
锁状态 需额外实现 完善API 监控更方便

1.4 锁类型选择矩阵

场景 推荐锁类型 原因
抢购活动 非公平锁 性能优先
订单支付 公平锁 防止资源抢占
库存扣减 可重入锁 支持嵌套调用
金融交易 红锁 最高安全性
数据迁移 读写锁 读写分离

二、环境搭建与深度配置

2.1 完整依赖配置

<dependencies>
    <!-- Spring Boot Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
    <!-- Redisson -->
    <dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson-spring-boot-starter</artifactId>
        <version>3.24.3</version>
    </dependency>
    
    <!-- 连接池 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>
    
    <!-- 监控 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
    </dependency>
</dependencies>

2.2 高级Redisson配置

spring:
  redis:
    host: redis-cluster.example.com
    port: 6379
    password: securePassword123!
    database: 0
    lettuce:
      pool:
        max-active: 100
        max-idle: 50
        min-idle: 10
        max-wait: 3000

redisson:
  config: |
    clusterServersConfig:
      nodeAddresses:
        - "redis://redis-node1:6379"
        - "redis://redis-node2:6379"
        - "redis://redis-node3:6379"
      scanInterval: 2000 # 集群状态扫描间隔
      slaveConnectionMinimumIdleSize: 24
      slaveConnectionPoolSize: 64
      masterConnectionMinimumIdleSize: 24
      masterConnectionPoolSize: 64
      readMode: "SLAVE" # 读写分离
      subscriptionConnectionMinimumIdleSize: 1
      subscriptionConnectionPoolSize: 50
    threads: 16
    nettyThreads: 32
    transportMode: "EPOLL" # Linux高性能模式
    lockWatchdogTimeout: 30000 # 看门狗超时时间
    useScriptCache: true # 启用脚本缓存

2.3 多环境配置策略

@Configuration
public class RedissonConfig {

    @Bean(destroyMethod = "shutdown")
    public RedissonClient redissonClient(
        @Value("${spring.redis.host}") String host,
        @Value("${spring.redis.port}") int port,
        @Value("${spring.redis.password}") String password,
        @Value("${spring.profiles.active}") String profile) {
        
        Config config = new Config();
        
        if ("prod".equals(profile)) {
            // 生产环境集群配置
            config.useClusterServers()
                .addNodeAddress("redis://" + host + ":" + port)
                .setPassword(password)
                .setPingConnectionInterval(1000);
        } else {
            // 开发环境单机配置
            config.useSingleServer()
                .setAddress("redis://" + host + ":" + port)
                .setPassword(password)
                .setConnectionPoolSize(64);
        }
        
        return Redisson.create(config);
    }
}

三、分布式锁工具类深度封装

3.1 高级锁工具类

@Component
@Slf4j
public class DistributedLockUtil {

    private final RedissonClient redissonClient;
    private final MeterRegistry meterRegistry;

    public DistributedLockUtil(RedissonClient redissonClient, MeterRegistry meterRegistry) {
        this.redissonClient = redissonClient;
        this.meterRegistry = meterRegistry;
    }

    /**
     * 基础锁操作
     */
    public <T> T executeWithLock(String lockKey, int waitTime, int leaseTime, 
                                TimeUnit unit, Supplier<T> supplier) {
        RLock lock = redissonClient.getLock(lockKey);
        boolean locked = false;
        Timer.Sample timer = Timer.start(meterRegistry);
        
        try {
            // 尝试获取锁
            locked = lock.tryLock(waitTime, leaseTime, unit);
            
            if (locked) {
                // 记录锁等待时间
                meterRegistry.timer("distributed.lock.wait")
                    .record(System.nanoTime() - timer.startTime(), TimeUnit.NANOSECONDS);
                
                // 执行业务逻辑
                return supplier.get();
            } else {
                // 锁获取失败
                meterRegistry.counter("distributed.lock.fail", "lockKey", lockKey).increment();
                throw new LockAcquisitionException("获取锁失败");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new LockAcquisitionException("锁获取被中断", e);
        } finally {
            if (locked && lock.isHeldByCurrentThread()) {
                try {
                    lock.unlock();
                    meterRegistry.counter("distributed.lock.success").increment();
                } catch (IllegalMonitorStateException e) {
                    log.warn("锁状态异常,可能已自动释放", e);
                }
            }
        }
    }

    /**
     * 可重入锁
     */
    public <T> T executeWithReentrantLock(String lockKey, Supplier<T> supplier) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock();
        try {
            return supplier.get();
        } finally {
            if (lock.isHeldByCurrentThread() && lock.getHoldCount() > 0) {
                lock.unlock();
            }
        }
    }

    /**
     * 公平锁
     */
    public <T> T executeWithFairLock(String lockKey, int waitTime, Supplier<T> supplier) {
        RLock lock = redissonClient.getFairLock(lockKey);
        try {
            if (lock.tryLock(waitTime, -1, TimeUnit.SECONDS)) {
                return supplier.get();
            }
            throw new LockAcquisitionException("获取公平锁失败");
        } catch (InterruptedException e) {
            throw new LockAcquisitionException("锁获取被中断", e);
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 读写锁
     */
    public <T> T executeWithReadLock(String lockKey, Supplier<T> supplier) {
        RReadWriteLock rwLock = redissonClient.getReadWriteLock(lockKey);
        RLock lock = rwLock.readLock();
        lock.lock();
        try {
            return supplier.get();
        } finally {
            lock.unlock();
        }
    }

    public void executeWithWriteLock(String lockKey, Runnable runnable) {
        RReadWriteLock rwLock = redissonClient.getReadWriteLock(lockKey);
        RLock lock = rwLock.writeLock();
        lock.lock();
        try {
            runnable.run();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 红锁
     */
    public <T> T executeWithRedLock(String lockKey, int waitTime, Supplier<T> supplier) {
        RLock lock1 = redissonClient.getLock(lockKey + "_node1");
        RLock lock2 = redissonClient.getLock(lockKey + "_node2");
        RLock lock3 = redissonClient.getLock(lockKey + "_node3");
        RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
        
        try {
            if (redLock.tryLock(waitTime, -1, TimeUnit.SECONDS)) {
                return supplier.get();
            }
            throw new LockAcquisitionException("获取红锁失败");
        } catch (InterruptedException e) {
            throw new LockAcquisitionException("锁获取被中断", e);
        } finally {
            redLock.unlock();
        }
    }
}

3.2 自定义锁异常体系

public class LockAcquisitionException extends RuntimeException {
    public LockAcquisitionException(String message) {
        super(message);
    }

    public LockAcquisitionException(String message, Throwable cause) {
        super(message, cause);
    }
}

public class LockOperationException extends RuntimeException {
    public LockOperationException(String message) {
        super(message);
    }
}

四、库存防超卖深度实现

4.1 库存服务接口设计

public interface InventoryService {
    /**
     * 扣减库存
     * @param productId 商品ID
     * @param quantity 扣减数量
     * @return 是否成功
     */
    boolean reduceInventory(Long productId, int quantity);
    
    /**
     * 获取商品库存
     * @param productId 商品ID
     * @return 库存数量
     */
    int getInventory(Long productId);
    
    /**
     * 预占库存
     * @param productId 商品ID
     * @param quantity 预占数量
     * @param expireSeconds 预占过期时间
     * @return 预占令牌
     */
    String reserveInventory(Long productId, int quantity, long expireSeconds);
    
    /**
     * 确认预占库存
     * @param reserveToken 预占令牌
     * @return 是否成功
     */
    boolean confirmReserve(String reserveToken);
    
    /**
     * 取消预占库存
     * @param reserveToken 预占令牌
     */
    void cancelReserve(String reserveToken);
}

4.2 Redis库存服务实现

@Service
@Slf4j
public class RedisInventoryServiceImpl implements InventoryService {

    private final RedisTemplate<String, Integer> redisTemplate;
    private final DistributedLockUtil lockUtil;
    private final RedissonClient redissonClient;
    private final InventoryRepository inventoryRepository;

    // 库存Key前缀
    private static final String INVENTORY_KEY = "inventory:";
    // 预占库存Key前缀
    private static final String RESERVE_KEY = "inventory_reserve:";
    // 预占令牌Key前缀
    private static final String RESERVE_TOKEN_KEY = "reserve_token:";

    @Override
    public boolean reduceInventory(Long productId, int quantity) {
        String lockKey = "lock:inventory:" + productId;
        
        return lockUtil.executeWithLock(lockKey, 3, 30, TimeUnit.SECONDS, () -> {
            String key = INVENTORY_KEY + productId;
            Integer current = redisTemplate.opsForValue().get(key);
            
            // 缓存未命中,从数据库加载
            if (current == null) {
                current = loadInventoryFromDB(productId);
                redisTemplate.opsForValue().set(key, current);
            }
            
            // 库存不足
            if (current < quantity) {
                log.warn("库存不足: productId={}, current={}, required={}", productId, current, quantity);
                return false;
            }
            
            // 扣减库存
            redisTemplate.opsForValue().decrement(key, quantity);
            
            // 异步更新数据库
            CompletableFuture.runAsync(() -> 
                inventoryRepository.reduceInventory(productId, quantity));
            
            return true;
        });
    }

    @Override
    public String reserveInventory(Long productId, int quantity, long expireSeconds) {
        String lockKey = "lock:inventory_reserve:" + productId;
        String reserveToken = UUID.randomUUID().toString();
        
        boolean success = lockUtil.executeWithLock(lockKey, 3, 30, TimeUnit.SECONDS, () -> {
            String key = INVENTORY_KEY + productId;
            Integer current = redisTemplate.opsForValue().get(key);
            
            if (current == null) {
                current = loadInventoryFromDB(productId);
                redisTemplate.opsForValue().set(key, current);
            }
            
            if (current < quantity) {
                return false;
            }
            
            // 预占库存
            redisTemplate.opsForValue().decrement(key, quantity);
            
            // 记录预占信息
            String reserveKey = RESERVE_KEY + reserveToken;
            Map<String, Object> reserveInfo = new HashMap<>();
            reserveInfo.put("productId", productId);
            reserveInfo.put("quantity", quantity);
            reserveInfo.put("expireAt", System.currentTimeMillis() + expireSeconds * 1000);
            
            redisTemplate.opsForHash().putAll(reserveKey, reserveInfo);
            redisTemplate.expire(reserveKey, expireSeconds + 60, TimeUnit.SECONDS);
            
            // 记录令牌映射
            redisTemplate.opsForValue().set(RESERVE_TOKEN_KEY + reserveToken, reserveKey, 
                expireSeconds + 60, TimeUnit.SECONDS);
            
            return true;
        });
        
        return success ? reserveToken : null;
    }

    @Override
    public boolean confirmReserve(String reserveToken) {
        String tokenKey = RESERVE_TOKEN_KEY + reserveToken;
        String reserveKey = (String) redisTemplate.opsForValue().get(tokenKey);
        
        if (reserveKey == null) {
            throw new InventoryException("预占记录不存在或已过期");
        }
        
        Map<Object, Object> reserveInfo = redisTemplate.opsForHash().entries(reserveKey);
        if (reserveInfo.isEmpty()) {
            throw new InventoryException("预占记录不存在");
        }
        
        Long productId = Long.parseLong(reserveInfo.get("productId").toString());
        int quantity = Integer.parseInt(reserveInfo.get("quantity").toString());
        
        // 删除预占记录
        redisTemplate.delete(reserveKey);
        redisTemplate.delete(tokenKey);
        
        // 异步创建订单
        CompletableFuture.runAsync(() -> 
            orderService.createOrderFromReserve(productId, quantity, reserveToken));
        
        return true;
    }

    @Override
    public void cancelReserve(String reserveToken) {
        String tokenKey = RESERVE_TOKEN_KEY + reserveToken;
        String reserveKey = (String) redisTemplate.opsForValue().get(tokenKey);
        
        if (reserveKey == null) {
            log.warn("预占记录不存在: token={}", reserveToken);
            return;
        }
        
        Map<Object, Object> reserveInfo = redisTemplate.opsForHash().entries(reserveKey);
        if (reserveInfo.isEmpty()) {
            log.warn("预占记录已失效: token={}", reserveToken);
            return;
        }
        
        Long productId = Long.parseLong(reserveInfo.get("productId").toString());
        int quantity = Integer.parseInt(reserveInfo.get("quantity").toString());
        
        // 归还库存
        String inventoryKey = INVENTORY_KEY + productId;
        redisTemplate.opsForValue().increment(inventoryKey, quantity);
        
        // 删除记录
        redisTemplate.delete(reserveKey);
        redisTemplate.delete(tokenKey);
    }
    
    // 定时清理过期预占
    @Scheduled(fixedRate = 60000)
    public void cleanExpiredReserves() {
        Set<String> keys = redisTemplate.keys(RESERVE_KEY + "*");
        long now = System.currentTimeMillis();
        
        for (String key : keys) {
            Long expireAt = (Long) redisTemplate.opsForHash().get(key, "expireAt");
            if (expireAt != null && expireAt < now) {
                // 自动取消过期预占
                String token = key.substring(RESERVE_KEY.length());
                cancelReserve(token);
            }
        }
    }
}

4.3 库存防超卖策略对比

策略 实现复杂度 性能 适用场景 缺点
悲观锁 低并发场景 高并发下性能差
乐观锁 冲突较少场景 重试逻辑复杂
分布式锁 高并发场景 实现复杂
预占库存 极高 秒杀场景 状态管理复杂
队列削峰 极高 极端高并发 延迟较高

五、抢单业务深度实现

5.1 抢单服务核心逻辑

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    private final InventoryService inventoryService;
    private final DistributedLockUtil lockUtil;
    private final OrderRepository orderRepository;
    private final IdGenerator idGenerator;
    private final RateLimiter rateLimiter;

    /**
     * 普通抢单(分布式锁版)
     */
    @Override
    public Order createOrder(Long userId, Long productId, int quantity) {
        // 限流保护
        if (!rateLimiter.tryAcquire()) {
            throw new RateLimitException("系统繁忙,请稍后再试");
        }
        
        String lockKey = "order:create:" + userId + ":" + productId;
        
        return lockUtil.executeWithLock(lockKey, 2, 10, TimeUnit.SECONDS, () -> {
            // 检查是否重复下单
            if (orderRepository.existsByUserIdAndProductId(userId, productId)) {
                throw new OrderException("请勿重复下单");
            }
            
            // 扣减库存
            if (!inventoryService.reduceInventory(productId, quantity)) {
                throw new InventoryException("库存不足");
            }
            
            // 创建订单
            Order order = new Order();
            order.setId(idGenerator.nextId());
            order.setUserId(userId);
            order.setProductId(productId);
            order.setQuantity(quantity);
            order.setStatus(OrderStatus.CREATED);
            
            orderRepository.save(order);
            
            // 发送订单创建事件
            eventPublisher.publishEvent(new OrderCreatedEvent(order));
            
            return order;
        });
    }

    /**
     * 预占库存抢单(高性能版)
     */
    @Override
    public Order fastCreateOrder(Long userId, Long productId, int quantity) {
        // 限流保护
        if (!rateLimiter.tryAcquire()) {
            throw new RateLimitException("系统繁忙,请稍后再试");
        }
        
        // 预占库存(15分钟有效期)
        String reserveToken = inventoryService.reserveInventory(productId, quantity, 900);
        if (reserveToken == null) {
            throw new InventoryException("库存不足");
        }
        
        try {
            // 创建订单
            Order order = new Order();
            order.setId(idGenerator.nextId());
            order.setUserId(userId);
            order.setProductId(productId);
            order.setQuantity(quantity);
            order.setStatus(OrderStatus.PENDING);
            order.setReserveToken(reserveToken);
            
            orderRepository.save(order);
            
            // 异步确认预占
            CompletableFuture.runAsync(() -> 
                inventoryService.confirmReserve(reserveToken));
            
            return order;
        } catch (Exception e) {
            // 创建失败时取消预占
            inventoryService.cancelReserve(reserveToken);
            throw e;
        }
    }

    /**
     * 订单支付完成回调
     */
    @Override
    @Transactional
    public void confirmOrder(Long orderId) {
        Order order = orderRepository.findById(orderId)
            .orElseThrow(() -> new OrderException("订单不存在"));
        
        if (order.getStatus() != OrderStatus.PENDING) {
            throw new OrderException("订单状态异常");
        }
        
        // 确认预占库存
        if (order.getReserveToken() != null) {
            inventoryService.confirmReserve(order.getReserveToken());
        }
        
        // 更新订单状态
        order.setStatus(OrderStatus.COMPLETED);
        orderRepository.save(order);
        
        // 发送订单完成事件
        eventPublisher.publishEvent(new OrderCompletedEvent(order));
    }
}

5.2 幂等性处理设计

@Aspect
@Component
@Slf4j
public class IdempotentAspect {

    private final RedissonClient redissonClient;
    private final RedisTemplate<String, String> redisTemplate;

    @Around("@annotation(idempotent)")
    public Object around(ProceedingJoinPoint joinPoint, Idempotent idempotent) throws Throwable {
        // 获取幂等键
        String idempotentKey = generateIdempotentKey(joinPoint, idempotent);
        
        // 使用分布式锁保证原子性
        RLock lock = redissonClient.getLock("lock:idempotent:" + idempotentKey);
        lock.lock();
        
        try {
            // 检查是否已处理
            if (redisTemplate.hasKey(idempotentKey)) {
                throw new IdempotentException("重复请求");
            }
            
            // 执行业务逻辑
            Object result = joinPoint.proceed();
            
            // 记录幂等键(有效期根据注解设置)
            redisTemplate.opsForValue().set(
                idempotentKey, 
                "processed", 
                idempotent.expireTime(), 
                TimeUnit.SECONDS
            );
            
            return result;
        } finally {
            lock.unlock();
        }
    }
    
    private String generateIdempotentKey(ProceedingJoinPoint joinPoint, Idempotent idempotent) {
        // 根据方法参数生成唯一键
        // 实现略...
    }
}

// 使用示例
@PostMapping("/create")
@Idempotent(key = "#userId + ':' + #productId", expireTime = 3600)
public Order createOrder(@RequestParam Long userId, @RequestParam Long productId) {
    // 业务逻辑
}

六、Redisson高级特性深度应用

6.1 看门狗机制原理

Client Redisson Redis 获取锁(不指定leaseTime) SET lock_key unique_id NX PX 30000 成功 返回成功 PEXPIRE lock_key 30000 成功 loop [每10秒执行] 释放锁 DEL lock_key 成功 释放成功 Client Redisson Redis

6.2 红锁(RedLock)算法实现

public boolean tryRedLock(String lockKey, int waitTime, int leaseTime) {
    RLock lock1 = redissonClient.getLock(lockKey + "_node1");
    RLock lock2 = redissonClient.getLock(lockKey + "_node2");
    RLock lock3 = redissonClient.getLock(lockKey + "_node3");
    RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
    
    try {
        // 尝试获取锁
        boolean acquired = redLock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
        
        if (acquired) {
            // 检查是否在多数节点上获取成功
            int acquiredNodes = 0;
            if (lock1.isHeldByCurrentThread()) acquiredNodes++;
            if (lock2.isHeldByCurrentThread()) acquiredNodes++;
            if (lock3.isHeldByCurrentThread()) acquiredNodes++;
            
            return acquiredNodes >= 2; // 多数原则
        }
        return false;
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        return false;
    }
}

6.3 联锁(MultiLock)应用场景

public void transferInventory(Long fromProductId, Long toProductId, int quantity) {
    RLock lock1 = redissonClient.getLock("inventory:" + fromProductId);
    RLock lock2 = redissonClient.getLock("inventory:" + toProductId);
    RLock multiLock = redissonClient.getMultiLock(lock1, lock2);
    
    multiLock.lock();
    try {
        // 减少源商品库存
        inventoryService.reduceInventory(fromProductId, quantity);
        
        // 增加目标商品库存
        inventoryService.increaseInventory(toProductId, quantity);
    } finally {
        multiLock.unlock();
    }
}

七、性能优化与防死锁深度策略

7.1 锁粒度优化方案

// 全局锁(不推荐)
RLock globalLock = redissonClient.getLock("global_inventory_lock");

// 商品级锁(推荐)
RLock productLock = redissonClient.getLock("inventory_lock:" + productId);

// 库存分段锁(超高并发优化)
public boolean reduceInventorySegment(Long productId, int quantity) {
    // 将库存分成32段
    int segment = (int) (productId % 32);
    String lockKey = "inventory_segment_lock:" + segment;
    
    return lockUtil.executeWithLock(lockKey, 3, 10, TimeUnit.SECONDS, () -> {
        // 操作分段库存
        // ...
    });
}

7.2 死锁检测与预防

// 死锁检测定时任务
@Scheduled(fixedRate = 60000)
public void detectDeadLocks() {
    // 获取所有活跃锁
    Set<String> lockKeys = redissonClient.getKeys().getKeysByPattern("lock:*");
    
    for (String lockKey : lockKeys) {
        RLock lock = redissonClient.getLock(lockKey);
        
        // 检查锁持有时间
        long holdTime = lock.remainTimeToLive();
        if (holdTime == -1) { // 看门狗持有的锁
            long heldTime = System.currentTimeMillis() - lock.getLockHoldTime();
            if (heldTime > 300000) { // 超过5分钟
                log.warn("锁持有时间过长: {}, heldTime={}ms", lockKey, heldTime);
                // 发送告警通知
                alertService.sendLockAlert(lockKey, heldTime);
            }
        } else if (holdTime > 60000) { // 非看门狗锁
            log.warn("锁可能未被释放: {}, remainTime={}ms", lockKey, holdTime);
        }
    }
}

// 锁超时自动释放
public <T> T executeWithTimeoutLock(String lockKey, int waitTime, int maxHoldTime, Supplier<T> supplier) {
    RLock lock = redissonClient.getLock(lockKey);
    boolean locked = false;
    
    try {
        locked = lock.tryLock(waitTime, maxHoldTime, TimeUnit.MILLISECONDS);
        if (locked) {
            return supplier.get();
        }
        throw new LockAcquisitionException("获取锁失败");
    } catch (InterruptedException e) {
        throw new LockAcquisitionException("锁获取被中断", e);
    } finally {
        if (locked && lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }
}

7.3 锁竞争监控指标

@Bean
public MeterRegistryCustomizer<MeterRegistry> lockMetrics(RedissonClient redissonClient) {
    return registry -> {
        Gauge.builder("redisson.lock.waiting_threads", () -> {
                int total = 0;
                Set<String> keys = redissonClient.getKeys().getKeysByPattern("lock:*");
                for (String key : keys) {
                    RLock lock = redissonClient.getLock(key);
                    total += lock.getQueueSize();
                }
                return total;
            })
            .description("等待锁的线程总数")
            .register(registry);
        
        Gauge.builder("redisson.lock.held_time.max", () -> {
                long max = 0;
                Set<String> keys = redissonClient.getKeys().getKeysByPattern("lock:*");
                for (String key : keys) {
                    RLock lock = redissonClient.getLock(key);
                    if (lock.isLocked()) {
                        long heldTime = System.currentTimeMillis() - lock.getLockHoldTime();
                        if (heldTime > max) max = heldTime;
                    }
                }
                return max;
            })
            .description("最长锁持有时间")
            .register(registry);
    };
}

八、压测对比与性能数据深度分析

8.1 JMeter压测配置

<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="高并发抢单测试">
  <intProp name="ThreadGroup.num_threads">1000</intProp>
  <intProp name="ThreadGroup.ramp_time">60</intProp>
  <longProp name="ThreadGroup.duration">600</longProp>
</ThreadGroup>

<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="创建订单请求">
  <elementProp name="HTTPsampler.Arguments" elementType="Arguments">
    <collectionProp name="Arguments.arguments">
      <elementProp name="userId" elementType="HTTPArgument">
        <stringProp name="Argument.value">${__Random(1,10000)}</stringProp>
      </elementProp>
      <elementProp name="productId" elementType="HTTPArgument">
        <stringProp name="Argument.value">1001</stringProp>
      </elementProp>
    </collectionProp>
  </elementProp>
  <stringProp name="HTTPSampler.domain">api.example.com</stringProp>
  <stringProp name="HTTPSampler.port">443</stringProp>
  <stringProp name="HTTPSampler.protocol">https</stringProp>
  <stringProp name="HTTPSampler.path">/order/create</stringProp>
  <stringProp name="HTTPSampler.method">POST</stringProp>
</HTTPSamplerProxy>

8.2 压测结果对比分析

指标 无锁方案 简单锁 分段锁 预占模式
QPS 12,500 8,200 18,300 23,500
平均响应时间 45ms 68ms 32ms 25ms
P99响应时间 210ms 350ms 150ms 95ms
库存准确性 严重超卖 100% 100% 100%
CPU使用率 95% 85% 75% 65%
Redis负载 12% 45% 68% 82%

8.3 性能瓶颈分析

客户端请求
Nginx负载均衡
应用服务器1
应用服务器2
应用服务器3
Redis分布式锁
Redis集群

瓶颈点分析:

  1. Redis集群成为性能瓶颈(82%负载)
  2. 分布式锁竞争导致线程阻塞
  3. 网络延迟影响锁获取速度
    优化方案:
  4. Redis集群横向扩展(增加分片)
  5. 采用分段锁减少竞争
  6. 使用本地缓存减少Redis访问
  7. 升级网络基础设施

九、生产环境最佳实践

9.1 锁命名规范

// 格式:系统:模块:资源类型:资源ID
String lockKey = "order:inventory:product:" + productId;

// 示例:
// order:payment:account:12345
// user:profile:update:67890
// product:price:adjust:1001

9.2 异常处理模板

public void executeBusinessWithLock(String lockKey, Runnable businessLogic) {
    RLock lock = redissonClient.getLock(lockKey);
    boolean locked = false;
    
    try {
        // 尝试获取锁
        locked = lock.tryLock(3, 30, TimeUnit.SECONDS);
        
        if (locked) {
            // 执行业务逻辑
            businessLogic.run();
        } else {
            // 锁获取失败处理
            handleLockAcquisitionFailure(lockKey);
        }
    } catch (InterruptedException e) {
        // 线程中断处理
        Thread.currentThread().interrupt();
        handleInterruptedException(e);
    } catch (Exception e) {
        // 业务异常处理
        handleBusinessException(e);
    } finally {
        if (locked) {
            try {
                // 双重检查锁状态
                if (lock.isHeldByCurrentThread() && lock.isLocked()) {
                    lock.unlock();
                }
            } catch (IllegalMonitorStateException e) {
                // 锁状态异常处理
                log.error("锁释放异常: {}", lockKey, e);
            }
        }
    }
}

9.3 监控告警配置

# Prometheus告警规则
groups:
- name: lock_alerts
  rules:
  - alert: HighLockContention
    expr: redisson_lock_waiting_threads > 50
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "高锁竞争警告"
      description: "系统锁竞争激烈,当前等待线程数: {{ $value }}"
  
  - alert: LongHoldingLock
    expr: redisson_lock_held_time_max > 300000
    for: 2m
    labels:
      severity: critical
    annotations:
      summary: "锁持有时间过长"
      description: "锁 {{ $labels.lock_name }} 持有时间超过5分钟"
  
  - alert: LockAcquisitionFailure
    expr: increase(distributed_lock_fail_total[5m]) > 100
    labels:
      severity: warning
    annotations:
      summary: "锁获取频繁失败"
      description: "5分钟内锁获取失败次数: {{ $value }}"

十、常见问题深度解决方案

10.1 锁超时问题解决方案

// 解决方案1:启用看门狗
lock.tryLock(3, -1, TimeUnit.SECONDS);

// 解决方案2:动态调整超时时间
long estimatedTime = estimateBusinessTime(); // 预估业务执行时间
lock.tryLock(3, estimatedTime * 2, TimeUnit.MILLISECONDS);

// 解决方案3:锁续期线程
private void startLockRenewal(RLock lock, long leaseTime) {
    ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
    scheduler.scheduleAtFixedRate(() -> {
        if (lock.isHeldByCurrentThread()) {
            lock.expire(leaseTime, TimeUnit.MILLISECONDS);
        }
    }, leaseTime / 3, leaseTime / 3, TimeUnit.MILLISECONDS);
}

10.2 锁释放问题解决方案

// 解决方案1:finally块中释放
finally {
    if (lock.isHeldByCurrentThread()) {
        lock.unlock();
    }
}

// 解决方案2:锁释放监听器
lock.lock();
lock.lockAsync().thenAccept(locked -> {
    try {
        // 业务逻辑
    } finally {
        lock.unlockAsync();
    }
});

// 解决方案3:自动释放模板
public <T> T executeWithAutoRelease(RLock lock, Supplier<T> supplier) {
    lock.lock();
    try {
        return supplier.get();
    } finally {
        if (lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }
}

10.3 锁竞争优化方案

// 方案1:锁分段
public class SegmentLock {
    private final RLock[] segments;
    
    public SegmentLock(int segmentCount, RedissonClient redissonClient) {
        segments = new RLock[segmentCount];
        for (int i = 0; i < segmentCount; i++) {
            segments[i] = redissonClient.getLock("segment_lock_" + i);
        }
    }
    
    public void execute(String key, Runnable action) {
        int segment = Math.abs(key.hashCode()) % segments.length;
        segments[segment].lock();
        try {
            action.run();
        } finally {
            segments[segment].unlock();
        }
    }
}

// 方案2:锁合并
public class CompositeLock {
    private final RLock lock1;
    private final RLock lock2;
    
    public CompositeLock(RedissonClient redissonClient, String key1, String key2) {
        lock1 = redissonClient.getLock(key1);
        lock2 = redissonClient.getLock(key2);
    }
    
    public void execute(Runnable action) {
        boolean locked1 = false;
        boolean locked2 = false;
        
        try {
            locked1 = lock1.tryLock(3, TimeUnit.SECONDS);
            locked2 = lock2.tryLock(3, TimeUnit.SECONDS);
            
            if (locked1 && locked2) {
                action.run();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            if (locked1) lock1.unlock();
            if (locked2) lock2.unlock();
        }
    }
}

10.4 Redis集群故障处理

// 故障转移配置
config.useClusterServers()
    .setScanInterval(2000)
    .setSlaveConnectionMinimumIdleSize(24)
    .setSlaveConnectionPoolSize(48)
    .setMasterConnectionMinimumIdleSize(24)
    .setMasterConnectionPoolSize(48)
    .setFailedSlaveReconnectionInterval(30000)
    .setFailedSlaveCheckInterval(60000);

// 集群状态监听
redissonClient.getClusterNodesGroup().addConnectionListener(new ConnectionListener() {
    @Override
    public void onConnect(InetSocketAddress addr) {
        log.info("节点连接成功: {}", addr);
    }
    
    @Override
    public void onDisconnect(InetSocketAddress addr) {
        log.warn("节点断开连接: {}", addr);
        alertService.sendNodeDownAlert(addr);
    }
});

总结与最佳实践

11.1 技术选型建议

场景 推荐方案 理由
普通电商 分布式锁+缓存 平衡性能与准确性
秒杀系统 预占库存+队列 极致性能
金融交易 红锁+数据库锁 最高安全性
数据迁移 读写锁 读写分离
定时任务 全局锁 简单可靠

11.2 性能优化金字塔

基础优化
连接池配置
合理超时
网络优化
锁粒度控制
锁分段
预占模式
本地缓存
队列削峰

11.3 上线检查清单

  • 锁超时时间配置合理
  • 看门狗机制已启用
  • 锁粒度优化完成
  • 死锁检测机制就绪
  • 监控告警配置完成
  • 压测通过性能要求
  • 故障转移方案验证
  • 回滚方案准备就绪
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐