资讯专栏INFORMATION COLUMN

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

ethernet / 3719人阅读

摘要:当触发定时任务时,一台服务的任务进入切面,通过方法为唯一的加锁,如果当前不存在,将放入缓存,并返回通过设置锁超时时间,结束后跳出执行定时任务方法。

问题描述

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

解决方案----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!");
    }

}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/72599.html

相关文章

  • 考拉定时任务框架kSchedule

    摘要:考拉订单流推送申报单推送物流信息等供应链相关业务已接入分片任务,极大提高了业务吞吐量降低压力,提升了通关效率。支撑双十一黑五双十二等大促,高峰期统一暂停非关键定时任务,让出系统资源,提高业务系统稳定性。 此文已由作者杨凯明授权网易云社区发布。 欢迎访问网易云社区,了解更多网易技术产品运营经验。 1.背景 目前项目中使用的定时任务框架存在下面这些问题 没有统一的定时任务管理平台 目前项目...

    AlexTuan 评论0 收藏0
  • 布式机制原理及实现方式

    摘要:分布式锁实现方式前言目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题。基于数据库实现分布式锁基于缓存等实现分布式锁基于实现分布式锁。 前言 分布式锁,是控制分布式系统之间同步访问共享资源的一种方式 在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥...

    yacheng 评论0 收藏0
  • 布式机制原理及实现方式

    摘要:分布式锁实现方式前言目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题。基于数据库实现分布式锁基于缓存等实现分布式锁基于实现分布式锁。 前言 分布式锁,是控制分布式系统之间同步访问共享资源的一种方式 在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥...

    Travis 评论0 收藏0
  • 七道常见的Redis面试题分享

    摘要:综合上述缺点,小明痛定思痛,提出了经营方式二。当客户下单,小明按送达地点标注好,依次放在一个地方。因此,有强一致性要求的数据,不能放缓存。迅速判断出,请求所携带的是否合法有效。 showImg(https://segmentfault.com/img/bVbvHHL?w=1341&h=448); 绝大部分写业务的程序员,在实际开发中使用 Redis 的时候,只会 Set Value 和...

    zhiwei 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<