面试官Redis分布式锁存在什么问题如何

1.如何实现分布式锁

Redis天生就可以作为一个分布式系统来使用,所以它实现的锁都是分布式锁。

Redis可以通过setnx(setifnotexists)命令实现分布式锁~

setnxmylocktrue-加锁

delmylock-释放锁

通过执行结果是否为1可以判断是否成功获取到锁~

2.Redis分布式锁存在什么问题

Redis分布式锁存在两个问题:

死锁问题:未设置过期时间,锁忘记释放,加锁后还没来的及释放锁就宕机了都会导致死锁问题.

锁误删问题:设置了超时时间,但是线程执行超过超时时间后锁误删问题.

2.1解决死锁问题

MySQL中解决死锁问题是通过设置超时时间,Redis也是如此,但是问题来了,第一步先加锁,然后再设置超时时间,那么就不满足原子性了,那么怎么办?

官方在Redis2.6.12版本之后,新增了一个功能,我们可以使用一条命令既执行加锁操作,又设置超时时间:setnx和expire

第一条命令成功加锁,并设置30s过期时间

第二条命令跟在第一条命令后,还没有超过30s,所以获取失败

2.2解决锁误删问题

锁误删问题是解决死锁问题带来的问题,如何理解?

既然知道了什么是锁误删问题,那么如何解决?

答:可以通过添加锁标识来解决.

前面我们使用set命令的时候,只使用到了key,那么可以给value设置一个标识,表示当前锁归属于那个线程,例如value=thread1,value=thread2.....

但是这样解决依然存在问题,因为新增锁标识之后,线程在释放锁的时候,需要执行两步操作了:

判断锁是否属于自己

如果是,就删除锁

这样就不能保证原子性了,那该怎么办?

解决方案

使用lua脚本来解决(Redis本身就能保证lua脚本里面所有命令都是原子性操作)

使用Redisson框架来解决(主流)

那么Redisson如何实现分布式锁呢?

代码示例

1.引入Redisson依赖

dependency

groupIdorg.redisson/groupId

artifactIdredisson-spring-boot-starter/artifactId

version3.23.2/version

/dependency

2.创建RedissonClient对象

Configuration

publicclassRedissonConfig{

Bean

publicRedissonClientredissonClient(){

Configconfig=newConfig();

config.useSingleServer().setAddress("redis://.0.0.1:");

//如果有密码需要设置密码

returnRedisson.create(config);

}

}

3.调用分布式锁

RestController

publicclassLockController{

Resource

privateRedissonClientredissonClient;

RequestMapping("/lock")

publicStringlockResource()throwsInterruptedException{

StringlockKey="myLock";

//获取锁

RLocklock=redissonClient.getLock(lockKey);

try{

//超时时间10s,[tryLock获取成功才需要释放锁,获取失败不需要释放锁]

booleanisLocked=lock.tryLock(20,TimeUnit.SECONDS);

if(isLocked){

//成功获取到锁

try{

TimeUnit.SECONDS.sleep(5);

return"成功获取到锁,并执行业务代码";

}catch(InterruptedExceptione){

e.printStackTrace();

}finally{

//释放锁

lock.unlock();

}

}else{

//获取锁失败

return"获取锁失败";

}

}catch(InterruptedExceptione){

e.printStackTrace();

}

return"获取锁成功";

}

}

启动项目,使用端口访问接口:




转载请注明:http://www.aierlanlan.com/cyrz/10073.html