Redis-5.0141 分布式锁-18


1. 问题描述

   
随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程的特点以及分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的 Java API 并不能提供分布式锁的能力。为了解决这个问题就需要一种跨 JVM 的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题!

2. 分布式锁主流的实现方案:

  • 基于数据库实现分布式锁

  • 基于缓存(Redis 等)

  • 基于 Zookeeper

   
根据实现方式,分布式锁还可以分为类 CAS 自旋式分布式锁以及 event 事件类型分布式锁:

  • 类 CAS 自旋式分布式锁:询问的方式,类似 java 并发编程中的线程获询问的方式尝试加锁,如 mysql、redis。

  • 另外一类是 event 事件通知进程后续锁的变化,轮询向外的过程,如 zookeeper、etcd。

每一种分布式锁解决方案都有各自的优缺点:

   性能:redis 最高

   可靠性:zookeeper 最高

3.用java代码使用redis分布锁

   
用setnx 的返回值来判断是否有线程正在进行操作,只是用一个键值对作为锁,和java业务代码没有关系
线程是一个个进行排队,只有当返回值是0的时候,说明前面以及没人在操作了.

Redis-5.0141  分布式锁-18

4.遇到的问题

4.1 其他线程把正在执行线程的锁给释放了

Redis-5.0141  分布式锁-18

解决方法:利用UUID生成随机值,当进行释放锁操作时先对UUID的随机值进行判断,相同再释放. 这就解决了可能被其他线程释放锁的问题.

Redis-5.0141  分布式锁-18

Redis-5.0141  分布式锁-18

4.2 还有一种可能就是在确认过uuid,即将要释放锁时,锁到了过期时间,自动释放了. 这时候另一个线程拿到了锁,并且在进行具体操作时,锁被上一个线程给释放了.

Redis-5.0141  分布式锁-18

解决方法: 使用lua脚本进行释放锁.

Redis-5.0141  分布式锁-18


为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:

1. 互斥性。在任意时刻,只有一个客户端能持有锁。

2. 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。

3. 解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。

4. 加锁和解锁必须具有原子性。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/280990.html

(0)
上一篇 2022年8月17日
下一篇 2022年8月17日

相关推荐

发表回复

登录后才能评论