• 首页

  • 文章归档

  • 隔壁朋友

  • 关于博主
H B L A O
H B L A O

hblao

获取中...

11
22
java

redis分布式锁解决集群服务器定时任务重复执行问题

发表于 2021-11-22 • springboot redis lock • 被 98 人看爆

问题描述
将带有定时任务的项目部署在单台测试环境上,完全没问题。生产上是两台集群服务器,项目部署上去发现定时任务的模块同时在两台机器上各执行了一遍,这将会导致其他意外的发生。

解决方案----redis分布式锁
使用redis分布式锁,为定时任务唯一指定的key加锁,并设置锁超时时间。当触发定时任务时,一台服务的任务进入切面,通过setNX(key,value)方法为唯一的key加锁,如果当前key不存在,将放入缓存,并返回true,通过expire(key,second)设置锁超时时间,结束后跳出执行定时任务方法。第二台服务任务进入时,设置锁的时候发现该锁已存在于缓存,并返回false,不跳转到执行定时任务方法。

核心代码
1.分布式锁切面

@Aspect
@Slf4j
@Component
public class CacheLockAspect {

private static final String LOCK_VALUE = "locked";

@Autowired
private RedisConnection connection;

@Around("execution(* *.*(..)) && @annotation(com.common.annotation.CacheLock)")
public void  cacheLockPoint(ProceedingJoinPoint pjp) {
    Method cacheMethod = null;
    for (Method method : pjp.getTarget().getClass().getMethods()) {
        if (null!=method.getAnnotation(CacheLock.class)){
            cacheMethod = method;
            break;
        }
    }
    try {
        String lockKey = cacheMethod.getAnnotation(CacheLock.class).lockedPrefix();
        long timeOut = cacheMethod.getAnnotation(CacheLock.class).expireTime();
        if(null == lockKey){
            throw new ManagerException(ErrorMsgEnum.LOCK_NAME_EMPTY);
        }
        if (connection.setNX(lockKey.getBytes(),LOCK_VALUE.getBytes())) {
            connection.expire(lockKey.getBytes(),timeOut);
            log.info("method:{}获取锁:{},开始运行!",cacheMethod,lockKey);
            pjp.proceed();
            return;
        }
        log.info("method:{}未获取锁:{},运行失败!",cacheMethod,lockKey);
    } catch (Throwable e) {
        log.error("method:{},运行错误!",cacheMethod,e);
        throw new ManagerException(ErrorMsgEnum.LOCK_JOB_ERROR,e);
    }

}

}
2.手写方法级注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CacheLock {
String lockedPrefix() default ""; //redis 锁key的前缀
long expireTime() default 10; //key在redis里存在的时间,1000S
}
3.定时任务服务

@Slf4j
@Service
public class TimeTaskService {

/**
 * 执行定时任务
 **/
@Scheduled(cron = "0 0 1 * * ?")
@CacheLock(lockedPrefix = "TimeTaskService",expireTime=30)
public void executeTask() {
    System.out.println("hello world!");
}

}

分享到:
java8两个集合取交集、并集与差集
Arthas - Java 线上问题定位处理的终极利器
  • 文章目录
  • 站点概览
hblao

Hihblao

QQ Email RSS
看爆 Top5
  • 设计一个高并发的高可用系统 434次看爆
  • MySQL 常用优化指南 224次看爆
  • Spring AOP 207次看爆
  • 人到中年 188次看爆
  • RedisTemplate常用使用说明 170次看爆

Copyright © 2022 hblao · 京ICP备16001163号

Proudly published with Halo · Theme by fyang · 站点地图 · 百度统计