分布式锁实现方案对比:Redis Redlock与Zookeeper互斥锁原理与代码实践

分布式锁是微服务架构中保证跨进程互斥访问的核心机制。当多个服务实例同时操作共享资源(库存扣减、订单去重、定时任务防重执行)时,本地锁无法跨进程生效。Redis和Zookeeper是两种主流的分布式锁实现方案,在一致性保证、性能特性和故障处理上各有取舍。本文通过代码实现对比两种方案的原理与适用场景。

Redis分布式锁:SET NX EX与Lua脚本解锁

Redis单实例分布式锁基于SET key value NX EX timeout命令,NX保证互斥(Key不存在才设置),EX设置过期时间防止死锁:

// Redis单实例分布式锁
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;
import java.util.UUID;

public class RedisDistributedLock {
    private final Jedis jedis;
    private static final String LOCK_PREFIX = "lock:";
    private static final int LOCK_EXPIRE = 30; // 锁过期时间(秒)

    public RedisDistributedLock(Jedis jedis) {
        this.jedis = jedis;
    }

    public String tryLock(String lockKey, String requestId) {
        String value = UUID.randomUUID().toString();
        SetParams params = SetParams.setParams().nx().ex(LOCK_EXPIRE);
        String result = jedis.set(LOCK_PREFIX + lockKey, value, params);
        return "OK".equals(result) ? value : null;
    }

    public boolean unlock(String lockKey, String requestId) {
        // 使用Lua脚本保证"判断+删除"原子性
        String luaScript = 
            "if redis.call('get', KEYS[1]) == ARGV[1] then " +
            "  return redis.call('del', KEYS[1]) " +
            "else " +
            "  return 0 " +
            "end";
        Object result = jedis.eval(luaScript, 
            1, LOCK_PREFIX + lockKey, requestId);
        return Long.valueOf(1).equals(result);
    }
}

解锁操作必须使用Lua脚本保证原子性。先GET判断value是否匹配,再DEL删除Key。如果不用Lua脚本,GET和DEL之间存在时间窗口,锁可能被其他线程误删。

requestId使用UUID标识锁的持有者,防止A线程获取锁后超时自动释放,B线程获取锁后,A线程的解锁操作误删B线程的锁。

Redlock算法:多实例投票提升可靠性

Redlock解决Redis单点故障问题。在多个独立Redis实例上同时获取锁,多数节点(N/2+1)获取成功即认为锁获取成功:

// Redisson Redlock实现
import org.redisson.Redisson;
import org.redisson.RedissonRedLock;
import org.redisson.api.RLock;

public class RedlockExample {
    public void executeWithLock() {
        RLock lock1 = redisson1.getLock("lock:order:123");
        RLock lock2 = redisson2.getLock("lock:order:123");
        RLock lock3 = redisson3.getLock("lock:order:123");

        RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
        try {
            if (redLock.tryLock(10, 30, TimeUnit.SECONDS)) {
                // 执行业务逻辑
                doBusinessLogic();
            }
        } finally {
            redLock.unlock();
        }
    }
}

Redlock在3个Redis实例上同时执行SET NX,至少2个成功才算获取锁。释放锁时向所有实例发送DEL。Redisson框架内置Redlock实现,支持锁续期(Watchdog机制)——后台线程每1/3过期时间自动续期,防止业务执行时间超过锁过期时间导致锁提前释放。

Zookeeper分布式锁:临时顺序节点方案

Zookeeper通过临时顺序节点实现分布式锁,天然解决锁过期和可重入问题:

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;

public class ZkDistributedLock {
    private final CuratorFramework client;
    private final InterProcessMutex lock;

    public ZkDistributedLock(CuratorFramework client, String lockPath) {
        this.client = client;
        this.lock = new InterProcessMutex(client, lockPath);
    }

    public void executeWithLock(Runnable task) throws Exception {
        try {
            if (lock.acquire(10, TimeUnit.SECONDS)) {
                try {
                    task.run();
                } finally {
                    lock.release();
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("获取分布式锁失败", e);
        }
    }
}

InterProcessMutex是Curator框架提供的可重入锁实现。底层原理:

  1. 在锁路径下创建临时顺序节点/lock/node-00001
  2. 获取所有子节点,检查自己是否为序号最小的节点
  3. 如果是最小节点,获取锁成功
  4. 如果不是,监听前一个节点的删除事件
  5. 前一个节点删除(对应客户端断开或主动释放锁)时,收到通知后重新检查

临时节点的特性:客户端连接断开时,Zookeeper自动删除该节点。这保证了锁持有者崩溃时锁会自动释放,不需要设置过期时间。

两种方案对比与选型建议

  • 一致性:Redis是AP模型,锁可能因主从切换失效;Zookeeper是CP模型,Zab协议保证强一致性
  • 性能:Redis TPS 10万+,延迟<1ms;Zookeeper TPS 1万左右,延迟2-5ms
  • 可靠性:Redlock提升可靠性但非强一致;Zookeeper临时节点自动释放,可靠性高
  • 复杂度:Redis实现简单;Zookeeper需部署集群

选型建议:

  • 电商秒杀库存扣减:Redis分布式锁 + Redisson,高并发场景下性能优先,配合库存预扣减兜底
  • 金融账户转账:Zookeeper分布式锁,强一致性保证,宁可牺牲性能也不允许锁失效
  • 定时任务防重执行:Redis分布式锁,简单高效,失效时重复执行影响可控
  • 分布式事务协调:Zookeeper分布式锁,与事务回滚配合保证数据一致

分布式锁不是万能的。使用前评估是否可以用幂等设计、乐观锁、队列串行化等方案替代。数据库层面的SELECT ... FOR UPDATE或乐观锁版本号机制,在单库场景下比分布式锁更可靠且无需额外中间件。技术选型的核心不在于哪种方案更”高级”,而在于业务对一致性和性能的真实需求。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/fen-bu-shi-suo-shi-xian-fang-an-dui-bi-redisredlock-yu/

(0)
小编小编
上一篇 1小时前
下一篇 1小时前

相关推荐