Redisson 分布式锁的公平性实现原理

在分布式系统中,公平锁确保多个客户端按请求顺序获取锁,避免饥饿现象。Redisson 通过 Redis 的 有序集合(Sorted Set)发布订阅(Pub/Sub) 机制实现公平锁,核心流程如下:

1. 请求排队机制
  • 当客户端申请锁时,在 Redis 中创建一个有序集合(如 lock_queue:{lockName}),每个客户端生成唯一标识(如 UUID:threadID)并插入集合: $$ \text{score} = \text{当前时间戳} + \text{随机微调值} $$
  • 客户端按 score 值升序排列,形成等待队列。
2. 锁获取逻辑
  • 客户端检查自身是否位于队列头部:
    // 伪代码:检查是否为第一个等待者
    if (redis.zrank("lock_queue:myLock", clientId) == 0) {
        // 尝试获取锁
        return tryAcquireLock();
    }
    

  • 若未轮到当前客户端,通过 Redis 的 subscribe 监听前一个节点的释放通知。
3. 锁释放与通知
  • 锁释放时删除当前节点,并触发事件:
    // 伪代码:释放锁并通知下一节点
    redis.zrem("lock_queue:myLock", currentClientId);
    redis.publish("channel:myLock", "UNLOCK");
    

  • 订阅该频道的下一个客户端收到通知后重试获取锁。
4. 超时与容错
  • 客户端设置超时时间(如 waitTime=10s),超时后放弃排队。
  • 通过 Lua 脚本保证原子性操作:
    -- 原子化检查队列位置和获取锁
    if redis.call('zrank', KEYS[1], ARGV[1]) == 0 then
        return redis.call('set', KEYS[2], ARGV[2], 'PX', ARGV[3]) 
    end
    return 0
    


Java 实现示例

import org.redisson.Redisson;
import org.redisson.api.RFairLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class FairLockDemo {
    public static void main(String[] args) throws InterruptedException {
        // 1. 配置 Redisson 客户端
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        RedissonClient client = Redisson.create(config);

        // 2. 获取公平锁实例
        RFairLock fairLock = client.getFairLock("orderLock");

        // 3. 尝试获取锁(等待20秒,锁持有10秒)
        if (fairLock.tryLock(20, 10, TimeUnit.SECONDS)) {
            try {
                System.out.println("【成功获取锁】执行关键业务...");
                Thread.sleep(3000); // 模拟业务处理
            } finally {
                fairLock.unlock();
                System.out.println("【释放锁】");
            }
        } else {
            System.out.println("获取锁超时");
        }

        client.shutdown();
    }
}

关键参数说明:
  • tryLock(waitTime, leaseTime, unit)
    • waitTime:排队等待的最长时间
    • leaseTime:锁自动释放时间(防止死锁)
  • 公平锁特性:
    • 按请求顺序分配锁
    • 避免优先级反转
    • 支持可重入(同一线程可多次加锁)

性能优化建议

  1. 减少网络开销
    • 使用 Lua 脚本合并多个 Redis 操作
  2. 超时策略
    • 根据业务场景调整 waitTimeleaseTime
  3. 监控队列长度
    • 定期检查有序集合大小,避免无限堆积
    long queueSize = fairLock.size(); // 获取等待队列长度
    

:公平锁比非公平锁性能略低(约 10%~15%),但适用于需要严格顺序的业务场景(如订单处理、资源调度)。

Logo

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

更多推荐