• 分布式锁在定时任务上的应用


    前言

      在实际开发中,我们会有各种各样的定时任务,通过这些定时任务,我们可以定期发送数据、上线数据、重试错误数据等等功能。有时候我们需求是希望有且只有一台机器在运行,既避免单点问题,又不会出现大量重复的操作。为此我们需要一个分布式锁来控制哪台服务器执行定时任务,获取到锁的服务执行任务,没有获取到锁的服务器等待,直到获取到锁,类似双机互备的方案。若获取到锁的服务器宕机,则通过锁的过期机制自动释放锁。

    考虑的问题

      1)锁竞争,有且只能有一台机器获取到锁

      2)重入锁,同一台机器再次获取锁时,不会因为锁已经被自身持有而出错

      3)死锁,持有锁的机器宕机时,锁需要释放

    方案

      针对锁竞争的问题,这里的解决方式有很多,比如ZK的节点编号,最小节点编号为当前获取锁节点;或者通过redis的单线程特性,通过setnx命令来实现分布式锁。这里我使用的是redis,具体流程如下:

      1)首先通过setnx命令来设置K-V键值对并添加过期时间(过期时间一般为获取锁周期的三倍,即重试三次之后,当前服务器确实与redis断开连接)

      2)如果执行成功则为获取到锁,并将value设置为当前服务器ip(能唯一区分每台服务器即可)

      3)如果执行失败,说明redis中已经存在锁,此时在判断此value值与当前服务器ip是否相同

      4)若相同,说明当前服务器已经获取到锁,满足重入锁的需求,同时为该K-V添加过期时间(续命,若此时与redis断开连接,可以通过锁过期解决死锁的问题)

      5)若值与当前服务器ip不相同,说明锁被其他服务器持有

      6)重复上述的过程,直到获取到锁

    流程图

      

    架构图

      

      系统采用抢占的模式,放弃了复杂的调度模式,服务主动去抢占分布式锁,获得锁的服务执行任务

    时序图

      

    总结

    上面只是简单描述了一下整体的思想,并没有任何代码,大家可以结合自己的实际情况进行更改,将代码打成jar包,应用在更多的地方。在实现最初,通过cglib实现了代理,但是觉得代码比较臃肿,而且生成的代理类也没有加入spring管理,后来直接把代理这块交给spring去做了,简化了很多,整体的思维也比较清晰,希望能够有帮助!

  • 相关阅读:
    (数学)Knight's Trip -- hdu -- 3766
    (DP 雷格码)Gray code -- hdu -- 5375
    (简单匹配)Card Game Cheater -- hdu --1528
    (数论)LightOJ -- 1245
    (树状数组+离散化)lines--hdu --5124
    01项目需要用到的jquery函数介绍
    jdbc基础
    基础加强
    jdbc
    01-1项目所需小工具
  • 原文地址:https://www.cnblogs.com/1ning/p/8986821.html
Copyright © 2020-2023  润新知