分布式锁
什么是分布式锁
满足分布式系统或集群模式下多进程可见并且互斥的锁
分布式锁具有的特点
- 高可用
- 多进程可见
- 互斥
- 高性能
- 安全性
分布式锁的实现
分布式锁的核心是实现多进程之间互斥,而满足这一点的方式有很多,常见的有三种:
MySQL | Redis | Zookeeper | |
---|---|---|---|
互斥 | 利用mysql本身的互斥锁机制 | 利用setnx这样的互斥命令 | 利用节点的唯一和有序性实现互斥 |
高可用 | 好 | 好 | 好 |
高性能 | 一般 | 好 | 一般 |
安全性 | 断开连接,自动释放锁 | 利用锁超时时间,到期后自动释放锁 | 临时节点,断开连接自动释放 |
基于Redis的分布式锁
实现分布式锁时需要实现的两个基本方法:
-
获取锁:互斥-确保只能一个线程获取锁(setnx lock thread1)
-
释放锁:手动释放(del lock) 超时自动释放锁(获取锁的时候添加一个超时时间)
public interface ILock { /** * 尝试获取锁 * @param timeoutSec 锁持有的超时时间,过期后自动释放 * @return true代表获取锁成功; false代表获取锁失败 */ boolean tryLock(long timeoutSec); /** * 释放锁 */ void unlock();
public class SimpleRedisLock implements ILock { private final String name; private StringRedisTemplate stringRedisTemplate; public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) { this.name = name; this.stringRedisTemplate = stringRedisTemplate; } private static final String KEY_PREFIX = "lock:"; private static final String ID_PREFIX = UUID.randomUUID().toString(true) + "-"; private static final DefaultRedisScript<Long> UNLOCK_SCRIPT; static { UNLOCK_SCRIPT = new DefaultRedisScript<>(); //执行的lua文件 UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua")); //脚本方法执行完成后的返回值 UNLOCK_SCRIPT.setResultType(Long.class); } @Override public boolean tryLock(long timeoutSec) { // 获取线程标示 String threadId = ID_PREFIX + Thread.currentThread().getId(); // 获取锁 Boolean success = stringRedisTemplate.opsForValue() .setIfAbsent(KEY_PREFIX + name, threadId, timeoutSec, TimeUnit.SECONDS); //自动拆箱:注意空指针的可能性,这里当success为空的时候,返回false return Boolean.TRUE.equals(success); } @Override public void unlock() { // 调用lua脚本 stringRedisTemplate.execute( UNLOCK_SCRIPT, Collections.singletonList(KEY_PREFIX + name), ID_PREFIX + Thread.currentThread().getId()); } }
-- 比较线程标示与锁中的标示是否一致 if(redis.call('get', KEYS[1]) == ARGV[1]) then -- 释放锁 del key return redis.call('del', KEYS[1]) end return 0
版权声明:本文为qq_43765199原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。