zoukankan      html  css  js  c++  java
  • 全局锁实现

    全局锁

    在系统访问单个资源时或多或少都会要使用到锁,如Java的Lock等,但多个系统访问资源,或在集群中各个实例需要访问资源时,就需要建立全局的锁,这里讲三种全局锁的方法。

    数据库

    利用ACID

    使用关系型数据库的ACID可以创建一个锁

    UPDATE LOCKTABLE SET INSTANCE=<instance_name> WHERE RESOURCE=XXXX AND INSTANCE IS NULL;
    

    当返回更新了相应记录后就代表获得了锁
    对应的可以使用以下sql来释放获得的锁

    UPDATE LOCKTABLE SET INSTANCE='' WHERE RESOURCE=XXXX AND INSTANCE=<instance_name>;
    

    上面的方法看上去很好,但是当获得锁的实例宕机那么这个锁就一直被占用着

    利用行锁

    为了解决实例非正常退出而没有释放锁可以使用数据库(ORACLE)的行锁

    SELECT 1 FROM LOCKTABLE WHERE RESOURCE=XXXX FOR UPDATE;
    

    这样在commit/rollback之前就能持有这个锁,如果调用方断开,数据库也会自动rollback。可以使用NOWAIT+循环查询的方式防止阻塞

    REDIS

    数据库固然可以,但应对大量的资源需要长期持有大量锁也不是很恰当,下面看下Redis如何创建全局锁

    SETNX

    SETNX是set if not exist的缩写,也就是当值不存在时再进行赋值

    SETNX lock.resource 1
    //hold the lock
    DEL lock.resource
    

    以上伪代码简单演示了如何获得锁和释放锁,和数据库的方法一样,这种方法同同样存在实例宕机的风险导致死锁

    SET

    可惜Redis上没有像数据库中的for update。一个替代方法是使用expire。即给锁设定一个超时时间,如果时间超过自动释放锁,这里超时时间要合适不能过长让其他实例空等,也不能过短实例没有结束就自动释放了。
    幸运的是Redis 2.6.12之后SET命令可以使用expire和notexist

    SET lock.resource <instance_name> NX EX timeout
    //hold the lock
    WATCH lock.resource
    GET lock.resource
    MULTI
    if(getResult==<instance_name>)
    	DEL lock.resource
    EXEC
    

    使用watch/multi确保竞态条件

    RedLock

    防止单Redis不可用,可以使用多个redis,在半数以上节点获得锁的情况下代表获得锁,否则就释放所有获得的锁。

    Redison

    如果不想自己造轮子,已经有现成的类库可以使用Redis创建全局锁了
    Redison封装了锁的实现,提供可重入的锁的一系列实现,可以方便地使用
    https://github.com/redisson/redisson/wiki/8.-Distributed-locks-and-synchronizers

    Zookeeper

    redis的不足就是只能通过expire来控制锁持有者失联的情况。
    zookeeper在这方面就有一定的优势,再加上zookeeper天生自带集群,在可靠性上优于redis
    zookeeper可以创建ephemeral节点,当客户端断开连接节点自动删除,可以创建一个节点,最小值持有当前锁

    create -e -s /LOCK/RESOURCE/REQUEST 1
    

    之后判断如果当前节点最小就获得锁,如果没有就在前一个节点上加watch,在watch中再进行判断,这样就实现了等待获得锁的队列。

    总结

    全局锁在集群上的应用有不少,最常见的就如集群内CRON任务执行的管理等。这里主要介绍的还是悲观锁,在某些场景也可以使用乐观锁进行优化。

  • 相关阅读:
    解决PKIX:unable to find valid certification path to requested target 的问题
    Linux 上的常用文件传输方式介绍与比较
    用VNC远程图形化连接Linux桌面的配置方法
    红帽中出现”This system is not registered with RHN”的解决方案
    linux安装时出现your cpu does not support long mode的解决方法
    CentOS SSH配置
    es6扩展运算符及rest运算符总结
    es6解构赋值总结
    tortoisegit安装、clon、推送
    es6环境搭建
  • 原文地址:https://www.cnblogs.com/resentment/p/5945459.html
Copyright © 2011-2022 走看看