All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jeesuite.common2.lock.redis.RedisLockCoordinator Maven / Gradle / Ivy

There is a newer version: 1.4.0
Show newest version
package com.jeesuite.common2.lock.redis;

import static com.jeesuite.cache.redis.JedisProviderFactory.getJedisCommands;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import javax.annotation.PreDestroy;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;

import com.jeesuite.cache.redis.JedisProvider;
import com.jeesuite.cache.redis.JedisProviderFactory;
import com.jeesuite.cache.redis.sentinel.JedisSentinelProvider;
import com.jeesuite.cache.redis.standalone.JedisStandaloneProvider;
import com.jeesuite.common.util.ResourceUtils;

import redis.clients.jedis.BinaryJedis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisPubSub;

/**
 * 
 * @description 
* @author vakin * @date 2018年3月22日 */ public class RedisLockCoordinator { private static final String DLOCK_GROUP_NAME = "_redisLock"; private static final int HEALTH_CHECK_PERIOD = 30000; private static final String REDIS_LOCK_ACTIVE_NODES_KEY = "RedisLockActiveNodes"; private static final long CLEAN_TIME = TimeUnit.SECONDS.toMillis(90); private static final String SPLIT_STR = "$$"; private static final String EVENT_NODE_ID = RandomStringUtils.random(8, true, true); private static String channelName = "redisLockCoordinator"; private AtomicLong eventIdSeq = new AtomicLong(0); private List activeNodeIds = new ArrayList<>(); private ScheduledExecutorService checkerSchedule; private Jedis subClient; private Map> getLockEventIds = new ConcurrentHashMap<>(); public RedisLockCoordinator() { String mode = ResourceUtils.getProperty("jeesuite.lock.redis.mode", ResourceUtils.getProperty("jeesuite.cache.mode","standalone")); String server = ResourceUtils.getProperty("jeesuite.lock.redis.servers", ResourceUtils.getProperty("jeesuite.cache.servers")); String datebase = ResourceUtils.getProperty("jeesuite.lock.redis.datebase", ResourceUtils.getProperty("jeesuite.cache.datebase","0")); String password = ResourceUtils.getProperty("jeesuite.lock.redis.password", ResourceUtils.getProperty("jeesuite.cache.password")); String maxPoolSize = ResourceUtils.getProperty("jeesuite.lock.redis.maxPoolSize", ResourceUtils.getProperty("jeesuite.cache.maxPoolSize","100")); Validate.notBlank(server, "config[jeesuite.lock.redis.servers] not found"); JedisPoolConfig poolConfig = new JedisPoolConfig(); poolConfig.setMaxIdle(1); poolConfig.setMinEvictableIdleTimeMillis(30*60*1000); poolConfig.setMaxTotal(Integer.parseInt(maxPoolSize)); poolConfig.setMaxWaitMillis(5 * 1000); String[] servers = server.split(";|,"); int timeout = 3000; if("standalone".equals(mode)){ JedisProvider provider = new JedisStandaloneProvider(DLOCK_GROUP_NAME, poolConfig, servers, timeout, password, Integer.parseInt(datebase),null); JedisProviderFactory.addProvider(provider); }else if("sentinel".equals(mode)){ String masterName = ResourceUtils.getProperty("jeesuite.lock.redis.masterName", ResourceUtils.getProperty("jeesuite.cache.masterName")); Validate.notBlank(masterName, "config[jeesuite.lock.redis.masterName] not found"); JedisSentinelProvider provider = new JedisSentinelProvider(DLOCK_GROUP_NAME, poolConfig, servers, timeout, password, Integer.parseInt(datebase), null, masterName); JedisProviderFactory.addProvider(provider); } Jedis redisClient = getRedisClient(); redisClient.hset(REDIS_LOCK_ACTIVE_NODES_KEY, EVENT_NODE_ID, String.valueOf(System.currentTimeMillis())); release(redisClient); activeNodeIds.add(EVENT_NODE_ID); // checkerSchedule = Executors.newScheduledThreadPool(1); // checkerSchedule.scheduleAtFixedRate(new Runnable() { // @Override // public void run() { // if(!subClient.isConnected()){ // subClient.connect(); // } // // // checkActiveNode(); // } // }, 0, HEALTH_CHECK_PERIOD - 1000, TimeUnit.MILLISECONDS); Thread thread = new Thread(new Runnable() { @Override public void run() { subClient = getRedisClient(); subClient.subscribe(new LockStateListener(), new String[]{channelName}); } }, channelName); thread.setDaemon(true); thread.start(); } private void checkActiveNode(){ Jedis redisClient = getRedisClient(); try { long currentTime = System.currentTimeMillis(); Map map = redisClient.hgetAll(REDIS_LOCK_ACTIVE_NODES_KEY); Iterator> iterator = map.entrySet().iterator(); while(iterator.hasNext()){ Entry entry = iterator.next(); if(currentTime - Long.parseLong(entry.getValue()) > HEALTH_CHECK_PERIOD){ redisClient.hdel(REDIS_LOCK_ACTIVE_NODES_KEY, entry.getKey()); }else{ redisClient.hset(REDIS_LOCK_ACTIVE_NODES_KEY, entry.getKey(), String.valueOf(currentTime)); } } if(!map.containsKey(EVENT_NODE_ID)){ redisClient.hset(REDIS_LOCK_ACTIVE_NODES_KEY, EVENT_NODE_ID, String.valueOf(currentTime)); } } finally { release(redisClient); } } public Jedis getRedisClient(){ Jedis jedis = (Jedis) JedisProviderFactory.getJedisProvider(DLOCK_GROUP_NAME).get(); if(!jedis.isConnected()){ jedis.connect(); } return jedis; } public void release(Jedis jedis) { JedisProviderFactory.getJedisProvider(DLOCK_GROUP_NAME).release(); } public String buildEvenId(){ return new StringBuilder().append(EVENT_NODE_ID).append(System.currentTimeMillis()).append(eventIdSeq.incrementAndGet()).toString(); } public void notifyNext(Jedis pubClient,String lockName){ long currentTimeMillis = System.currentTimeMillis(); String nextEventId; while(true){ nextEventId = pubClient.rpop(lockName); if(StringUtils.isBlank(nextEventId)){ return; } if(activeNodeIds.contains(nextEventId.substring(0,8)) && currentTimeMillis - Long.parseLong(nextEventId.substring(8,21)) < CLEAN_TIME){ break; } } pubClient.publish(channelName, lockName + SPLIT_STR + nextEventId); } public boolean await(String lockName,String eventId,long timeoutMills){ List eventIds = getGetLockEventIds(lockName); long start = System.currentTimeMillis(); int deadLockCheckPoint = 0; while (true) { try {TimeUnit.MILLISECONDS.sleep(1);} catch (InterruptedException e) {} if (eventIds.contains(eventId)){ eventIds.remove(eventId); return true; } long useTime = System.currentTimeMillis() - start; if (useTime > timeoutMills) { return false; } //防止redis的锁数据丢失或者redis挂掉造成死锁,1秒钟检查一次 int useTimeSeconds = (int) (useTime / 1000); if(useTimeSeconds > 0 && useTimeSeconds > deadLockCheckPoint){ deadLockCheckPoint = useTimeSeconds; try { if(getJedisCommands(DLOCK_GROUP_NAME).llen(lockName) == 0){ return false; } } catch (Exception e) { return false; } } } } private List getGetLockEventIds(String lockName){ List eventIds = getLockEventIds.get(lockName); if(eventIds == null){ synchronized (getLockEventIds) { eventIds = getLockEventIds.get(lockName); if(eventIds == null){ eventIds = new Vector<>(); getLockEventIds.put(lockName, eventIds); } } } return eventIds; } @PreDestroy public void close(){ try {subClient.close();} catch (Exception e) {} if(checkerSchedule != null)checkerSchedule.shutdown(); } private class LockStateListener extends JedisPubSub { public LockStateListener() {} @Override public void onMessage(String channel, String message) { super.onMessage(channel, message); if(StringUtils.isBlank(message)){ return; } String[] parts = StringUtils.splitByWholeSeparator(message, SPLIT_STR); String lockName = parts[0]; String nextEventId = parts[1]; if(!nextEventId.startsWith(EVENT_NODE_ID)){ return; } getGetLockEventIds(lockName).add(nextEventId); } } public static void main(String[] args) { System.out.println(1500 % 1000); System.out.println(1500 / 1000); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy