分布式锁
1、在分布式系统环境下,一个办法在同一时间只能被一个机器的一个线程执行
2、高可用的获取锁与开释锁
3、高性能的获取锁与开释锁
4、具备可重入个性(可了解为从新进入,由多于一个工作并发应用,而不用放心数据谬误)
5、具备锁生效机制,避免死锁
6、具备非阻塞锁个性,即没有获取到锁将间接返回获取锁失败
基于zookeeper的分布式锁
1.zookeeper的一些个性
- 有序节点:如果以后有一个父节点为/lock,咱们能够在这个父节点上面创立子节点;zookeeper提供了一个可选的有序个性,例如咱们能够创立子节点“
/lock/node-
”并且指明有序,那么zookeeper在生成子节点时会依据以后的子节点数量主动增加整数序号,也就是说如果是第一个创立的子节点,那么生成的子节点为/lock/node-0000000000
,下一个节点则为/lock/node-0000000001
,顺次类推。 - 长期节点:客户端能够建设一个长期节点,在会话完结或者会话超时后,zookeeper会主动删除该节点。
- 事件监听:在读取数据时,咱们能够同时对节点设置事件监听,当节点数据或构造变动时,zookeeper会告诉客户端。以后zookeeper有如下四种事件:
1.节点创立;
2.节点删除;
3.节点数据批改;
4.子节点变更。
2.实现
①客户端连贯zookeeper,并在/lock下创立长期的且有序的子节点,第一个客户端对应的子节点为/lock/lock-1,第二个为/lock/lock-2,以此类推。
②客户端获取/lock下的子节点列表,判断本人创立的子节点是否为以后子节点列表中序号最小的子节点,如果是则认为取得锁,否则监听/lock的子节点变更音讯,取得子节点变更告诉后反复此步骤直至取得锁;
③执行业务代码;
④实现业务流程后,删除对应的子节点开释锁。
基于curator的zookeeper分布式锁实现
public static void main(String[] args) throws Exception { //创立zookeeper的客户端 RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3); CuratorFramework client = CuratorFrameworkFactory.newClient("10.21.41.181:2181,10.21.42.47:2181,10.21.49.252:2181", retryPolicy); client.start(); //创立分布式锁, 锁空间的根节点门路为/curator/lock InterProcessMutex mutex = new InterProcessMutex(client, "/curator/lock"); mutex.acquire(); //取得了锁, 进行业务流程 System.out.println("Enter mutex"); //实现业务流程, 开释锁 mutex.release(); //敞开客户端 client.close(); }
基于redis的分布式锁
1.流程
1、服务A为了取得锁,向Redis发动如下命令: SET productId:lock 0xx9p03001 NX PX 30000
其中,"productId"由本人定义,能够是与本次业务无关的id,"0xx9p03001"是一串随机值,必须保障全局惟一(起因在后文中会提到),“NX"指的是当且仅当key(也就是案例中的"productId:lock”)在Redis中不存在时,返回执行胜利,否则执行失败。"PX 30000"指的是在30秒后,key将被主动删除。执行命令后返回胜利,表明服务胜利的取得了锁。
2、服务B为了取得锁,向Redis发动同样的命令: SET productId:lock 0000111 NX PX 30000
因为Redis内曾经存在同名key,且并未过期,因而命令执行失败,服务B未能取得锁。服务B进入循环申请状态,比方每隔1秒钟(自行设置)向Redis发送申请,直到执行胜利并取得锁。
3、服务A的业务代码执行时长超过了30秒,导致key超时,因而Redis主动删除了key。此时服务B再次发送命令执行胜利,假如本次申请中设置的value值为0000222。
4、服务A执行结束,为了开释锁,服务A会被动向Redis发动删除key的申请。
2.实现
①加锁
客户端集成Redisson,在加锁之前,首先须要通过hash算法选定集群内某一个Redis Master,后续加锁、解锁等各种过程都是在这个Redis Master和与之绑定的slave节点之间。
②执行lua脚本实现加锁
③watch dog主动延期
watch dog是一个后盾线程,它会每隔10秒察看以后客户端是否依然持有锁,如果持有,阐明客户端可能依然在应用锁,因而缩短锁的残余生存工夫。
④开释锁机制
如果执行lock.unlock(),Redis会找到上方test数据结构,将加锁次数减一。如果减完后发现加锁次数为0,则阐明以后客户端不再持有锁,因而执行: del test命令, 从Redis中删除这条key。
// 筹备为名为"test"的key加锁RLock lock = redisson.getLock("test");// 加锁lock.lock();// 解锁lock.unlock();