本文主要介绍分布式锁的基本概念以及实现。
分布式锁
分布式锁需要满足的特性:
可见性:多个线程都能看到相同的结果,注意:这个地方说的可见性并不是并发编程中指的内存可见性,只是说多个进程之间都能感知到变化的意思
互斥:互斥是分布式锁的最基本的条件,使得程序串行执行
高可用:程序不易崩溃,时时刻刻都保证较高的可用性
高性能:由于加锁本身就让性能降低,所有对于分布式锁本身需要他就较高的加锁性能和释放锁性能
安全性:安全也是程序中必不可少的一环
分布式锁的三种实现方式:
Redis实现分布式锁
在这里我们利用了redis单线程,所有的redis请求都会被串行化处理的特点,结合setnx
命令来实现分布式锁,同时利用redis的ttl来防止死锁。
当有多个线程进入时,我们就利用该方法,第一个线程进入时,redis 中还没有这个key ,返回了1,如果结果是1,则表示他抢到了锁,那么他去执行业务,然后再删除锁,退出锁逻辑,没有抢到锁的线程,等待一定时间后重试或者直接返回即可。
在上述描述中,会出现一些问题:锁的误删,原子性。
分布式锁误删
如上图,线程1误删了线程2的锁。解决办法,在存入锁时,放入自己的标识,在删除锁时,判断当前这把锁的标识是不是自己存入的,如果是,则进行删除,如果不是,则不进行删除。
分布式锁的原子性
如上图,当线程1判断这把锁是自己的之后,还没来的及删除,就被阻塞住了(调度),这时锁超时释放,线程2获取到锁执行业务,但是后面又被线程1删除。
解决方式:Redis提供了Lua脚本功能,在一个脚本中编写多条Redis命令,确保多条命令执行时的原子性。