Redis解决分布式定时任务重复执行问题

问题描述: 有一个定时任务是每周一给客户发送邮件的功能, 后台部署了2台服务器,所以客户 收到了2封重复邮件。

解决思路:

分布式锁一般有三种实现方式:1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁。

这里使用一台Redis服务器来解决上面的问题。

代码部分比较简单:

加锁 :主要是给多个定时任务给redis加锁(key),如果存在key,则加锁失败,如果不存在,则尝试去加锁,返回加锁结果。 

解锁: 设置一下过期时间为20秒(可根据任务执行长短调整),过期后自动释放掉。这里就不去代码里面释放锁了。

private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    private static final Long RELEASE_SUCCESS = 1L;

 /**
     * 尝试获取分布式锁
     *
     * @param jedis      Redis客户端
     * @param lockKey    锁
     * @param requestId  请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
    //这里的jedis自己去实现一下 String result
= jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); if (LOCK_SUCCESS.equals(result)) { return true; } return false; }

 

测试 (同时启动4个服务,每个服务上面启动三个同样的定时任务)

 //每分钟执行一次
    static final String cron1 = "0 */1 * * * ?";

    @Scheduled(cron = cron1)
    public void testRedis1() {
        String msg = doRedis();
        System.out.println("msg1 :" + msg);
    }
    
    @Scheduled(cron = cron1)
    public void testRedis2() {
        String msg = doRedis();
        System.out.println("msg 2:" + msg);
    }
    
    @Scheduled(cron = cron1)
    public void testRedis3() {
        String msg = doRedis();
        System.out.println("msg 3:" + msg);
    }


    //执行redis
    private String doRedis() {
        boolean flag = RedisTool.tryGetDistributedLock("sendMail_20200101", UUID.randomUUID().toString(), 1000 * 20);
        String msg = null;
        if (flag) {
            msg = "你获取到锁了可以去操作业务!";
        } else {
            msg = "别人获取到锁了,你就不用操作了!!!!";
        }
        return msg;
    }

 

测试结果

 

 

观察到每一分钟, 3X4个定时任务中,只有一个能获取到锁,可以去操作业务,其他同样的定时任务失败了 。

 

总结:后面会具体总结一下分布式锁相关的内容

 

posted @ 2020-04-14 13:58  将军上座  阅读(3610)  评论(3编辑  收藏  举报