分布式锁

分布式锁

使用Redis做分布式锁的思路大概是这样的:在redis中设置一个值表示加了锁,然后释放锁的时候就把这个key删除。

setnx lock:key true
del lock:key

若执行到中间出现异常,那么导致del指令调用不到,这样就会产生 死锁 现象

setnx lock:key true
expire lock:key 5
del lock:key

若setnx与expire中间挂了,也会导致同样得问题
使用redis事务解决,但是这里不行,因为expire是依赖setnx的,setnx没抢到锁,expire不应该执行,事务没有if分支逻辑

setnx和expire组合在一起的原子指令
set lock:key true ex 5 nx
del lock:key

不能解决超时问题

若在加锁和释放锁中间的执行逻辑太长,导致超出了锁的expire限制,就会出现线程安全问题。
解决方案:为set指令的value参数设置一个随机数,释放锁的时候先匹配随机数。这是为了保证当前线程占有的锁不会被其他线程释放
但是匹配value和删除value不是一个原子操作,这就需要Lua脚本处理。
但这也不是一个完美方案,若超时发生,当前线程逻辑未执行完,其他线程也会进行抢占的。

集群模式缺陷

在集群模式,客户端在主节点申请的锁还没有来得及同步到从节点,主节点就挂掉了,然后从节点编程了主节点。另一个客户端请求加锁也会成功,最后导致两个客户端同时获得了锁操作资源,引起线程安全问题。
这种不安全只在主从faileover情况发生,持续时间短,业务系统多数可以容忍

若希望绝对高可用,挂一台redis完全不受影响
解决方案:RedLock算法
需要多个redis实例,相互没有主从关系。 通过过半选举机制,加锁时,会向多redis实例发送set(key,value,nx=true,ex=xxx)指令 ,只要过半set成功,那就加锁成功。释放锁时,需要向所有节点发送del指令。
代价:需要多redis实例,性能也下降了,代码需要引入额外library

# delifequals
if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

ZooKeeper实现分布式锁

zookeeper是什么?

ZooKeeper是一个分布式的应用程序协调服务,提供可靠的、可扩展的、分布式的、可配置的协调服务来管理整个集群的状态。

zookeeper提供了什么?

1. 文件系统

四种节点类型:持久有序,持久无需,临时有序,临时无序

2. 通知机制

四种事件类型:节点创建事件,节点删除事件,节点修改事件,数据修改事件
客户端向服务端 注册一个watcher监听,当某事件触发这个监听,就会像客户端发送一个事件通知。

  1. 客户端向zk注册whatcher的同时,会将watcher对象存储在客户端的whatchManager中
    2.当zk触发watcher事件后,会向客户端发送通知
    3.客户端线程从管理者取出watcher对象执行回调逻辑

zookeeper的作用有哪些?

  1. 命名服务:通过路径的唯一性实现命名
  2. 集群配置服务:将集群节点的配置信息放到zk某节点上,所有节点都监听此节点,一旦收到数据改变通知,则应用新得配置数据。
  3. 集群管理服务:实现数据库节点出入检测,以及leader选举(创建临时顺序节点)
  4. 线程同步管理服务:实现分布式锁
  5. 数据订阅服务:订阅方监听被订阅方节点数据变化的事件
  • 临时节点:客户端连接时创建,客户端挂起的时候自动删除。
  • 节点类型:。。。。。。。。。。。只有持久化节点才可以创建子节点

zookeeper实现分布式锁,解决线程同步问题

  1. 首先创建持久化父节点/distribute_lock
  2. 当Client访问资源时,创建临时顺序节点,然后判断自己创建的子节点是否为当前子节点列表中最小的子节点,如果是则获取锁访问共享资源;否则监听父节点【变更事件】,当收到子节点变更通知后重复判断,直到获取锁。
  3. 当线程完成业务逻辑后,删除对应子节点释放锁

zookeeper实现分布式锁优化

在这里插入图片描述

  1. 创建临时节点:保证故障情况下也能释放锁,完美解决了redis实现分布式锁的劣势,包括业务执行时间过长超过锁的有效时间,包括集群宕机时发生线程安全问题。
  2. Client只监听比自己小的节点,以避免发生羊群效应
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值