分布式锁redis及zookeeper实现区别

基本要求:

  1. 互斥性。在任意时刻,只有一个客户端能持有锁。
  2. 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
  3. 具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
  4. 解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。

Redis --Jedis实现

  1. jedis.set(lockKey, lockId, “NX”,“PX”, 15000)。格式 - String set(String
    key, String value, String nxxx, String expx, long time); 功能 -
    存储数据到缓存中,并制定过期时间和当Key存在时是否覆盖。参数 - key :redis key value :redis值
    nxxx:只能取NX或者XX,如果取NX,则只有当key不存在是才进行set,如果取XX,则只有当key已经存在时才进行set
    expx:只能取EX或者PX,代表数据过期时间的单位,EX代表秒,PX代表毫秒。time:过期时间,单位是expx所代表的单位。
  2. String script = “if redis.call(‘get’, KEYS[1]) == ARGV[1] then
    return redis.call(‘del’, KEYS[1]) else return 0 end”; Object result
    = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
    用一个Lua代码执行解锁,保证了命令的原子性。该命令执行时会检查锁的value是否和解锁传的id一致,相同才能完成解锁,即删除key。
  3. 高并发优化思路:对锁的资源进行拆分加锁。比如限制库存超卖,把1000库存锁改为10个100库存,每次对其中的100个库存进行加锁和释放锁,这样可以提高并发性能,这种方法需要在其中一个库存组返回库存不够时释放锁,并对其他库存组再次进行加锁操作,保证1000个库存都卖光。
  4. 此方式有个弊端,若加锁设置过期时间为10s,但是业务处理时间超过10s时,redis会主动释放锁,此时可能由其他线程获取锁并进行业务操作,这样会造成业务逻辑错乱。
  5. 推荐使用Redisson框架,所有的指令都是通过Lua脚本执行,保证了命令的原子性,并且有Watchdog存在,他会在获取锁之后每隔10s延迟当前锁的过期时间,保证持有锁的线程能在完成业务逻辑之后才释放锁。即使宕机,Watchdog也就没了,超过了过期时间会自动释放锁。

zookeeper --curator框架

  1. 通过在zookeeper里其中一个节点作为锁节点,创建临时顺序节点来实现。

  2. 客户端A先在锁节点下创建一个临时顺序节点,节点名类似于xxxx-00001最后的数字是依次顺序递增的,创建成功后会查询这个锁节点下所有的子节点,然后判断子节点集合里的第一个节点是否为自己创建的这个,如果是的话则说明可以进行加锁,客户端A加锁成功。

  3. 在客户端A加锁成功,且并未释放锁期间,客户端B尝试加锁,也在这个锁节点下创建一个临时顺序节点,节点名类似于xxxx-00002,并获取当前锁节点下的所有子节点,发现第一个子节点并不是自己创建的,此时,客户端B会通过zk的api对自己节点的上一个顺序子节点添加一个监听器。

  4. 客户端A在执行完逻辑后进行解锁,即把自己创建的这个xxxx-00001临时顺序节点给删除,节点被删除会触发监听器,zk会通知监听这个节点的客户端B锁已被释放。

  5. 此时客户端B会再次获取锁节点下所有的子节点,并判断第一个顺序节点是否为自己创建的,是则进行加锁成功,执行逻辑后再释放锁。

  6. 使用临时顺序节点的另外一个用意是,当客户端创建了临时顺序节点后不小心自己宕机了,zk会自动感知到这个客户端已宕机,会自动删除这个临时顺序节点,相当于自动释放锁。

redis和zookeeper的优劣

  1. redis方式其他线程竞争锁资源时,会不断尝试进行加锁,比较消耗性能。而zookeeper方式通过监听器,只有在其他线程释放锁之后才会再次尝试进行加锁。
  2. redis方式在某些极端情况下加锁解锁可能会出现问题。
  3. zookeeper方式若有较多客户端进行加锁,对zk的leader压力会比较大。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值