redis分布式锁,无须设置有效期,自动检测hold锁的节点是否存活

1.有一个独立的keeplive守护线程保证节点存活,频率是n。
2.节点存活信息由固定前置+mac+进程id+进程启动时间,保证节点重启问题。
3. 锁的信息由固定前置+mac+进程id+进程启动时间。
4. 具体锁的逻辑参考lock方法。
package six.com.crawler.common;

import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;

import redis.clients.jedis.JedisCluster;

/**

  • @author 作者
  • @E-mail: 359852326@qq.com
  • @date 创建时间:2017年5月27日 下午3:13:14
  •   基于redis实现分布式锁,无需给锁key加上过期时间,程序会自动检测
    

    */
    public class RedisLock {

    private static long SYSTEM_START_TIME = System.currentTimeMillis();
    private static String mac;
    private static String pid;
    private static String nodeKeepliveInfoPre;

    static {
    String name = ManagementFactory.getRuntimeMXBean().getName();
    pid = name.split("@")[0];
    try {
    InetAddress ia = InetAddress.getLocalHost();
    byte[] macBytes = NetworkInterface.getByInetAddress(ia).getHardwareAddress();
    StringBuffer sb = new StringBuffer("");
    for (int i = 0; i < macBytes.length; i++) {
    int temp = macBytes[i] & 0xff;
    String str = Integer.toHexString(temp);
    if (str.length() == 1) {
    sb.append("0" + str);
    } else {
    sb.append(str);
    }
    }
    mac = sb.toString().toUpperCase();
    } catch (Exception e) {
    }
    nodeKeepliveInfoPre = mac + "_" + pid + "_" + SYSTEM_START_TIME + "_";
    }

    private Thread keepliveThread;
    private JedisCluster jedisCluster;
    private String nodeKeepliveInfoKeyPre;
    private String nodeKeepliveInfoKey;
    private long loopKeepliveInterval;
    private int keepliveInfoExpire;
    private long checkLockIntervalTime;

    public RedisLock(JedisCluster jedisCluster, String nodeKeepLiveInfoKeyPre, long loopKeepliveInterval,
    long checkLockIntervalTime) {
    this.jedisCluster = jedisCluster;
    this.nodeKeepliveInfoKeyPre = nodeKeepLiveInfoKeyPre;
    this.nodeKeepliveInfoKey = getNodeKeepliveInfoKey(mac, pid, String.valueOf(SYSTEM_START_TIME));
    this.loopKeepliveInterval = loopKeepliveInterval;
    this.keepliveInfoExpire = (int) (loopKeepliveInterval) / 1000 * 2;
    this.checkLockIntervalTime = checkLockIntervalTime;
    initKeepLive();
    }

    /**

    • 节点mac+进程id+进程启动时间保证节点重启问题
      */
      private void initKeepLive() {
      keepliveThread = new Thread(() -> {
      String nodeInfo = null;
      while (true) {
      nodeInfo = nodeKeepliveInfoPre + String.valueOf(System.currentTimeMillis());
      jedisCluster.set(nodeKeepliveInfoKey, nodeInfo);
      jedisCluster.expire(nodeKeepliveInfoKey, keepliveInfoExpire);
      try {
      Thread.sleep(loopKeepliveInterval);
      } catch (InterruptedException e) {
      }
      }

      }, "node-keeplive-thread");
      keepliveThread.setDaemon(true);
      keepliveThread.start();
      }

    public void lock(String lockKey) {
    while (true) {
    if (1 == jedisCluster.setnx(lockKey, getNodeLockInfo())) {
    break;
    }
    String nodeInfo = jedisCluster.get(lockKey);
    String nodeInfoKey = getNodeKeepliveInfoKey(nodeInfo);
    String lastKeepNodeInfo = jedisCluster.get(nodeInfoKey);
    do {
    try {
    Thread.sleep(checkLockIntervalTime);// 这个时间需要根据节点刷新时间取一个合适值
    } catch (InterruptedException e) {
    }
    String tempNodeInfo = jedisCluster.get(nodeInfoKey);
    if (isNotKeeplive(lastKeepNodeInfo, tempNodeInfo)) {
    // 证明节点挂了
    unlock(lockKey);
    break;
    } else {
    lastKeepNodeInfo = tempNodeInfo;
    }
    } while (true);
    }
    }

    /**

    • 判断目标节点是否还在线
    • @param lastKeepliveInfo
    • @param newKeepliveInfo
    • @return
      */
      private boolean isNotKeeplive(String lastKeepliveInfo, String newKeepliveInfo) {
      String[] lastMeta = lastKeepliveInfo.split("_");
      String[] newMeta = newKeepliveInfo.split("_");
      // mac pid 启动时间 系统时间
      if (lastMeta[0] != newMeta[0]) {
      // 当前Hold key的节点已被其他节点占据
      return true;
      } else {
      if (lastMeta[1] != newMeta[1]) {
      // pid发生变化表示节点已经重启
      return true;
      } else {
      if (lastMeta[2] != newMeta[2]) {
      // 启动时间发生变化表示节点已经重启
      return true;
      } else {
      if (lastMeta[3] != newMeta[3]) {
      // 系统时间发生变化表示节点正常存活
      return false;
      } else {
      return true;
      }
      }
      }
      }
      }

    public void unlock(String lockKey) {
    jedisCluster.del(lockKey);
    }

    private String getNodeLockInfo() {
    return mac + "_" + pid + "_" + SYSTEM_START_TIME + "_" + System.currentTimeMillis();
    }

    private String getNodeKeepliveInfoKey(String mac, String pid, String systemStartTime) {
    String nodeKeepLiveInfoKey = nodeKeepliveInfoKeyPre + mac + pid + systemStartTime;
    return nodeKeepLiveInfoKey;
    }

    private String getNodeKeepliveInfoKey(String nodeLockInfo) {
    String[] meta = nodeLockInfo.split("_");
    return getNodeKeepliveInfoKey(meta[0], meta[1], meta[2]);
    }

}

