2

分布式锁的使用与注意事项

 3 years ago
source link: https://last2win.com/2021/01/15/redis-lock/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

此文是2021年第一篇博客,计划每2周写一篇博客。

分布式锁的使用与注意事项

分布式锁介绍

最近项目需要用到分布式锁,在网上看了挺多写分布式锁的文章,于是打算写一篇关于分布式锁的文章。

单机的服务不需要用分布式锁,多线程抢夺同一资源,在内存中使用锁就可以了。

分布式锁适用于多台机器抢夺同一资源。多台机器抢夺同一资源一般有以下情况:

1.微服务系统中,同一个接口同样的参数可能会被上游连续调用2次,想要保护自身系统的一致性和幂等性,在接口入口处进行分布式锁的操作是很有必要的。

2.在一个服务中,一笔单据可能被不同的定时任务/接口捞起,会重复调用下游接口,使用分布式锁可以保护下游。

从上面列举的2种情况可以看出,分布式锁必须是独立的第三方。

目前最流行的分布式锁是Redis分布式锁,下面介绍一下Redis分布式锁的使用方法。

Redis支持当key不存在时设置一个Key,因此把一个共享资源作为Key,就可以实现分布式锁。

>set key value nx

其中nx表示当Key不存在时设置key,如果Key已经存在,不进行设置。

等程序运行结束,需要释放资源时,把锁删除就可以了:

>del key

但这样直接使用分布式锁有以下几个问题:

1.如果获取锁的程序出现了异常,没有删除锁,那么后续这个资源就无法被其他程序使用了。因此锁需要设置过期时间。

2.锁有过期时间后出现了第二个问题。如果程序A执行的时间过长,导致锁失效;锁失效后程序B拿到锁,如果此时A释放了B的锁,那么C也可以拿到锁了。为了解决这个问题,需要在设置value的时候选择一个随机字符串,删除锁的时候需要先判断value是否为自己设置的value。

因此最终的用法如下:

>set key random_string nx px 10000

其中px 10000表示该key的过期时间为10秒。

上文提到的分布式锁的用法就是最常见的Redis分布式锁的用法,但也有缺点。因为分布式锁有过期时间,程序A始终有可能执行时间过长导致锁失效,比如JVM GC暂停了很久,程序A以为锁没失效,仍会进行资源的访问。

参考大佬文章:How to do distributed locking — Martin Kleppmann’s blog可以得出以下观点:

1.如果使用分布式锁是为了效率,防止不同客户端做重复的任务。即使锁失效了,也能保证幂等性,或者无需幂等性保证,那么单节点的Redis锁就够用了。

2.如果使用Redis锁是为了正确性,任何情况都不允许锁失效,那么分布式锁不适合这个场景,更推荐使用事务型数据库进行上锁操作,比如select…for update。

参考资料:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK