博客信息

Redis分布式锁解决集群环境重复执行问题

0
发布时间:『 2019-07-31 06:59』  博客类别:redis  阅读(584) 评论(0)

需求:要求定时执行接口任务

出现问题:集群环境下,定时任务重复执行。


由于服务都是集群部署,定时任务会在各个服务器上重复执行,轻则浪费服务器资源,重则造成数据紊乱。 

quartz定时任务提供了集群方式,但还需为其创建数据库表。spring schedule可以实现简单轻量级的定时任务,但无法保证只执行一次。 

通过探讨得知,可以使用redis的分布式锁保证spring schedule集群只执行一次。 


redis分布式锁是通过setnx命令实现的。该命令的作用是,当往redis中存入一个值时,会先判断该值对应的key是否存在,如果存在则返回0,如果不存在,则将该值存入redis并返回1。根据这个特性,我们在程序中,每次都调用setIfAbsent(该方法是setnx命令的实现)方法,来模拟是否获取到锁,如果返回true,则说明该key值不存在,表示获取到锁;如果返回false,则说明该key值存在,已经有程序在使用这个key值了,从而实现了类似加锁的功能。

@Component
@Configuration
@EnableScheduling
public class AutoConvertTask {
    private static final Logger logger = LoggerFactory.getLogger(AutoConvertTask.class);

    @Autowired
    private RedisTemplate redisTemplate;

    private static final String LOCK = "task-job-lock";

    private static final String KEY = "tasklock";

    @Scheduled(cron = "0 0 0 * * ? ")
    public void autoConvertJob() {
        boolean lock = false;
        try {
            lock = redisTemplate.opsForValue().setIfAbsent(KEY, LOCK);
            logger.info("是否获取到锁:" + lock);
            if (lock) {
                List<GameHistory> historyList = historyService.findTenDaysAgoUntreated();
                for (GameHistory history : historyList) {
                    update(history);
                }
            } else {
                logger.info("没有获取到锁,不执行任务!");
                return;
            }
        } finally {
            if (lock) {
                redisTemplate.delete(KEY);
                logger.info("任务结束,释放锁!");
            } else {
                logger.info("没有获取到锁,无需释放锁!");
            }
        }

    }

}


总结:然后按照这段代码提示获取锁,当多个项目同时获取redis分布式锁,你用redis单线程的特性,所以当有一台服务器获取到锁的时候,其他的服务器就无法获取,则可以避免集群,分布式环境下重复执行的问题。


关键字:     redis分布式锁  
博主信息

勿扰
简介:对自己狠一点,社会才会对你好一点!
4年1月
QQ
热门文章
Powered by 勿扰 V2.0 湘ICP备18002237号-2     Copyright © 2016-2018 勿扰个人博客 版权所有