在分布式系统中,分布式锁就是为了解决多实例之间的同步问题。比如master选举,能够获得分布式锁的就是master,没有获得锁的就是slave。或者可以获取锁的实例可以执行特定操作。目前常用的分布式锁实现有两种,基于zookeeper和redis。Zookeeper和redis也是生产环境中经常使用的第三方组件。下面我就来分析一下它们的实现原理。分布式锁的实现要求一把分布式锁至少要满足以下三个要求:互斥,同一把锁在任何时候只能由一个客户端持有。不会出现死锁,即使持有的客户端异常崩溃,也不会影响后续的客户端锁。谁加锁谁解锁,加锁和解锁必须是同一个客户端。Zookeeper分布式锁在讲解zookeeper的分布式锁之前,有两个概念需要明确一下:临时节点:生命周期与链接周期一致。例如,客户端链接A创建了一个临时节点NodeA。如果链路A关闭或者网络异常断开,NodeA也会消失。顺序节点:节点名按升序创建,比如先创建000000001,那么下一个创建的节点会分配000000002。zookeeper分布式锁的实现原理是使用临时顺序节点。大致过程如下:当每个客户端锁定某个函数时,在zookeeper指定的目录下生成一个唯一的临时顺序节点。所有临时节点中序号最小的节点为当前锁持有者。释放锁时,删除自己持有的临时节点。例如,对于锁定过程,所有客户端都会在/lock目录下创建临时节点。如果他们发现自己创建的临时节点是/lock目录下的最小节点,那么就成功获取锁,否则watch比自己小。节点中最大的节点。监控比自己小的节点中最大的节点,目的是为了避免“惊群”效应,避免一次锁释放唤醒所有等待的客户端,却只有一个客户端能获取到锁。释放锁只需要删除自己创建的临时序列节点即可。整个流程流程图如下:优点:锁安全性高,zookeeper数据不易丢失。用户易于使用。缺点:性能消耗大。因为临时节点需要动态生成和删除,当集群负载比较高的时候,临时节点消失会有一个时间差(一般在一分钟以内)。Redis分布式锁Redis分布式锁实现比zookeeper分布式锁实现要复杂一些,也分为redis单实例和多实例(master-master)实现。需要指出的是,如果redis采用主从结构部署,锁的获取和释放只能向master请求,这与单实例的实现原理基本一致。不然主从切换的时候,会多人拿到同一个锁。锁盒。例如:ClientA获得了master的锁。主节点在将A创建的密钥写入从节点之前宕机了。(主从同步是一种异步操作)从节点成为主节点。B也得到了A仍然持有的同一个锁,因为slave没有关于A持有锁的信息。redis单实例实现方案通过以下命令获取锁:SETresource_namemy_random_valueNXPX30000该命令的作用是只有当key不存在时才设置这个key的值(NX的功能,即不存在)存在),超时时间设置为30000毫秒(PX的作用),这个key的值设置为my_random_value。该值在所有请求锁定的客户端中必须是唯一的。键值的超时时间也称为“锁定有效时间”。这是锁的自动释放时间。本实施方案适用于非分布式、单点、保证永不停机的环境。Redis集群实现方案(Redlock算法)在分布式版本的算法中,我们假设有N个redis主节点。这些节点是完全独立的,不需要任何复制或分布式协调算法来同步数据。假设这里N=5,客户端获取锁的流程如下:获取当前时间,单位毫秒。轮询请求用相同的密钥在N个节点上加锁。(每次请求的超时时间设置得更短,以便当一个master节点不用时,快速请求下一个master)。如果超过半数的主节点成功获取锁(此处为3个),则客户端计算第二步请求锁所花费的时间。如果小于锁释放时间,则认为加锁成功。如果获取锁成功,那么现在自动释放锁的时间=初始锁释放时间-请求锁所花费的时间。最后会释放每个主节点上的锁。成功获取锁的节点数需要超过master节点数的一半才算成功。成功获取锁的思路应该是基于zookeeper的paxos算法。还有一点需要指出的是,当一个client获取失败时,应该随时延迟再重试,避免多个client同时重试失败。优点:高性能缺点:单实例会存在单点问题,多实例主从切换会造成数据丢失,主从集群模式实现复杂。看老大给大家讲解一下基于Zookeeper和Redis的分布式锁
