如下内容为目前本身理解的总结,若有错误请你们指正。java
在单进程的系统中,当存在多个线程能够同时改变某个变量(可变共享变量)时,就须要对变量或代码块作同步,使其在修改这种变量时可以线性执行消除并发修改变量。node
而同步的本质是经过锁来实现的。为了实现多个线程在一个时刻同一个代码块只能有一个线程可执行,那么须要在某个地方作个标记,这个标记必须每一个线程都能看到,当标记不存在时能够设置该标记,其他后续线程发现已经有标记了则等待拥有标记的线程结束同步代码块取消标记后再去尝试设置标记。这个标记能够理解为锁。linux
除了利用内存数据作锁其实任何互斥的都能作锁(只考虑互斥状况),如流水表中流水号与时间结合作幂等校验能够看做是一个不会释放的锁,或者使用某个文件是否存在做为锁等。只须要知足在对标记进行修改能保证原子性和内存可见性便可。redis
此处主要指集群模式下,多个相同服务同时开启.数据库
与单机模式下的锁不只须要保证进程可见,还须要考虑进程与锁之间的网络问题。(我以为分布式状况下之因此问题变得复杂,主要就是须要考虑到网络的延时和不可靠。。。一个大坑)安全
分布式锁仍是能够将标记存在内存,只是该内存不是某个进程分配的内存而是公共内存如Redis、Memcache。至于利用数据库、文件等作锁与单机的实现是同样的,只要保证标记能互斥就行。服务器
1. 直接调用Lua脚本原子setnx同时expire,设置一个随机值。 2. 获取到锁则执行同步代码块,没获取则根据业务场景能够选择自旋、休眠、或作一个等待队列等拥有锁进程来唤醒(相似Synchronize的同步队列)。 3. 当同步代码块执行完成,先判断锁的key是不是本身设置的,若是是则删除key(可利用Lua作成原子操做),不是则代表本身的锁已通过期,不须要删除。(这时候就出现了多进程同时有锁的问题了)
通常状况下直接用setnx加expire就够了,但从安全性的角度看仍是存在一下几个问题:网络
Redlock是Redis的做者antirez给出的集群模式的Redis分布式锁,它基于N个彻底独立的Redis节点(一般状况下N能够设置成5)。多线程
1. 获取当前时间(毫秒数)。 2. 按顺序依次向N个Redis节点执行获取锁的操做。获取锁的操做与单机锁同样。 3. 若是获取锁成功的节点数>=N/2+1,则再计算获取锁的时间有没有超过锁过时时间(可考虑设置一个必须留多长的时间给代码块执行),若是超过了则认为取锁失败。 4. 若是取锁失败则应该对全部节点进行释放锁的操做。
原理:利用临时节点与watch机制。每一个锁占用一个普通节点/lock,当须要获取锁时在/lock下建立一个临时节点,建立成功则表示获取锁成功,失败则watch/lock节点,有删除操做后再去争锁。临时节点好处在于当进程挂掉后能自动上锁的节点自动删除即取消锁。并发
缺点:全部取锁失败的进程都监听父节点,很容易发生羊群效应,即当释放锁后全部等待进程一块儿来建立节点,并发量很大。
原理:上锁改成建立临时有序节点,每一个上锁的节点均能建立节点成功,知识其序号不一样。只有序号最小的能够拥有锁,当须要不是最小的则watch序号排在前面的一个节点(公平锁)。
步骤:
1. 在/lock节点下建立一个有序临时节点(EPHEMERAL_SEQUENTIAL)。 2. 判断建立的节点序号是否最小,若是是最小则获取锁成功。不是则取锁失败,而后watch序号比自己小的前一个节点。 3. 当取锁失败,设置watch后则等待watch事件到来后,再次判断是否序号最小。 4. 取锁成功则执行代码,最后删除自己节点,释放了锁。
目前就这些了。。。。后面想到再补充吧。
引用:基于Redis的分布式锁真的安全吗?
基于Redis的分布式锁真的安全吗?上
基于Redis的分布式锁真的安全吗?下