`
zhoumeng87
  • 浏览: 69896 次
文章分类
社区版块
存档分类
最新评论

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 作者 官网www.fhadmin.org
  • @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]);
    }

}

分享到:
评论

相关推荐

    C#实操控制并发之Lock和Redis分布式锁

    1. **获取锁:** 使用`SET`命令尝试设置一个key(比如`lock_key`),并设置一个过期时间,确保即使发生异常,锁也能自动释放。 2. **释放锁:** 当操作完成,使用`DEL`命令删除key。 3. **锁的公平性:** 防止死锁,...

    redis分布式锁工具类

    现在很多项目单机版已经不满足了,分布式变得越受欢迎,同时也带来很多问题,分布式锁也变得没那么容易实现,分享一个redis分布式锁工具类,里面的加锁采用lua脚本(脚本比较简单,采用java代码实现,无须外部调用...

    redis分布式锁.zip

    Redis 分布式锁是分布式系统中解决并发控制和数据一致性问题的一种常见机制。在大型分布式应用中,单机锁无法满足需求,因为它们局限于单个服务器。Redis 的高可用性和低延迟特性使其成为实现分布式锁的理想选择。...

    springboot基于redis分布式锁

    在现代的高并发系统中,分布式锁是一种非常重要的机制,用于协调多个节点间的资源访问,以确保数据的一致性和完整性。SpringBoot是一个流行的Java微服务框架,它简化了与各种技术栈的集成,包括Redis这样的高性能...

    Java基于redis实现分布式锁代码实例

    Java基于Redis实现分布式锁代码实例 分布式锁的必要性 在多线程环境中,资源竞争是一个常见的问题。例如,在一个简单的用户操作中,一个线程修改用户状态,首先在内存中读取用户状态,然后在内存中进行修改,然后...

    redis实现分布式锁,自旋式加锁,lua原子性解锁

    总结来说,通过Redis实现分布式锁,可以有效解决多节点间的资源竞争问题。使用自旋式加锁策略可以确保锁的获取,而Lua脚本则为解锁提供了原子性保证,从而避免了并发环境下的数据一致性问题。在实际应用中,还可以...

    redis分布式锁工具包,提供纯Java方式调用,支持传统Spring工程.zip

    Redis 分布式锁工具包是为了解决在分布式系统中实现锁的问题,它提供了一种纯Java的方式来调用,使得在传统的Spring工程中可以轻松集成和使用。在现代的高并发、分布式环境下,单机锁已经无法满足需求,因为它们不能...

    C++基于redis的分布式锁redisAPI

    本文将深入探讨如何使用C++结合Redis实现分布式锁,并详细讲解Redis API在C++中的应用,以及如何处理与Boost库的集成。 首先,Redis是一个高性能的键值存储数据库,广泛用于缓存、消息队列、分布式锁等场景。分布式...

    C#.net Redis分布式锁源码实现

    分布式锁是在分布式系统中,用于协调不同节点间对共享资源访问的一种工具。它确保在任何时刻,只有一个客户端能够持有锁并执行相应的操作,从而避免数据不一致性和并发问题。 Redis作为一个内存数据存储系统,因其...

    用Redis实现分布式锁_redis_分布式_

    分布式锁是一种在分布式系统中协调多个节点访问共享资源的机制,它确保了在任何时刻,只有一个客户端能够持有锁并执行相应的操作。Redis,作为一个高性能的键值存储系统,常被用于实现分布式锁,因为它提供了丰富的...

    Redis分布式锁实现Redisson 15问.doc

    Redis分布式锁实现Redisson 15问 Redis分布式锁是指在分布式系统中,多个服务实例之间对同一个资源加锁的机制,以保证数据的一致性和安全性。Redisson是一个基于Redis的分布式锁实现,它提供了一个高效、可靠的加锁...

    记录redisson实现redis分布式事务锁

    Redisson是基于Redis的Java客户端,它提供了丰富的数据结构和服务,包括分布式锁、信号量、队列、计数器等,极大地扩展了Redis在分布式系统中的应用能力。本篇文章将详细探讨如何使用Redisson实现Redis分布式事务锁...

    redis分布式锁实现类

    redis分布式锁的工具类,采用的是Lua代码的方式,保证了Java执行方法的原子性。

    redis分布式锁带过期时间和方法名代码.zip

    redis分布式锁带方法名和过期时间,如果不传方法名自动获取改方法名做key,使锁的粒度到方法级别,释放锁的时间可以根据自己的需要自定义,默认5s,为了解决超大方法执行时间太长,还没有执行完,锁就被释放掉的问题.

    zk:redis分布式锁.zip

    当超过半数的实例成功设置锁时,认为获取锁成功。在释放锁时,需要确保所有实例上的锁都被解除。 在实际应用中,选择Zookeeper还是Redis作为分布式锁的实现取决于具体需求。Zookeeper更适合需要强一致性、高可用性...

    基于 Redis 的分布式锁

    通常的做法是,在设置锁时使用一个唯一标识作为锁的值,在删除锁之前检查这个唯一标识是否与自己设置的一致。如果不一致,则不进行删除操作。 3. 避免锁失效:如果Redis采用主从架构,当主节点故障时,可能会发生锁...

    redis分布式锁实现抢单秒杀

    在IT行业中,尤其是在高并发的电子商务系统中,"redis分布式锁实现抢单秒杀"是一个常见的挑战。这个场景模拟了多个用户同时参与秒杀活动,系统需要确保库存的准确性和抢单的公平性,避免超卖和数据不一致的问题。...

    redis分布式加锁解锁代码

    redis分布式锁,包含单服务器上锁解锁情况,和分布式上锁解锁情况,全部封装在类里,有需要可以下载,希望可以帮助到你。

    redlock-py, 在 python 中,Redis分布式锁.zip

    redlock-py, 在 python 中,Redis分布式锁 redlock - python 中的分布式锁这个 python 库实现了基于redis的分布式锁管理器算法( ) 。要创建锁定管理器:dlm = Redlock([{"host":"localhost","port":

Global site tag (gtag.js) - Google Analytics