分布式锁自己理解用

182 阅读2分钟

redis分布式锁

1.setnx和expire不是原子性。可能setnx之后,服务挂了,那么对象就一直被锁住了。因此得设置超时时间。用lua脚本将senx和expire结合起来。
2. redis2.16版本之后提供新的set参数 set key value nx px 3000,命令。
3. 分布式锁中,当任务结束或者碰见异常后需要将锁给释放。

  • 有这么一种情况A:请求a枷锁,枷锁时间3s。当业务处理时间超过3s后,锁自动释放。那么请求b也能拿到锁。此时a结束,将b锁释放。b处理完业务逻辑去释放锁发现锁不存在了。
  • 另或许情况B:请求a释放了请求b的锁。这时候请求c进来了,接着b释放了c的锁。导致分布式锁失效

    针对以上解决办法,延长锁时间,评估业务处理时间加上buffer。弊端是当异常情况,比如加锁后应用服务就重启了,锁需要等待一段时间才能自动释放。时间设置太短也不行。可以设置个while轮训,当时间超过预估设置时间三分之二时,重新赋值。
    4.为了避免释放别人锁的极端情况,可以对value进行判断。value赋加业务含义,如uuid之类的。删除key先比对value是否是自己的值。先判断key的value再删。这里也要用lua脚本保持原子性。

业界用的比较多的有redisson框架,这个底层用的redlock,封装了常用的操作。有时间再去看看这个源码,忘记了。面试感觉会问吗?啊啊啊啊。有时间更新到这文章里来额

zk锁

第二种实现分布式锁,是利用zookeeper的临时节点实现锁的先到先得,保证次序。
先建一个根节点永久节点比如order。接着在这个父节点下新建各个子节点。子节点按照新建的顺序序号依次增加。每次都取序号最小的节点进行加锁操作。后面监听前面的,当前一个节点操作完成后会通知后一个节点。于是后一个节点就会判断自身是否是序号最小的节点,是执行逻辑不是则继续等待。
这里为什么要设置临时节点,是因为一旦服务器节点实际删除或者和服务器断开连接,都会将这个临时节点移出。排在之后的节点也能收到删除事件。避免当一个节点退出时,所有节点都监听。只有后监听直接前面的。