分布式锁(redis和zookeeper)

zookerper分布式锁

zk实现分布式锁原理:使用zk临时节点(连接断开后就会删除) +事件通知(wacther)

a)使用zk创建临时节点
b)哪个服务器能创建节点成功,相当于就拿到锁,用完之后关闭zk连接就会自动删除节点(释放锁)
c)没拿到锁的服务器就等待,使用wacther监听节点(节点被删除就收到通知),收到节点删除通知就去获取锁的资源
这种方式
缺点:所有取锁失败的进程都监听父节点,很容易发生羊群效应(即当释放锁后所有等待进程一起来创建节点,并发量很大)。

ZK 锁优化(临时有序节点实现)

原理:上锁改为创建临时有序节点(01、02...),每个上锁的节点均能创建节点成功,只是其序号不同。只有序号最小的可以拥有锁,如果这个节点序号不是最小的则 watch监听序号比本身小的前一个节点,当请求释放锁时,只有被删除节点(01)的下一个节点(02)去获取 (其他节点相当于排队,公平锁)。
步骤:
1.在 /lock 节点下创建一个有序临时节点 (EPHEMERAL_SEQUENTIAL),zk会生成有序的节点。
2.判断创建的节点序号是否最小,如果是最小则获取锁成功。不是则取锁失败,然后其他节点 watch(监听) 序号比本身小的前一个节点。
3.当获取锁成功则执行代码,释放锁(删除该节点)后,下一个节点就会收到通知,然后去获取锁,其他排在后面的节点继续等待(公平锁)

如何避免zk客户端(使用分布式锁的服务)死锁问题

a)zkServer端宕机,一直接收不到watch删除节点的通知

1.获取锁等待时设置阻塞的超时时间
2.通过监听zk宕机之后,主动唤醒

b)zk客户端(使用锁的服务)宕机

zk先天性特性避免死锁问题,断开连接后主动释放锁(临时节点被删除)

c)获取到锁的jvm一直不释放锁

(类似于redis看门狗 watchdog)获取锁时记录锁信息(锁id,线程,事务,锁状态等),开始一个定时线程给锁续期,续期3次还没处理完业务,就主动释放锁,事务随之回滚

zookeeper锁的实现框架curator


redis分布式锁

redis实现分布式锁原理:使用setnx实现分布式锁

a)获取锁:多个jvm同时setnx,最终只有一个jvm成功
b)释放锁:删除该key(获取时value设置唯一id,删除时判断同一id才删除)

redis锁的实现框架redisson,解决续期等问题

a)获取锁:使用lua脚本创建hash key(记录线程,锁id等信息,value为1(实现可重入锁),默认锁时间30s
b)释放锁:删除该key
c)锁续命设计:注册监听watchdog(看门狗),默认每隔10s续期,重置锁的过期时间(默认30s),防止业务未执行完就过期,续期多次未释放锁就会主动释放

如何避免客户端死锁问题

a)设置过期key
b)限制续命次数,超过就主动释放锁并回滚事务

key过期了,但是业务还没有执行完毕如何处理

redisson实现了watchdog机制,获取锁后创建一个定时线程,默认每隔10s续期一次,重置锁的过期时间,续期3次就还未释放,就会主动释放锁,并回滚事务

redis集群,主节点宕机了如何处理?

因为redis使用ap,同步数据时是异步的,主节点挂了,从节点变成主节点,可能获取锁的key未同步过来,就会造成多个jvm获取到锁的情况
解决方案:

使用RedLock红锁算法(类似zk),实现原理
1.redis集群没有主从之分
2.客户端获取锁时对多个redis节点循环进行setnx操作,满足一半以上返回成功,是获取锁成功
3.注意循环对redis进行获取锁时,总耗时时间不能大于key的过期时间。如果耗时大于key的过期时间,返回获取锁失败,并删除之前创建成功的key

你可能感兴趣的:(分布式锁(redis和zookeeper))