阿伟先生 發表於 2025-11-15 12:00:15

Redis的分布式锁如何使用和代码示例

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">1. 分布式锁的基本原理</a></li><li><a href="#_label1">2. 使用 Jedis 实现 Redis 分布式锁</a></li><ul class="second_class_ul"><li><a href="#_lab2_1_0">依赖添加</a></li><li><a href="#_lab2_1_1">分布式锁实现类</a></li></ul><li><a href="#_label2">3. 详细解释</a></li><ul class="second_class_ul"></ul><li><a href="#_label3">4. 注意事项</a></li><ul class="second_class_ul"></ul><li><a href="#_label4">5. 使用 Redlock 算法</a></li><ul class="second_class_ul"></ul><li><a href="#_label5">总结</a></li><ul class="second_class_ul"></ul></ul></div><p>在分布式系统中,分布式锁是一种关键的工具,用于确保多个进程在不同机器上能够安全地访问共享资源。Redis 提供了一种简单且高效的方式来实现分布式锁。以下是如何使用 Redis 实现分布式锁的详细介绍和代码示例。</p>
<p class="maodian"><a name="_label0"></a></p><h2>1. 分布式锁的基本原理</h2>
<p>Redis 分布式锁的基本原理是使用 Redis 的 <code>SET</code> 命令来尝试设置一个键,如果该键不存在,则表示获取锁成功。为了防止死锁,需要为锁设置过期时间。</p>
<p class="maodian"><a name="_label1"></a></p><h2>2. 使用 Jedis 实现 Redis 分布式锁</h2>
<p>以下是使用 Jedis 客户端在 Java 中实现 Redis 分布式锁的完整示例。</p>
<p class="maodian"><a name="_lab2_1_0"></a></p><h3>依赖添加</h3>
<p>在你的 Maven 项目中添加 Jedis 依赖:</p>
<div class="jb51code"><pre class="brush:plain;">&lt;dependency&gt;
    &lt;groupId&gt;redis.clients&lt;/groupId&gt;
    &lt;artifactId&gt;jedis&lt;/artifactId&gt;
    &lt;version&gt;3.7.0&lt;/version&gt;
