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

    xiaoxiao2022-05-20  223

    1.有一个独立的keeplive守护线程保证节点存活,频率是n。2.节点存活信息由固定前置+mac+进程id+进程启动时间,保证节点重启问题。

    锁的信息由固定前置+mac+进程id+进程启动时间。具体锁的逻辑参考lock方法。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]); }

    }

    相关资源:七夕情人节表白HTML源码(两款)

    最新回复(0)