业务逻辑:多个数据同步请求并发访问,需要做到请求次数不丢失,比如产生50个请求,那么50个同步请求需要按顺序执行,同步50次;涉及到的环境为2台tomcat服务器双活模式;
代码逻辑:首先将每次请求均存入至redis队列 network_queue,而后使用springboot定时触发(之所以使用springboot定时方式,而不用线程池是因为springboot定时调度是单线程串行的,只有上一个任务执行完后 下一个任务才会进行)
package com.hansight.abc.listener;
import com.hansight.abc.redis.RedisUtil;
import com.hansight.abc.util.UUIDUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
/**
* 定时任务 + 分布式锁
*/
@Component
public class NetworkTest {
private static final Logger logger = LoggerFactory.getLogger(NetworkTest.class);
@Autowired
private RedisUtil redisUtil;
@Scheduled(cron = "*/20 * * * * ?")
public void run() throws UnknownHostException {
logger.info(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
Long size = redisUtil.llen("network_queue");
logger.info("当前本地网段redis队列长度为 {}", size);
String time = String.valueOf((new Date()).getTime()) + "_" + UUID.randomUUID().toString();
Long status = redisUtil.setnx("network_lock", time,60);
logger.info("time {} 是否抢到锁 {}",time,status==1?"是":"否");
String nxVlue = redisUtil.get("network_lock");
if ( size >0 && status == 1) {
String value = redisUtil.rpop("network_queue");
logger.info("已加锁 {} 本地网段redis中取出值为 {}", nxVlue, value);
UUIDUtil.test(value);
}
logger.info("nxVlue.equals(time) {}",nxVlue.equals(time));
if (status == 1 && nxVlue.equals(time)) {
redisUtil.remove("network_lock");
logger.info("已删除当前锁 nxVlue {} time {}",nxVlue,time);
}
}
}
package com.hansight.abc.redis;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Component
public class RedisUtil {
private static final Logger logger = LoggerFactory.getLogger(RedisUtil.class);
@Autowired
private JedisSentinelPool jedisSentinelPool;
public void remove(final String... keys) {
for (String key : keys) {
remove(key);
}
}
public void remove(final String key) {
if (exists(key)) {
try (Jedis jedis = jedisSentinelPool.getResource()) {
jedis.del(key);
jedis.close();
} catch (Exception e) {
logger.error("Error on delete key: {}", key, e);
}
}
}
public boolean exists(final String key) {
try (Jedis jedis = jedisSentinelPool.getResource()) {
Boolean exists = jedis.exists(key);
jedis.close();
return exists;
} catch (Exception e) {
logger.error("Error on check key exists: {}", key, e);
}
return false;
}
public String get(final String key) {
try (Jedis jedis = jedisSentinelPool.getResource()) {
String s = jedis.get(key);
jedis.close();
return s;
} catch (Exception e) {
logger.error("Error on get value by key: {}", key, e);
}
return null;
}
public boolean set(final String key, Object value) {
if (value == null) {
logger.warn("invalid value for key: {}", key);
return false;
}
boolean result = false;
try (Jedis jedis = jedisSentinelPool.getResource()) {
jedis.set(key, value.toString());
jedis.close();
result = true;
} catch (Exception e) {
logger.error("Error on set value to key: {}", key, e);
}
return result;
}
public boolean set(final String key, Object value, int expireTime) {
if (value == null) {
logger.warn("invalid value for key: {}", key);
return false;
}
boolean result = false;
try (Jedis jedis = jedisSentinelPool.getResource()) {
jedis.set(key, value.toString());
jedis.expire(key, expireTime);
jedis.close();
result = true;
} catch (Exception e) {
logger.error("Error on set value to key with expire time in seconds {}: {}", expireTime, key, e);
}
return result;
}
public Long putSet(final String key, final String[] value) {
if (value == null || value.length <= 0) {
logger.warn("invalid value for key: {}", key);
return 0L;
}
try (Jedis jedis = jedisSentinelPool.getResource()) {
Long sadd = jedis.sadd(key, value);
jedis.close();
return sadd;
} catch (Exception e) {
logger.error("Error on execute set-add to key: {}", key, e);
return -1L;
}
}
public Long putSet(final String key, final List<String> value) {
return putSet(key, value.toArray(new String[0]));
}
public Set<String> getSet(final String key) {
try (Jedis jedis = jedisSentinelPool.getResource()) {
Set<String> smembers = jedis.smembers(key);
jedis.close();
return smembers;
} catch (Exception e) {
logger.error("Error on get set-members from key: {}", key, e);
return new HashSet<>();
}
}
public void rename(String oldKey, String newKey) {
try (Jedis jedis = jedisSentinelPool.getResource()) {
jedis.rename(oldKey, newKey);
jedis.close();
} catch (Exception e) {
logger.error("Error on rename key from [{}] to [{}]", oldKey, newKey, e);
}
}
public Long increment(String key, int increment) {
Long res = 0L;
try (Jedis jedis = jedisSentinelPool.getResource()) {
res = jedis.incrBy(key, increment);
jedis.close();
} catch (Exception e) {
logger.error("Error on incrBy key {},increment {} ", key, increment, e);
}
return res;
}
public Set<String> keys(final String key) {
try (Jedis jedis = jedisSentinelPool.getResource()) {
Set<String> keys = jedis.keys(key);
jedis.close();
return keys;
} catch (Exception e) {
logger.error("Error on check key keys: {}", key, e);
}
return null;
}
public Long llen(String key) {
Long result = 0L;
try (Jedis jedis = jedisSentinelPool.getResource()) {
result = jedis.llen(key);
} catch (Exception e) {
logger.error("Error on check key keys: {}", key, e);
}
return result;
}
public Long setnx(String key,String value,int expirTime){
Long result = 0L;
try (Jedis jedis = jedisSentinelPool.getResource()) {
result = jedis.setnx(key,value);
if(result==1){
jedis.expire(key,expirTime);
}
} catch (Exception e) {
logger.error("Error on check key keys: {}", key, e);
}
return result;
}
public String rpop(String key) {
String result = null;
try (Jedis jedis = jedisSentinelPool.getResource()) {
result = jedis.rpop(key);
} catch (Exception e) {
logger.error("Error on check key keys: {}", key, e);
}
return result;
}
}