zoukankan      html  css  js  c++  java
  • 分布式锁

    摘自:

    https://www.cnblogs.com/seesun2012/p/9214653.html

    一、分布式

    1、CAP理论

    任何一个分布式系统都无法同时满足一致性(Consistency)、可用性(Availability)、分期容错性(Partition tolerance)最多同时只能满足两项。

    2、分布式

    • 分布式不是多线程,而是多进程
    • 多线程可以共享堆内存,将标记直接存储在内存就可以实现锁。而分布式运行的各个进程很有可能分布在不同的机器上。因此需要将标记存储在所有进程都能看到的地方。

    二、分布式锁

    • 当在分布式模型下,数据只有一份,因此需要利用锁技术控制对数据修改的进程数。
    • 锁要保证进程之间可见,还要考虑网络之间的问题。
    • 分布式锁可以将标记存在内存,但是内存是进程共享的内从,集群环境,例如Redis。还可以利用数据库,保证标记能互斥就可以。

    三、需要的分布式锁

    • 在分布式部署的应用集群环境中,同一个方法在同一时刻只能被一台机器中的一个线程调用。
    • 这把锁是一把可重入锁(避免死锁)
    • 有高可用的获取锁和释放锁功能
    • 获取锁和释放锁的性能要好

    四、基于数据库的分布式锁

    思路:利用主键唯一的特性,如果有多个请求同时提交到数据库的话,数据库会保证只有一个操作可以成功,那么我们就可以认为操作成功的那个线程获得了该方法的锁,当方法执行完毕之后,想要释放锁的话,删除这条数据库记录即可。

    上面这种简单的实现有以下几个问题:

    • 这把锁强依赖数据库的可用性,如果数据库是单点的,那么一旦数据库挂掉,会导致业务系统不可用
    • 这把锁没有失效时间,一旦解锁操作失败,就会导致锁记录一直在数据库中,其它线程无法再获取该锁
    • 这把锁是非阻赛的,一旦insert失败就会报错
    • 这把锁是非重入的,同一个线程在没有释放锁之前,无法获得该锁。
    • 非公平锁
    • 采用主键防重,在大并发情况下会造成锁表的情况。

    上述问题的解决:

    • 增加备用数据库,一旦一个挂了就立即切换
    • 对于没有失效时间的问题,用定时任务清理超时数据
    • 非阻塞的,用while循环直到insert成功
    • 非重入的,增加字段,记录主机信息和线程信息,如果主机信息和线程信息在下一次操作可以查到,那么就直接分配
    • 非公平的,再建一张中间表,将等待锁的线程全部记录下来,并根据创建时间排序,先创建的先获取锁
    • 最后一个问题,解决办法是在程序执行过程中生产主键。

    五、基于Redis做分布式锁

    1、基于setnx(),expire()法

    • setnx(key, value),set if not exists,该方法是原子的。如果key不存在,则当前key设置成功,返回1。如果当前key已经存在,则设置当前key失败,返回0。
    • expire(),设置过期时间

    setnx()如果返回0则返回占位失败,如果返回1则占位失败。

    expire()命令对lockkey设置超时时间,为的是避免死锁行为

    执行完业务代码后可以通过delete来删除。

    该方法存在死锁问题

    2、setnx(),get(),getset()法

    为了解决死锁问题,新方法

    • setnx(lockkey, 当前时间+过期时间),1则获取锁成功,0则没有获取锁,转为2。
    • get(lockkey)获取值oldExpireTime,并将这个value值与当前的系统时间进行比较,如果小于当前系统时间,则认为这个锁已经超时,可以允许别的请求重新获取,转为3
    • 计算newExpireTime = 当前时间 + 过期时间,然后getset(lockkey, newExpireTime)会返回当前lockkey的值currentExpireTime
    • 判断currentExpireTime与oldExpireTime是否相等,如果相等,说明当前getset()设置成功,获取了锁。如果不等,说明这个锁又被别的请求获取走了,那么当前请求可以直接返回失败,或者继续重试。
    • 在获取锁之后,当前线程可以开始自己的业务处理,当处理完毕后,比较自己的处理时间和对于锁设置的超时时间,如果小于锁设置的超时时间,则直接执行delete释放锁;如果大于锁设置的超时时间,则不需要再对锁进行处理
    谢谢!
  • 相关阅读:
    2021软件工程-个人阅读作业
    OO第四单元——基于UML的UML解析器总结&OO课程总结
    OO第三单元——基于JML的社交网络总结
    OO第二单元——电梯作业总结
    SQL拼接字符串
    SQL查询列表中每种类型的第一条
    JS获取当前时间,设置不可用以前的时间
    JavaScript中的函数使用
    .Net软件开发面试技巧
    .Net小白的第一篇博客
  • 原文地址:https://www.cnblogs.com/ylxn/p/10356422.html
Copyright © 2011-2022 走看看