Java分布式锁理论(redis、zookeeper))案例详解

 更新时间:2024年01月12日 09:36:32   作者:寻获与失落  
zookeeper有个节点路径的概念,节点路径不能重复,保证了唯一性,这篇文章给大家介绍Java分布式锁理论(redis、zookeeper) 案例详解,感兴趣的朋友跟随小编一起看看吧

一、分布式锁有哪些应用场景?

1、定时任务

2、秒杀抢购,防止库存超卖的问题

3、双写一致性协议

比如我们为了高可用性搭建了服务集群,分别是8080和8081,我们在项目中设立定时任务,目的是每天晚上定时拉取用户数据,给每个人发送一些推荐短信。那么这会出现什么问题呢?8080和8081都有定时任务,到半夜2点同时查询数据库,同时调用阿里云接口发短信,那么肯定会重复,使用了分布式锁,8080抢到锁执行定时任务,那么8081就会阻塞不会执行。

那么肯定会有人问,为什么不用synchronized锁呢?

如果我们是单个项目,用synchronized锁可以实现,但我们用的是集群,synchronized是无法跨jvm的。

二、分布式锁的实现方案

(1)基于数据库实现——mysql行锁

(2)基于zookeeper  CP模式

(3)基于redis setnx实现  AP模式

(4)Redis框架 Redisson、RedisLock

要求:

  • 保证一致性:zookeeper 实现分布式锁
  • 保证可用性:redis实现分布式锁

三、zookeeper实现分布式锁

zookeeper有个节点路径的概念,节点路径不能重复,保证了唯一性。

如图,我有4个springboot项目,首先jvm1先抢到了资源,设置了zk的节点路径/lockPath,这个操作就相当于获取到了锁,这时其余三个jvm获取锁失败进行阻塞状态。当jvm1执行任务完毕,调用close()关闭连接,zk自动删除节点路径释放锁,zk通知其余3个jvm节点,它们3个开始竞争锁。

一直不释放锁怎么办?

我们上面说的是正常理想情况,那么问题来了,如果jvm1一直不释放锁,该怎么办?

可以采用续命设计(设置超时时间),续命多次如果业务还是没有执行完毕的情况下,则认为该锁超时应该主动释放该锁,再将所有业务代码回滚,防止其它jvm一直阻塞等待。

如何避免分布式锁羊群效应问题?

如图可以看出,当我们有100个jvm的时候,如果jvm1抢到了锁,执行完业务释放了锁,zk就要唤醒其余99个jvm,那唤醒这个操作成本是很高的。

如何解决呢?

采用zk的临时顺序节点

我们现在有三个jvm,分别创建了三个临时顺序节点路径,谁最小就获取锁成功,首先jvm1最小获取锁成功,jvm2和jvm3就阻塞,jvm2创建的临时节点就去订阅最小的/lockPath1,当jvm1执行完毕释放锁并删除/lockPath1节点,那么现在/lockPath2就是最小的节点,获取锁成功。

其实就相当于synchronized的公平锁,jvm1、jvm2、jvm3依次按顺序执行,这样我们就不用唤醒所有,jvm1节点消失,我只需要唤醒jvm2节点。

四、redis实现分布式锁

如果不存在值,则返回1,如果存在,则返回0。

那也就是说,我jvm1先setnx返回1抢到了锁,这时jvm2也setnx发现返回0,那就无法执行业务。

当我们执行业务完成后,删除此key就起到了释放锁的作用。

那么问题来了,一个老生常谈的话题,如果jvm1一直不释放锁怎么办?

答:先拿setnx来争抢锁,抢到之后,再用expire命令给锁加一个过期时间防止锁忘记了释放。

但这样还有问题,如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那该怎么解决?

答:我们可以使用lua脚本来使setnx+expire成为原子操作。

到此这篇关于Java分布式锁理论(redis、zookeeper) 详解的文章就介绍到这了,更多相关Java分布式锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 轻量级声明式的Http库——Feign的独立使用

    轻量级声明式的Http库——Feign的独立使用

    这篇文章主要介绍了轻量级声明式的Http库——Feign的使用教程,帮助大家更好的理解和学习使用feign,感兴趣的朋友可以了解下
    2021-04-04
  • Java多线程之Park和Unpark原理

    Java多线程之Park和Unpark原理

    这篇文章主要介绍了Java多线程之Park和Unpark原理,需文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,要的朋友可以参考下
    2021-04-04
  • RocketMQ设计之主从复制和读写分离

    RocketMQ设计之主从复制和读写分离

    这篇文章主要介绍了RocketMQ设计之主从复制和读写分离,RocketMQ提高消费避免Broker发生单点故障引起Broker上的消息无法及时消费,下文关于了RocketMQ的相关内容,需要的小伙伴可以参考一下
    2022-03-03
  • 详解SpringCloud微服务架构之Hystrix断路器

    详解SpringCloud微服务架构之Hystrix断路器

    本篇文章主要介绍了详解SpringCloud微服务架构之Hystrix断路器,Hystrix是一个库,通过添加延迟容差和容错逻辑来帮助您控制这些分布式服务之间的交互,有兴趣的可以了解一下
    2018-01-01
  • 深入java事件注册的应用分析

    深入java事件注册的应用分析

    本篇文章是对java事件注册进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • SpringBoot整合RabbitMQ实现RPC远程调用功能

    SpringBoot整合RabbitMQ实现RPC远程调用功能

    在分布式系统中,RPC(Remote Procedure Call)是一种常用的通信机制,它可以让不同的节点之间像调用本地函数一样进行函数调用,隐藏了底层的网络通信细节,通过本教程,你可以了解RPC的基本原理以及如何使用Java实现一个简单的RPC客户端和服务端
    2023-06-06
  • IDEA感觉不香了AI智能编程工具Cursor使用图文教程

    IDEA感觉不香了AI智能编程工具Cursor使用图文教程

    这篇文章主要介绍了IDEA感觉不香了AI智能编程工具Cursor使用,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-05-05
  • 在Java中关闭SQL执行日志来优化服务器性能

    在Java中关闭SQL执行日志来优化服务器性能

    Java应用程序中,数据库操作是一个常见的任务,如果不适当地处理SQL执行日志,可能会导致不必要的性能损失,SQL执行日志通常由数据库连接池、ORM框架(如Hibernate、MyBatis)、或者应用服务器的内置日志机制生成,本文将探讨如何在Java中关闭SQL执行日志,提升应用性能和效率
    2024-11-11
  • Spring boot详解fastjson过滤字段为null值如何解决

    Spring boot详解fastjson过滤字段为null值如何解决

    这篇文章主要介绍了解决Spring boot中fastjson过滤字段为null值的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • 简单了解java等待唤醒机制原理及使用

    简单了解java等待唤醒机制原理及使用

    这篇文章主要介绍了简单了解java等待唤醒机制原理及使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12

最新评论