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任务执行的管理等。这里主要介绍的还是悲观锁,在某些场景也可以使用乐观锁进行优化。

  • 相关阅读:
    【七款炫酷的页面特效】
    【PHP环境-WampServer踩坑】
    【Elasticsearch在winodws系统启动报could not find java+闪退】
    【Vue-入门笔记-7】
    关于ios的光标和键盘回弹问题
    AES加密然后ajax传输数据
    文件进行MD5计算
    jqGrid 常用 总结 -2
    关于页面传参,decodeURI和decodeURIComponent
    js防抖和节流
  • 原文地址:https://www.cnblogs.com/resentment/p/5945459.html
Copyright © 2011-2022 走看看