有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步, 认准https://blog.zysicyj.top
在分布式系统中,分布式锁是一种常见的需求,用于在多个节点之间同步资源访问。Redis 作为一个高性能的内存数据库,提供了多种方式来实现分布式锁。下面详细介绍如何使用 Redis 实现分布式锁,以及相关的注意事项。
基本实现方式
最简单的分布式锁实现方式是使用 Redis 的 SETNX
命令(SET if Not eXists),结合 EXPIRE
命令来设置键的过期时间,避免因程序异常终止而导致锁无法释放。
实现示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| import redis.clients.jedis.Jedis;
public class RedisLock { private Jedis jedis; private String lockKey; private int lockExpireTime;
public RedisLock(Jedis jedis, String lockKey, int lockExpireTime) { this.jedis = jedis; this.lockKey = lockKey; this.lockExpireTime = lockExpireTime; }
public boolean acquireLock(String requestId) { String result = jedis.set(lockKey, requestId, "NX", "EX", lockExpireTime); return "OK".equals(result); }
public boolean releaseLock(String requestId) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " + " return redis.call('del', KEYS[1]) " + "else " + " return 0 " + "end"; Object result = jedis.eval(script, 1, lockKey, requestId); return (Long) result == 1; }
public static void main(String[] args) { Jedis jedis = new Jedis("localhost", 6379); RedisLock redisLock = new RedisLock(jedis, "myLock", 30);
String requestId = "abc123"; if (redisLock.acquireLock(requestId)) { try { System.out.println("Lock acquired, processing..."); } finally { redisLock.releaseLock(requestId); } } else { System.out.println("Unable to acquire lock, try again later."); } } }
|
实现细节
SET 命令 :
使用 SET
命令并加上 NX
和 EX
参数,可以在一个原子操作中设置键的值和过期时间。
1
| SET myLock abc123 NX EX 30
|
Lua 脚本 :
使用 Lua 脚本保证获取锁和释放锁的原子性。释放锁时需要检查锁的持有者是否是当前客户端,以避免误删他人持有的锁。
1 2 3 4 5
| if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end
|
注意事项
唯一标识符 :
每个锁请求需要一个唯一的标识符(如 UUID),用于区分不同客户端持有的锁。这样可以确保只有持有锁的客户端才能释放锁。
过期时间 :
锁的过期时间要设置合理,过短会导致业务未执行完锁就失效,过长会导致锁占用时间过久。可以根据业务逻辑和执行时间进行调整。
避免死锁 :
使用过期时间可以避免客户端崩溃导致锁无法释放的问题,但需要确保锁的过期时间足够覆盖业务逻辑的执行时间。
锁续期 :
对于执行时间较长的任务,可以考虑锁续期机制,即在持有锁的客户端定期刷新锁的过期时间,防止锁提前失效。
使用 Redisson 实现分布式锁
Redisson 是一个在 Redis 上的 Java 客户端,它提供了更多高级的分布式工具,包括分布式锁。使用 Redisson 可以更简便地实现分布式锁。
Redisson 示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| 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 RedissonLockExample { public static void main(String[] args) { Config config = new Config(); config.useSingleServer().setAddress("redis://localhost:6379"); RedissonClient redissonClient = Redisson.create(config);
RLock lock = redissonClient.getLock("myLock");
try { if (lock.tryLock(100, 10, TimeUnit.SECONDS)) { try { System.out.println("Lock acquired, processing..."); } finally { lock.unlock(); } } else { System.out.println("Unable to acquire lock, try again later."); } } catch (InterruptedException e) { e.printStackTrace(); } finally { redissonClient.shutdown(); } } }
|
结论
使用 Redis 实现分布式锁是一种高效、简便的方式,通过合理的锁机制和过期时间,可以有效防止资源竞争和死锁问题。Redisson 提供了更高级的分布式锁实现,进一步简化了分布式系统中的锁管理。