1.redis分布式锁(redLock)
删除key的时候要用lua脚本去删除,lua脚本删除的时候会比对key的value值是否是自己的值,否则会导致误删除(某个锁超时之后去del锁就会出错)
这种锁会出现问题,如果是单点,就会单点故障;如果主从结构,主节点挂了,key还没有同步到从节点,此时从节点切换到主节点,别人就会拿到锁,由于锁没有同步过来,锁就会失效掉!(redlock怎么解决这个问题的?)
Redlock的解决方案:
去加锁,只要一半以上的redis加锁成功 就算成功,有一个超时时间,在超时时间内加锁成功的才算加锁成功
其实是规避了之前的问题,之前只要一个挂了就完蛋,这里由于是集群,挂了一两个还是可以加锁成功的! (这里还可以再看看! 具体redlock)
这块加锁很麻烦!!业界很少用这种!
2.zookeeper分布式锁
当一个系统没有获取到锁的时候,会对这个锁注册一个监听器,当另外一个锁释放之后,zookeeper会把锁释放的情况反向推送给它! 这个时候系统可以获得这把锁,感知到锁被释放之后会尝试重新去获取锁,如果还没有,就继续注册监听器!! 不需要每秒轮询 去反复尝试
其实原理是 创建一个临时节点,为什么是临时节点,如果系统挂掉了,那么不释放的话 就会死锁,永远占用
另外一个系统去尝试创建同名的临时节点,如果没有创建成功 那么就注册一个监听器,当释放掉节点以后,zookeeper就会通知系统,然后系统再次尝试去获取锁,也就是尝试去创建临时节点
zookeeper分布式锁大概思路 思想: 如果没有获取到锁,循环,注册一个监听器,判断监听器是否存在,利用countdownlatch 卡住,等待zookeeper监听器发现节点是否删除,判断是否是自己监听的节点,来唤醒countdownlatch ,不卡住的话,继续执行,然后再次尝试去获取锁
更好的实现:基于zookeeper的临时顺序节点去实现的,不需要用while true 更加优雅
想要获取锁的客户端创建临时节点,并且进行排序,000 001 002 003 这种,然后对创建的临时节点按照lockroot 这个要上锁的对象的子节点 ,进行排序,然后判断如果是最小的节点,就可以获得锁; lock.get(0),如果不是最小的节点,那么就去找比他小1的那个节点,然后等待这个节点释放锁,后面的等前面的释放锁; 这个等待释放锁的函数: 注册监听器判断前一个节点监听器是否存在, 如果持有锁的那个人释放了锁 删除节点,就会调用通知 然后去尝试获取锁
3.redis分布式锁和zookeeper分布式锁的对比
redis分布式锁需要集群,比较麻烦,需要不断去尝试获取锁,比较消耗性能
zookeeper分布式锁,获取不到锁的话,不需要主动去尝试,性能开销较小
另外一点就是redis获取锁的客户端如果挂了,需要等待超时时间之后释放锁,但是zookeeper分布式锁挂了,是临时节点,可以自动释放锁
redis锁需要遍历上锁,计算超时时间 很麻烦 zookeeper分布式锁比较简
单,模型简单易用