redis分布式锁,无须设置有效期,自动检测hold锁的节点是否存活
来源:互联网 发布:java编程语言机构 编辑:程序博客网 时间:2024/05/22 03:24
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]);
}
}
- redis分布式锁,无须设置有效期,自动检测hold锁的节点是否存活
- 基于单Redis节点的分布式锁
- 监控redis是否存活的脚本
- redis 设置分布式锁
- 基于redis单节点实现分布式锁
- redis的分布式锁
- Redis的分布式锁
- Session的有效期设置
- 【Redis深入】Redis分布式锁的实现
- redis分布式锁的实现
- redis实现的分布式锁
- 基于Redis的分布式锁
- redis分布式锁的实现
- 分布式锁的redis实现
- redis分布式锁的思考
- 基于Redis的分布式锁
- 基于redis的分布式锁
- 基于redis的分布式锁
- 把非负数组分割为m组 求m组相邻元素最小值中的最大值 以及最大值中的最小值
- STS启动报错 : Computing Git status for repository
- pandas apply函数的入门
- ACM解题小技巧
- 【源码下载】基于百度地图的demo(定位,导航,语音播报,搜索,传感器)
- redis分布式锁,无须设置有效期,自动检测hold锁的节点是否存活
- 网络设备丢弃ECN包导致的慢响应问题
- Cglib动态代理源码例子解析
- shell整理(3)
- Docker 数据管理
- 开发中,常用到的Eclipse快捷键
- 多对多查询(11)
- HBase概念、基本架构及原理
- Linux-USB驱动(1)-USB总线介绍