那些年我们用过的分布式锁,你都get到了吗
分布式锁的特性互斥性:和我们本地锁一样互斥性是最基本,但是分布式锁需要保证在不同节点的不同线程的互斥。可重入性:同一个节点上的同一个线程如果获取了锁之后那么也可以再次获取这个锁。锁超时:和本地锁一样支持锁超时,防止死锁。常见的分布式锁MySQLzookeeperRedis基于MySQL实现分布式锁基于zookeeper实现分布式锁基于Redis实现分布式锁...
·
分布式锁的特性
- 互斥性:和我们本地锁一样互斥性是最基本,但是分布式锁需要保证在不同节点的不同线程的互斥。
- 可重入性:同一个节点上的同一个线程如果获取了锁之后那么也可以再次获取这个锁。
- 锁超时:和本地锁一样支持锁超时,防止死锁。
zookeeper实现分布式锁
- zookeeper的分布式锁是基于
临时顺序节点来实现的 - 通过session的会话周期来防止锁超时
- zookeeper的临时节点在客户端断开后自动删除,可解决死锁问题
- 当自身节点的序号不是最小的时候,通过监听机制,一直等到自身节点序号为最小,可实现阻塞锁
- 在创建节点是,客户端把自身信息写入节点,获取所有,通过节点信息判断,可实现锁重入
Redis实现分布式锁
基于 SET NX EX实现,单机版
这里利用 Redis set key 时的一个 NX 参数可以保证在这个 key 不存在的情况下写入成功。并且再加上 EX 参数可以让该 key 在超时之后自动删除。
- 加锁
private static final String SET_IF_NOT_EXIST = "NX";
private static final String SET_WITH_EXPIRE_TIME = "PX";
public boolean tryLock(String key, String request) {
String result = this.jedis.set(LOCK_PREFIX + key, request, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, 10 * TIME);
if (LOCK_MSG.equals(result)){
return true ;
}else {
return false ;
}
}
- 解锁
解锁也很简单,其实就是把这个 key 删掉就万事大吉了,比如使用 del key 命令。
public boolean unlock(String key,String request){
//lua script
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = null ;
if (jedis instanceof Jedis){
result = ((Jedis)this.jedis).eval(script, Collections.singletonList(LOCK_PREFIX + key), Collections.singletonList(request));
}else if (jedis instanceof JedisCluster){
result = ((JedisCluster)this.jedis).eval(script, Collections.singletonList(LOCK_PREFIX + key), Collections.singletonList(request));
}else {
//throw new RuntimeException("instance is error") ;
return false ;
}
if (UNLOCK_MSG.equals(result)){
return true ;
}else {
return false ;
}
}
基于Redisson实现,高可用版
参考地址:https://codechina.csdn.net/mirrors/redisson/redisson?utm_source=csdn_github_accelerator
// 1. 配置文件
Config config = new Config();
config.useSingleServer()
.setAddress("redis://127.0.0.1:6379")
.setPassword(RedisConfig.PASSWORD)
.setDatabase(0);
//2. 构造RedissonClient
RedissonClient redissonClient = Redisson.create(config);
//3. 设置锁定资源名称
RLock lock = redissonClient.getLock("redlock");
lock.lock();
try {
System.out.println("获取锁成功,实现业务逻辑");
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
Redis分布式锁 VS zookeeper分布式锁
- zookeeper可靠性比redis强太多,只是效率低了点,如果并发量不是特别大,追求可靠性,首选zookeeper。为了效率,则首选redis实现。
- zookeeper分布式锁性能上可能没有Redis分布式锁那么高。因为每次在创建锁和释放锁的过程中,都要动态创建、销毁瞬时节点来实现锁功能。zookeeper中创建和删除节点只能通过Leader服务器来执行,然后将数据同步到所有的Follower机器上。
- zookeeper的原子性基于sequence=false保证节点唯一性,redis的原子性基于lua脚本
- redis存在可能丢数据的问题,因为redis内存操作成功之后直接返回success,这个时候还没有刷盘就可以造成数据丢失从而导致锁失效
更多推荐



所有评论(0)