分布式锁

1.什么是分布式锁

  分布式锁是控制分布式系统之间访问共享资源的一种方式。

  在分布式系统中,常常需要协调他们的动作,如果不同的系统/服务/应用程序访问了同一个或一组资源,

  那么在访问这些资源的时候,需要使用互斥防止彼此产生干扰来保证数据一致性,那么就需要使用分布式锁。

  

  下图是分布式的一种场景,但是没有体现临界资源的概念,本人比较懒,直接摘抄原图。

  下面JVM1,JVM2,JVm3实际指向同一个临界资源(举例:数据库),三个进程需要更新同一份数据,那么需要控制并发问题

  

   

2.分布式锁的特性

  互斥:一个临界资源同一时间只能被一个线程执行

  可重入:已经获取锁的人(尚未释放),可多次重新获取

  失效机制:锁需要有一定的有效期,避免因为获取到锁的服务进程奔溃导致锁无法释放

  非阻塞:获取锁成功或者失败,都立马返回,不阻塞(在有些场景下,获取不到锁的人,就不需要干活了,所以不应该阻塞)

  高可用、高性能的获取锁和释放锁

3.分布式锁的实现方案列举

  

  

 4.基于数据库的实现

  悲观锁:直接使用某个临界资源表,获取锁的时候调用select ... for update来获取锁,其它竞争服务获取不到锁会阻塞等待,效果不好

  乐观锁:新建临界资源表,每条锁对应一个记录,每条记录有一个版本号,更新数据时判断版本号是否和自己预期一致

5.基于zookeeper的实现

 基本思想:各服务进程在某个锁下创建临时、有序节点, 同时注册watch监听事件

  节点名最小的服务获取到锁

  使用完锁时删除节点,后面的节点因为注册了watch监听事件,所以可以收到通知,下一个节点获取到锁

  如果使用锁的过程中,进程崩溃,由于使用的是临时节点,zookeeper感知到进程退出后,会删除临时节点,后面的节点会收到通知

  

 6.基于redis的实现

  使用setnx竞争设置一个key,拿到key的人表示获取到了锁(setnx就是没有则设置)(互斥)

  获取锁的同时需要增加超时时间设置,避免自己奔溃后,锁无法释放(这两步需要是原子操作)(失效机制)

  使用锁的过程中,需要进行锁的保活,因为redis中key的超时时间是固定的,但是执行时间不固定的,避免key过期,其它进程同时获取到锁

  释放锁的时候,需要检查这个key对应的值是否是自己,避免因为自己的锁失效(下一个人已经获取到锁),导致后面连锁反应,全部人都获取到锁

7.Redlock(红锁)

  redlock是集群模式的redis分布式锁,它基于集群中n个的redis节点进行加锁。

  主要是因为redis集群的数据一致性实时性相对较差,在一个节点上写成功的数据,其它节点不一定能看到,所以集群模式下,不能单独的锁一台redis实例。 

  备注:zookeeper不需要,是因为zk是基于CP原则实现的,而且是顺序节点,那么客户端要么看不到,要么看到的是正确数据

  1.客户端获取当前时间,以毫秒为单位

  2.客户端尝试获取n个节点的锁,每个节点获取锁的方式同上面单机redis

  3.客户端计算计算在获取锁的过程中总共花费时间,时间小于超时时间且获得了半数以上的锁,则获取锁成功

  4.更新锁的超时时间(预定义超时时间-获取锁的时间)

  5.如果获取锁失败,则删除所有的锁

参考文档:

  https://www.jianshu.com/p/a1ebab8ce78a

  https://www.cnblogs.com/ldws/p/12155003.html

  

原文地址:https://www.cnblogs.com/gc65/p/12774218.html