资讯专栏INFORMATION COLUMN

浅谈分布式锁

legendmohe / 1527人阅读

摘要:如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。基于的分布式锁利用临时节点与机制。

1. 什么是锁?

      在单进程的系统中,当存在多个线程可以同时改变某个变量时,就需要对变量或代码块做同步,使其在修改这种变量时能够线性执行消除并发修改变量。
   而同步的本质是通过锁来实现的。为了实现多个线程在一个时刻同一个代码块只能有一个线程可执行,那么需要在某个地方做个标记,这个标记必须每个线程都能看到,当标记不存在时可以设置该标记,其余后续线程发现已经有标记了则等待拥有标记的线程结束同步代码块取消标记后再去尝试设置标记。这个标记可以理解为锁。
   不同地方实现锁的方式也不一样,只要能满足所有线程都能看得到标记即可。如java中synchronize是在对象头设置标记,Lock接口的实现类基本上都只是某一个volitile修饰的int型变量其保证每个线程都能拥有对该int的可见性和原子修改,linux内核中也是利用互斥量或信号量等内存数据做标记。

2. 什么是分布式锁?

    分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。

3. 分布式锁实现的几种方式(每种方式都具备多种实现方案)

基于数据库实现分布式锁

基于数据库乐观锁实现:
乐观锁通常实现基于数据版本号(version)的记录机制实现的,在修改数据库前获取版本号,修改数据时与获取版本号不一致则抛出异常(修改数据时切记对版本号进行+1)

基于缓存(redis...)实现分布式锁

使用redis的setnx()、get()、getset()方法,用于分布式锁

setnx(lockkey, 当前时间+过期超时时间) ,如果返回1,则获取锁成功;如果返回0则没有获取到锁,转向2。

get(lockkey)获取值oldExpireTime ,并将这个value值与当前的系统时间进行比较,如果小于当前系统时间,则认为这个锁已经超时,可以允许别的请求重新获取,转向3。

计算newExpireTime=当前时间+过期超时时间,然后getset(lockkey, newExpireTime) 会返回当前lockkey的值currentExpireTime。

判断currentExpireTime与oldExpireTime 是否相等,如果相等,说明当前getset设置成功,获取到了锁。如果不相等,说明这个锁又被别的请求获取走了,那么当前请求可以直接返回失败,或者继续重试。

在获取到锁之后,当前线程可以开始自己的业务处理,当处理完毕后,比较自己的处理时间和对于锁设置的超时时间,如果小于锁设置的超时时间,则直接执行delete释放锁;如果大于锁设置的超时时间,则不需要再锁进行处理(这样可以避免死锁)。

基于Zookeeper的分布式锁

    利用临时节点与 watch 机制。每个锁占用一个普通节点 /lock,当需要获取锁时在 /lock 目录下创建一个临时节点,创建成功则表示获取锁成功,失败则 watch/lock 节点,有删除操作后再去争锁。临时节点好处在于当进程挂掉后能自动上锁的节点自动删除即取消锁

4. 推荐开源分布式锁lock-spring-boot-starter

    基于redisson实现的spring boot starter分布式锁框架,实现了可重入锁、公平锁、联锁、红锁、读写锁等常用锁的方式,并支持集群模式下的redis。

为什么推荐此项目?

我参与项目的开发

高可用,使用简单

支持单机模式,集群模式,云托管模式,哨兵模式

支持参数加锁,对象属性上加锁,支持方法上加锁

引入maven依赖即可使用

 
     io.gitee.tooleek
     lock-spring-boot-starter
     1.1.0
 

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/75904.html

相关文章

  • 浅谈Java并发编程系列(一)—— 如何保证线程安全

    摘要:比如需要用多线程或分布式集群统计一堆用户的相关统计值,由于用户的统计值是共享数据,因此需要保证线程安全。如果类是无状态的,那它永远是线程安全的。参考探索并发编程二写线程安全的代码 线程安全类 保证类线程安全的措施: 不共享线程间的变量; 设置属性变量为不可变变量; 每个共享的可变变量都使用一个确定的锁保护; 保证线程安全的思路: 1. 通过架构设计 通过上层的架构设计和业务分析来避...

    mylxsw 评论0 收藏0
  • 浅谈缓存(一)

    摘要:缓存穿透场景当通过一个去数据库查询出来的数据结果为缓存系统就不会缓存该数据每次该查询都会经过数据库层造成没有必要的开销解决方案将该缓存至缓存系统中为一个特殊值缓存失效场景由于初始化的时候某些缓存过期时间设置的都一样一段时间以后缓存全部失效在 缓存穿透 场景:当通过一个key去数据库查询出来的数据结果为null,缓存系统就不会缓存该数据,每次该key查询都会经过数据库层,造成没有必要的D...

    Shihira 评论0 收藏0
  • 浅谈缓存(一)

    摘要:缓存穿透场景当通过一个去数据库查询出来的数据结果为缓存系统就不会缓存该数据每次该查询都会经过数据库层造成没有必要的开销解决方案将该缓存至缓存系统中为一个特殊值缓存失效场景由于初始化的时候某些缓存过期时间设置的都一样一段时间以后缓存全部失效在 缓存穿透 场景:当通过一个key去数据库查询出来的数据结果为null,缓存系统就不会缓存该数据,每次该key查询都会经过数据库层,造成没有必要的D...

    B0B0 评论0 收藏0
  • 浅谈缓存(一)

    摘要:缓存穿透场景当通过一个去数据库查询出来的数据结果为缓存系统就不会缓存该数据每次该查询都会经过数据库层造成没有必要的开销解决方案将该缓存至缓存系统中为一个特殊值缓存失效场景由于初始化的时候某些缓存过期时间设置的都一样一段时间以后缓存全部失效在 缓存穿透 场景:当通过一个key去数据库查询出来的数据结果为null,缓存系统就不会缓存该数据,每次该key查询都会经过数据库层,造成没有必要的D...

    xzavier 评论0 收藏0

发表评论

0条评论

legendmohe

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<