Redis解决,多实例执行work,同步锁问题

2018-02-12  本文已影响140人  未名枯草

项目需要一个定时任务,执行图片处理job,并上传云存储,部署多台docker,避免多个docker中的work同步执行,防止重复实现数据重复上传存储,需要设计锁机制:
此时:需要注意锁设定是否成功问题;死锁问题;抢锁问题等,
直接上代码分析:

private Integer J_TIMEOUT;

    @Scheduled(cron = "0 0/9 * * * ?") //测试,使用9分钟执行一次。  

    public void HandleSchedule(){
        String today= TimeUtil.getNowDayDate(new Date());
        String time_Lock="time_Key_today";
        String sync_Lock= "sync_Lock";

        //时间标记判断
        if (redisUtils.exists(time_Lock)&&today.equals(redisUtils.get(time_Lock))) {
            log.info("Today the Job had Handled! today:" + today);
            return;
        }
        //lock锁判断
        if (redisUtils.exists(sync_Lock)&&today.equals(redisUtils.get(sync_Lock))){
            log.info("sync  Today the Job is Handling by Other Machine,Locked! today:"+ today);
            return;
        }
        //避免死锁,如果过期时间未生效/未成功设置情况下,删除锁
        if (redisUtils.exists(sync_Lock)&&!(today.equals(redisUtils.get(sync_Lock)))){
            log.info("sync LockKey Value is not Today! Delete the Key! today:"+ today);
            redisUtils.del(sync_Lock);
        }

        Boolean existSuccessLock= redisUtils.setnx(sync_Lock,today); //设置锁lock  setnx();
        if (!existSuccessLock){
            log.info("sync LockKey set False! Today:"+ today);
            return;
        }
        Long successExpire = 0L;
        try {
            successExpire = redisUtils.expire(sync_Lock,J_TIMEOUT); //设置锁lock过期时间
            if (successExpire.equals(0L)) {
                log.info("Set sync Lock Timeout False! today:"+today);
                return;
            }
            //设置锁lock过期时间 成功
            log.info("Having the Redis sync Lock! sync_Lock:"+sync_Lock);
            boolean workSuccessTab =true;
            workSuccessTab = HandleTask2.work();
            if (workSuccessTab){
                redisUtils.setnx(time_Lock,today); //标记当前任务执行完成,此处要添加失败重试
            }
            log.info("******One Job Schedule End!******");

        }catch(Exception e) {
            log.error(" Exception!e:"+e);
        }finally {
            log.info("Delete sync Lock! Today:"+today);
            redisUtils.del(lockKey);
        }
    }

1. 判断时间锁time_Lock的值是否是当天today,如果是,表明已经有work执行了job,今天其他work不能继续执行job;
2. 如果time_Lock不是今天,表明当天还没执行过,可执行下一步;
3. 首先判断同步锁sync_Lock的值value是否存在,如果存在,再判断是否是今天,如果是今天,说明锁被其他实例占用个,此时work停止继续执行,
4. 如果同步锁sync_Lock的值value是否存在,如果存在,value不是今天,则说明是死锁,此时del这个锁,开始执行第6步
5. 若果不存在这个锁,则同样执行第6步;
6. 获取锁,如果获取成功,则继续执行,如果获取失败,则退出当前这次执行;
7. 设定过期时间,如果设定成功则执行下一步,如果设定时间失败,则直接删除获取的sync_Lock锁;如果在设定过期时间之前机器宕机,此时锁已经获取并设定值,此时形成死锁,通过第4步解决。
8. 获取了锁并设定成功了过期时间,则执行任务;
9. 如果执行任务成功,则设定time_Lock;
10.不过结果如何,最后finally要删除同步锁,防止过期时间失效引起死锁。

流程图如图:

多实例执行任务同步锁流程图.png
上一篇 下一篇

猜你喜欢

热点阅读