分布式锁实现及常见问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分布式锁实现及常见问题相关的知识,希望对你有一定的参考价值。

参考技术A 对于平台系统,由于系统是集群模式,每个节点都是无状态模式,提供统一的功能,所以无法使用JVM的锁,需要使用分布式锁保证所有机器只有一个在执行

由于分布式锁一般是通过其他机器或进程(redis,zk,mysql等)来记录状态所以需要有的特性

Redis为AP模式,可能存在获取到多把锁,比如在主从切换时,Zk为CP架构,不会存在获取到多把锁,因为在创建节点时会同步给半数节点。redis分布式锁相对更快

设置锁的超时时间,宕机后只会影响一定的时间

获取锁时判断设置的值是否和当前线程的信息一样

使用watchDog进行续租

极端情况下,节点1获取到了锁,发送修改了值的请求,请求已经发送出去,但是还没有发送到资源服务器,此时节点1断开了ZK连接,节点2拿到了锁,也发送了修改值的命令,资源服务器先收到节点2的请求,之后又收到了节点1的请求就会出错

分布式锁,及Redis实现分布式锁

一、什么是分布式锁?

要介绍分布式锁,首先要提到与分布式锁相对应的是线程锁、进程锁。

线程锁:主要用来给方法、代码块加锁。当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段。线程锁只在同一JVM中有效果,因为线程锁的实现在根本上是依靠线程之间共享内存实现的,比如synchronized是共享对象头,显示锁Lock是共享某个变量(state)。

进程锁:为了控制同一操作系统中多个进程访问某个共享资源,因为进程具有独立性,各个进程无法访问其他进程的资源,因此无法通过synchronized等线程锁实现进程锁。

分布式锁:当多个进程不在同一个系统中,用分布式锁控制多个进程对资源的访问。


二、分布式锁的使用场景。

线程间并发问题和进程间并发问题都是可以通过分布式锁解决的,但是强烈不建议这样做!因为采用分布式锁解决这些小问题是非常消耗资源的!分布式锁应该用来解决分布式情况下的多进程并发问题才是最合适的。

有这样一个情境,线程A和线程B都共享某个变量X。

如果是单机情况下(单JVM),线程之间共享内存,只要使用线程锁就可以解决并发问题。

如果是分布式情况下(多JVM),线程A和线程B很可能不是在同一JVM中,这样线程锁就无法起到作用了,这时候就要用到分布式锁来解决。


三、分布式锁的实现(Redis)

分布式锁实现的关键是在分布式的应用服务器外,搭建一个存储服务器,存储锁信息,这时候我们很容易就想到了Redis。首先我们要搭建一个Redis服务器,用Redis服务器来存储锁信息。

在实现的时候要注意的几个关键点:

1、锁信息必须是会过期超时的,不能让一个线程长期占有一个锁而导致死锁;

2、同一时刻只能有一个线程获取到锁。

几个要用到的redis命令:

setnx(key, value):“set if not exits”,若该key-value不存在,则成功加入缓存并且返回1,否则返回0。

get(key):获得key对应的value值,若不存在则返回nil。

getset(key, value):先获取key对应的value值,若不存在则返回nil,然后将旧的value更新为新的value。

expire(key, seconds):设置key-value的有效期为seconds秒。

看一下流程图:

在这个流程下,不会导致死锁。

我采用Jedis作为Redis客户端的api,下面来看一下具体实现的代码。

(1)首先要创建一个Redis连接池。

分布式锁,及Redis实现分布式锁

分布式锁,及Redis实现分布式锁

(2)对Jedis的api进行封装,封装一些实现分布式锁需要用到的操作。

分布式锁,及Redis实现分布式锁

分布式锁,及Redis实现分布式锁

分布式锁,及Redis实现分布式锁

(3)分布式锁工具类

分布式锁,及Redis实现分布式锁

分布式锁,及Redis实现分布式锁

分布式锁,及Redis实现分布式锁

分布式锁,及Redis实现分布式锁

分布式锁,及Redis实现分布式锁

分布式锁,及Redis实现分布式锁

分布式锁,及Redis实现分布式锁

分布式锁,及Redis实现分布式锁


以上是关于分布式锁实现及常见问题的主要内容,如果未能解决你的问题,请参考以下文章

分布式锁的实现及问题

Redis分布式锁的实现及注意事项

分布式锁原理及实现方式

基于Hazelcast及Kafka实现的分布式锁与集群负载均衡

分布式锁原理及实现方式

分布式锁的技术选型及思考