锁以及分布式锁

一、分布式锁 须要知足的要求

  1)、排他性:同一时间只会有一个客户端能获取到锁,其余客户端同时不能获取;java

  2)、避免死锁:锁在一段时间后必定会被释放;web

  3)、高可用:获取或释放锁的机制必须高可用且性能佳。redis

  实现方式:
    a、基于数据库实现 基于数据库的乐观锁:在数据库表中引入一个版本号字段。在修改数据的时候,版本号同时改变。另外一我的去修改的同时,对比版本号,不一致,则操做不成功。则从新操做。 基于数据库的悲观锁:MySQL中基于for update实现,排它锁;算法

    b、基于Redis实现 主要是依赖Redis自身的原子操做:set user_key user_value NX PX 100 ,解锁就是删除该key。 当key不存在才会执行成功,当多个进程同时并发设置一个key,只有一个进程成功。 针对redis集群模式的分布式锁,能够采用redis的redlock机制;spring

    c、基于ZooKeeper实现 使用临时有序节点来实现分布式锁 具体实现还得看其余文章,这只是个大概讲解。数据库

二、非公平锁

  在加锁过程,线程1运行,线程2处于等待队列。 线程1运行结束,结果线程3抢先于线程2进行。这就是非公平锁的简单含义。架构

  在ReentrantLock lock = new ReentrantLock()默认的就是非公平锁,构造函数中加入true:ReentrantLock lock = new ReentrantLock(true)。并发

  公平锁原则就是线程3就绪后,会先查看等待队列是否有线程,有就排队。框架

三、Redis分布式锁的底层原理

  Redis锁引入Redisson(一个开源框架)的依赖异步

  代码: Rlock lock = redisson.getLocl(”myLock“): 加锁:lock.lock(); 解锁lock.unlock();

  实现原理:

    1)、加锁机制:若是某个客户端要加锁,面对的是redis集群,首先会根据hash几点选择一台机器。而后发送一段lua脚本到redis上,脚本中的KEYS[1]表明加锁的key,ARGV[1]表明锁默认生存时间30秒,ARGV[2]表明客户端ID;

    2)、锁互斥机制:当客户端1访问,加锁。客户端2访问,key已经存在,会获得一个锁的剩余时间。而后进入一个while循环,不短尝试加锁。等客户端1锁释放,客户端2就会加锁;

    3)、watch dog 自动延期机制:加锁时间超过30秒,客户端1还想继续持有这把锁,那就启动watch dog看门狗,是一个后台线程,每隔10秒检查1下,若是客户端1还持有锁,就会不断延长锁key的生存时间;

    4)、可重入加锁机制:若是客户端1都已经持有这把锁,结果可重入的加锁。此时就会对客户端1的加锁次数+1;

    5)、释放锁机制:lock.unlock()是对锁数据的加锁次数-1,发现是0的时候即客户端1再也不持有这把锁。客户端2此时就能够加锁了。

  在集群状况下,机器A申请到了锁L,结果A宕机,并无同步到集群的其余机器上,可能机器B也会申请到锁L。 因此提出了红锁(RedLock)的算法:

    1)、首先生成集群中多个机器的RLock,并将其构建成RedLock;

    2)、一次对三个集群加锁,过程和普通Redis加锁一致;

    3)、若是循环加锁失败,判断失败数是否小于集群数N/2,必须保证失败数小于集群数N/2;

    4)、另外锁超时是全部的锁时间相加,若是超时时间5ms,集群1已经5ms,则加锁失败;

    5)、三、4步失败的话,就会进行解锁操做。

  缺点:

    集群状况下,对某个redis master实例,写入myLock这种锁key的value,会异步复制给对应的master slave。当master宕机,主备切换,redis slave变成redis master,会致使客户端2来加锁的时候在新的客户端上完成加锁(加锁针对1台机器),客户端1也进行了加锁。 就会多个客户端对一个分布式锁进行加锁,产生脏数据。

四、ZooKeeper分布式锁的实现原理

  多个客户端(线程)争抢一个zk分布式锁:

    1)、因此线程都会建立一个锁节点下的一个接一个的顺序节点,按照请求时间设置一个字段排序;

    2)、当访问到zk的锁节点时候,本身是第一顺序位,就加锁。 若是本身不是第一顺序位,就对上一个顺序位的节点加监听器;

    3)、只要监听到上一个节点释放了锁,本身就排序到前一个顺序位了。

  其实就是一个排队机制。

参考:纯洁的微笑、石杉的架构笔记、java版web项目、架构师之路、springForAll社区等公众号。