&lt;/dependency&gt;</pre></div>
<p class="maodian"><a name="_lab2_1_1"></a></p><h3>分布式锁实现类</h3>
<p>下面是一个简单的 Redis 分布式锁实现类:</p>
<div class="jb51code"><pre class="brush:java;">import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;
public class RedisDistributedLock {
    private final Jedis jedis;
    private final String lockKey;
    private final long expireTime;
    public RedisDistributedLock(Jedis jedis, String lockKey, long expireTime) {
      this.jedis = jedis;
      this.lockKey = lockKey;
      this.expireTime = expireTime;
    }
    public boolean acquireLock(String lockValue) {
      SetParams params = new SetParams().nx().px(expireTime);
      String result = jedis.set(lockKey, lockValue, params);
      return "OK".equals(result);
    }
    public boolean releaseLock(String lockValue) {
      String script = "if redis.call('get', KEYS) == ARGV then " +
                        "return redis.call('del', KEYS) " +
                        "else return 0 end";
      Object result = jedis.eval(script, 1, lockKey, lockValue);
      return "1".equals(result.toString());
    }
    public static void main(String[] args) {
      try (Jedis jedis = new Jedis("localhost", 6379)) {
            String lockKey = "myLock";
            String lockValue = "myUniqueValue";
            long expireTime = 30000; // 30 seconds
            RedisDistributedLock lock = new RedisDistributedLock(jedis, lockKey, expireTime);
            // Acquire lock
            if (lock.acquireLock(lockValue)) {
                System.out.println("Lock acquired!");
                // Do your critical section work here
                // Release lock
                if (lock.releaseLock(lockValue)) {
                  System.out.println("Lock released!");
                } else {
                  System.out.println("Failed to release lock!");
                }
            } else {
                System.out.println("Failed to acquire lock!");
            }
      }
    }
}</pre></div>
<p class="maodian"><a name="_label2"></a></p><h2>3. 详细解释</h2>
<ul><li><strong>acquireLock 方法</strong>:该方法尝试获取锁。使用 <code>SET</code> 命令和 <code>NX</code>(仅当键不存在时设置)和 <code>PX</code>(设置过期时间)参数来确保设置锁时的原子性。返回 <code>true</code> 表示获取锁成功,返回 <code>false</code> 表示获取锁失败。</li><li><strong>releaseLock 方法</strong>:该方法释放锁。使用 Lua 脚本来确保释放锁的原子性,确保只有持有锁的客户端才能释放锁。Lua 脚本检查当前锁的值是否与传入的值匹配,如果匹配则删除锁。</li></ul>
<p class="maodian"><a name="_label3"></a></p><h2>4. 注意事项</h2>
<ul><li><strong>锁的过期时间</strong>:确保锁的过期时间足够长,可以覆盖所有可能的操作时间,但也不能太长,以防止死锁。</li><li><strong>唯一标识</strong>:确保每个客户端设置的 <code>lockValue</code> 唯一,这样可以确保只有持有锁的客户端才能释放锁。</li><li><strong>容错处理</strong>:在实际应用中,还需要考虑网络分区、Redis 故障等情况,可以使用 Redlock 算法来增强可靠性。</li></ul>
<p class="maodian"><a name="_label4"></a></p><h2>5. 使用 Redlock 算法</h2>
<p>Redlock 是 Redis 提供的一种分布式锁算法,旨在提高分布式环境下锁的可靠性。其基本思想是在多个独立的 Redis 实例上尝试获取锁,以提高容错性。</p>
<p>以下是使用 Redlock 算法的实现示例:</p>
<div class="jb51code"><pre class="brush:java;">import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.params.SetParams;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
public class RedisRedlock {
    private final List&lt;JedisPool&gt; jedisPools;
    private final long expireTime;
    private final long retryDelay;
    private final int retryCount;
    public RedisRedlock(List&lt;JedisPool&gt; jedisPools, long expireTime, long retryDelay, int retryCount) {
      this.jedisPools = jedisPools;
      this.expireTime = expireTime;
      this.retryDelay = retryDelay;
      this.retryCount = retryCount;
    }
    public String acquireLock(String lockKey) {
      String lockValue = UUID.randomUUID().toString();
      int n = jedisPools.size();
      int quorum = n / 2 + 1;
      for (int i = 0; i &lt; retryCount; i++) {
            int count = 0;
            long startTime = System.currentTimeMillis();
            for (JedisPool pool : jedisPools) {
                try (Jedis jedis = pool.getResource()) {
                  SetParams params = new SetParams().nx().px(expireTime);
                  String result = jedis.set(lockKey, lockValue, params);
                  if ("OK".equals(result)) {
                        count++;
                  }
                }
            }
            long elapsedTime = System.currentTimeMillis() - startTime;
            if (count &gt;= quorum &amp;&amp; elapsedTime &lt;= expireTime) {
                return lockValue;
            } else {
                for (JedisPool pool : jedisPools) {
                  try (Jedis jedis = pool.getResource()) {
                        if (lockValue.equals(jedis.get(lockKey))) {
                            jedis.del(lockKey);
                        }
                  }
                }
            }
            try {
                Thread.sleep(retryDelay);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
      }
      return null;
    }
    public boolean releaseLock(String lockKey, String lockValue) {
      String script = "if redis.call('get', KEYS) == ARGV then " +
                        "return redis.call('del', KEYS) " +
                        "else return 0 end";
      boolean success = false;
      for (JedisPool pool : jedisPools) {
            try (Jedis jedis = pool.getResource()) {
                Object result = jedis.eval(script, Arrays.asList(lockKey), Arrays.asList(lockValue));
                if ("1".equals(result.toString())) {
                  success = true;
                }
            }
      }
      return success;
    }
    public static void main(String[] args) {
      List&lt;JedisPool&gt; jedisPools = Arrays.asList(
                new JedisPool("localhost", 6379),
                new JedisPool("localhost", 6380),
                new JedisPool("localhost", 6381)
      );
      long expireTime = 30000; // 30 seconds
      long retryDelay = 200; // 200 milliseconds
      int retryCount = 3;
      RedisRedlock redlock = new RedisRedlock(jedisPools, expireTime, retryDelay, retryCount);
      String lockKey = "myLock";
      String lockValue = redlock.acquireLock(lockKey);
      if (lockValue != null) {
            System.out.println("Lock acquired!");
            // Do your critical section work here
            if (redlock.releaseLock(lockKey, lockValue)) {
                System.out.println("Lock released!");
            } else {
                System.out.println("Failed to release lock!");
            }
      } else {
            System.out.println("Failed to acquire lock!");
      }
    }
}</pre></div>
<p class="maodian"><a name="_label5"></a></p><h2>总结</h2>
<p>Redis 分布式锁是一种有效的工具,用于在分布式环境中实现互斥访问。通过使用 Jedis 客户端,可以方便地实现基本的分布式锁功能。而 Redlock 算法则提供了一种更可靠的分布式锁实现,适用于对容错性要求较高的场景。合理配置和使用分布式锁,可以显著提高分布式系统的稳定性和一致性。</p>
頁: [1]
查看完整版本: Redis的分布式锁如何使用和代码示例