时间: 2024-09-01 09:48:03

redis分布式锁,无须设置有效期,自动检测hold锁的节点是否存活的相关文章

Redis 分布式锁的正确实现方式( Java 版 )

分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁.可靠性首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:互斥性.在任意时刻,只有一个客户端能持有锁. 不会发生死锁.即使有一个客户端在持有锁的期间

Redis分布式锁服务(八)

阅读目录: 概述 分布式锁 多实例分布式锁 总结 概述 在多线程环境下,通常会使用锁来保证有且只有一个线程来操作共享资源.比如: object obj = new object(); lock (obj) { //操作共享资源 } 利用操作系统提供的锁机制,可以确保多线程或多进程下的并发唯一操作.但如果在多机环境下就不能满足了,当A,B两台机器同时操作C机器的共享资源时,就需要第三方的锁机制来保证在分布式环境下的资源协调,也称分布式锁. Redis有三个最基本属性来保证分布式锁的有效实现: 安全

IE中“自动检测设置”无法取消怎么办?

有时我们会遇到IE中自动检测设置无法取消的情况,具体表现为"自动检测设置"默认是打勾的却显示为灰色无法操作,这时我们可以通过修改注册表来取消IE中的"自动检测设置",具体方法如下: 新建一个记事本文档写入以下内容 Windows Registry Editor Version 5.00 [HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionInternet SettingsConnections] "

windows8.1锁屏界面上自动播放幻灯片设置步骤

进行Windows 8.1桌面,把鼠标移动到右下角,出现右边工具,找到"设置",并单击它. 2 在"设置"里找到"更改电脑设置",并单击它,打开"电脑设置"页面. 3 在"电脑"设置页面里找到"锁屏界面",并点击它以选择. 4 在打开的"锁屏界面"的右边我们就可以进行各项参数的设置. 在锁屏界面上放映幻灯片:把它设置成开,这样锁屏了才能自动进行播放. 使用来自以下位置

Win7如何自动检测设置浏览器更新

  Win7如何自动检测设置浏览器更新 1.利用此策略设置,可管理Internet Explorer 是否在Internet中检查较新版本.如果将Internet Explorer 设置为执行上述操作,则会每隔大约30天执行一次检查,并且当有新版本可用时会提示用户安装新版本. 2.如果启用此策略设置,则Internet Explorer 会每隔大约30天在Internet中检查一次新版本,并在有新版本可用时提示用户下载新版本. 3.如果禁用此策略设置,则Internet Explorer 不会在

Win7旗舰版系统屏幕如何设置不自动锁屏

  Win7旗舰版系统屏幕如何设置不自动锁屏?Windows7系统中如何实现电脑屏幕不自动锁屏?正所谓萝卜青菜各有所爱,有些用户喜欢使用win7系统的自动锁屏,这样可以在暂时离开电脑的时候节能,而且桌面内容不会被别人看到,但是有些用户觉得在家中的电脑没必要这样,显得麻烦,因此想让Windows7系统的电脑屏幕不自动锁屏,那么该如何设置呢,一起来学习吧! 1.点击win7系统桌面的"开始"-"控制面板",切换到小图标模式下,点击电源选项; 2.在打开的电源选项界面中,

redis分布式锁的运用和理解

问题描述 redis分布式锁的运用和理解 redis是单进程单线程模式 ,为什么还需要分布式锁?跨jvm是指多个服务器上在运行同一个服务吗? 网上看了很多说跨jvm会需要锁 ,但还是不怎么理解 解决方案 redis分布式锁redis分布式锁-SETNX实现Redis实现分布式锁 解决方案二: redis 3.0也有集群模式了,可以多个机器组成一个整体的cache 解决方案三: redis分布式锁和zookeeper分布式锁都在在企业服务中常用的知识.譬如:你有一个服务程序,需要部署在5台独立的机

J2EE分布式架构 dubbo+springmvc+mybatis+ehcache+redis分布式架构

平台简介         Jeesz是一个分布式的框架,提供项目模块化.服务化.热插拔的思想,高度封装安全性的Java EE快速开发平台.         Jeesz本身集成Dubbo服务管控.Zookeeper注册中心.Redis分布式缓存技术.FastDFS分布式文件系统.ActiveMQ异步消息中间件.Nginx负载均衡等分布式技术         使用Maven做项目管理,项目模块化,提高项目的易开发性.扩展性         以Spring Framework为核心容器,Spring

Windows自动登录及锁屏

这个操作对于广大使用Windows(包括xp/win7/2003/2008 R2 等windows 系统) 的上班族会有点用. 其一:如果是个人吧系统(win7.xp)上班时候打开电脑,自动登录,系统启动该自动运行的程序,然后自动锁定屏幕,安全又快速--趁这个时候去泡个茶啥的,回来就开工啦! 其二:对于使用服务器操作系统,那么有些服务器运行了关键应用程序,恰好又不是后台服务,那么就必须依赖于登录系统后才能启动应用程序,通过此方法可以将应用服务自动启动.不需要管理员登录系统.且保证了其它员工在不知