0
点赞
收藏
分享

微信扫一扫

redis-分布式锁

左手梦圆 2022-03-10 阅读 106

在分布式场景中,分布式锁经常选用redis或者ZK来实现,在使用redis时,应注意的问题。

使用分布式锁时需要解决的问题:

1、锁需要具备唯一性

问题讲解:分布式场景下为了保证同一变量在分布式环境中的唯一性,需要对同一资源加锁。

解决方案:使用redis命令setnx(set if not exist),即只能被一个客户端操作成功,如果redis实例存在唯一键(key),如果再想在该键(key)上设置值,就会被拒绝。在锁操作完了后,需要进行锁释放>del lockkey #释放锁。

2、 死锁(因操作客户端挂掉,锁无法释放。----引入原子性的超时时间)

问题讲解: redis释放锁需要客户端的操作,如果此时客户端突然挂了,就没有释放锁的操作了,也意味着其他客户端想要重新加锁,却加不了的问题。

解决方案:,需要在加锁的同时,给锁加上超时时间。

 >setnx lockkey true #加锁操作  >expire lockkey 5    #给锁加上超时时间

因为setnx和expire需要两个命令来完成操作,也就是需要两次RTT操作,如果在setnx和expire两次命令之间,客户端突然挂掉,这时又无法释放锁,且又回到了死锁的问题.

进一步优化: 使用set扩展命令,set lockkey true ex 5 nx命令可以一次性完成setnx和expire两个操作,也就是解决了原子性问题.( 锁的创建和设置锁超时时间需要具备原子性

 >set lockkey true ex 5 nx #加锁,过期时间5s-----

  ... do something critical ...

  >del lockkey

3、锁的超时问题(任务超时--使用lua删除锁再重建锁,保证原子性)

  问题讲解:  虽然给锁加上了超时时间,但是客户端并不能一定在超时时间之内完成定时任务,所以,即使当前客户端没有完成任务,此时又会有其他的客户端设置锁成功,此时同一资源将会面临多个客户端同时操作的问题.

 解决方案:客户端可以在锁设置成功之后,进行定时任务,在锁超时之前使用lua脚本删除锁并重新设置锁和超时时间。当然,这里为什么会使用lua来完成操作呢,其实和上面的原子性问题一样,在删除锁和重新设置锁和锁的超时时间之间,可能面临其他的客户端将锁资源占有,而lua具有原子性的特性,删除锁和重新加锁这两个操作要么都完成,要么都不完成.(具体方案以及代码后续补充)

4、锁的可重入问题

问题讲解: 拥有锁的客户端想要再次获得锁

解决方案:我们可以选择使用lua脚本的方案,将锁重新删除和设置.

5、 集群下分布式锁的问题以及需要考虑的其他问题

 问题讲解:

  这一问题是在redis集群方案时会出现的.事实上,现在为了保证redis的高可用和访问性能,都会设置redis的主节点和从节点,主节点负责写操作,从节点负责读操作,也就意味着,我们所有的锁都要写在主redis服务器实例中,如果主redis服务器宕机,资源释放(在没有加持久化时候,如果加了持久化,这一问题会更加复杂),此时redis主节点的数据并没有复制到从服务器,此时,其他客户端就会趁机获取锁,而之前拥有锁的客户端可能还在对资源进行操作,此时又会出现多客户端对同一资源进行访问和操作的问题.

  解决方案:后续补充

举报

相关推荐

0 条评论