Home
img of docs

探讨 分布式锁 的实现原理及常见的实现方式。介绍几种常见的分布式锁实现方式(Redis 分布式锁、Zookeeper 分布式锁、数据库实现的分布式锁)

chou403

/ SpringCloud

/ c:

/ u:

/ 4 min read


分布式锁是如何实现的,具体实现是什么

分布式锁是一种在分布式系统中用于控制对共享资源的并发访问的机制。由于多个节点可能同时访问同一资源,因此需要一种机制来确保这些访问不会产生冲突。分布式锁的实现方式有多种,常见的方法包括基于数据库,Redis 和 Zookeeper 的实现。下面介绍几种常见的分布式锁的实现方法及其具体实现。

基于数据库的分布式锁

方法一: 使用数据库表

创建一个锁表,通过在该表中插入或删除特定记录来实现分布式锁。

使用数据库表示例代码
   CREATE TABLE distributed_lock (
    lock_name VARCHAR(255) PRIMARY KEY,
    lock_value VARCHAR(255)
);
   public class DatabaseLock {
    private static final String LOCK_NAME = "my_lock";
    private final DataSource dataSource;

    public DatabaseLock(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public boolean lock() {
        try (Connection connection = dataSource.getConnection()) {
            String sql = "INSERT INTO distributed_lock (lock_name, lock_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE lock_name=lock_name";
            try (PreparedStatement ps = connection.prepareStatement(sql)) {
                ps.setString(1, LOCK_NAME);
                ps.setString(2, UUID.randomUUID().toString());
                ps.executeUpdate();
                return true;
            }
        } catch (SQLException e) {
            return false;
        }
    }

    public void unlock() {
        try (Connection connection = dataSource.getConnection()) {
            String sql = "DELETE FROM distributed_lock WHERE lock_name = ?";
            try (PreparedStatement ps = connection.prepareStatement(sql)) {
                ps.setString(1, LOCK_NAME);
                ps.executeUpdate();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

基于 Redis 的分布式锁

Redis 提供了 SET 命令的扩展,可以使用 NX(不存在时设置)和 EX(过期时间)参数实现分布式锁。可以通过 Redisson 或手动实现 Redis 分布式锁。

示例代码(手动实现)
   import redis.clients.jedis.Jedis;

public class RedisLock {
    private static final String LOCK_KEY = "distributed_lock";
    private static final int EXPIRE_TIME = 10; // seconds
    private final Jedis jedis;
    private String lockValue;

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

    public boolean lock() {
        lockValue = UUID.randomUUID().toString();
        String result = jedis.set(LOCK_KEY, lockValue, "NX", "EX", EXPIRE_TIME);
        return "OK".equals(result);
    }

    public void unlock() {
        String value = jedis.get(LOCK_KEY);
        if (lockValue.equals(value)) {
            jedis.del(LOCK_KEY);
        }
    }
}
示例代码(使用 Redisson)
   import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

import java.util.concurrent.TimeUnit;

public class RedissonLock {
    private final RedissonClient redissonClient;
    private final RLock lock;

    public RedissonLock() {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        redissonClient = Redisson.create(config);
        lock = redissonClient.getLock("distributed_lock");
    }

    public boolean lock() {
        try {
            return lock.tryLock(100, 10, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            return false;
        }
    }

    public void unlock() {
        lock.unlock();
    }
}

基于 Zookeeper 的分布式锁

Zookeeper 可以通过创建临时有序节点实现分布式锁。Apache Curator 是一个 Zookeeper 客户端库,简化了分布式锁的实现。

基于 Zookeeper 示例代码
   import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.framework.CuratorFrameworkFactory;

public class ZookeeperLock {
    private static final String ZK_ADDRESS = "127.0.0.1:2181";
    private static final String LOCK_PATH = "/distributed_lock";
    private final InterProcessMutex lock;
    private final CuratorFramework client;

    public ZookeeperLock() {
        client = CuratorFrameworkFactory.newClient(ZK_ADDRESS, new ExponentialBackoffRetry(1000, 3));
        client.start();
        lock = new InterProcessMutex(client, LOCK_PATH);
    }

    public boolean lock() {
        try {
            return lock.acquire(10, TimeUnit.SECONDS);
        } catch (Exception e) {
            return false;
        }
    }

    public void unlock() {
        try {
            lock.release();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

分布式锁总结

上述三种方法展示了在不同环境下实现分布式锁的具体实现方式:

  1. 基于数据库: 简单但效率较低,适用于小规模分布式系统。
  2. 基于 Redis: 性能好,使用方便,适用于大部分分布式系统。
  3. 基于 Zookeeper: 提供强一致性和高可用性,适用于需要高可靠性的分布式系统。

选择合适的分布式锁实现方式取决于具体的应用场景和需求。