学习分布式定时任务| 青训营笔记

78 阅读3分钟

这是我参与「第五届青训营」伴学笔记创作活动的第12天。

前言

定时器无论是前端程序员还是后端程序员都用过或者实现过类似功能的代码,它在我们实际业务中的应用面还是挺广泛的。因此,这篇笔记主要记录下今天学习和自己以前用过的定时任务。

笔记内容

1.定义

定时任务是指系统为了自动完成特定任务,实时、延时、周期性完成任务调度的过程。 比如,我们碰到这样的业务场景:现在用户在更新个人资料上传头像时,是先执行上传头像进对象存储桶中后点确定保存图片的url进数据库,但是如果用户上传完头像并未点保存,这对用户是个正常操作,用户此时的头像url还是原来的,并未改变。但是,对象存储中却出现了一个没有使用的垃圾资源,就可以通过定时任务去清理。

分布式定时任务是把分散的、可靠性差的定时任务纳入统一的平台,并实现集群管理调度和分布式部署的一种定时任务的管理方式。 可以说,分布式定时任务是随着分布式架构的流行而必然出现的产物

2.发展历程

最开始是Linux命令CronJob,接着是单机定时任务,比如Java中会用到的Timer或者ScheduledExecutorService,接着是一些专门负责任务调度的框架或插件出现,比如Quartz。最后,随着分布式架构逐渐成为主流之后,分布式定时任务也随之出现。

3.使用过的定时任务

笔者在自己曾做过的一个项目里使用过Quartz,使用的场景就是我在定义中提到的清理服务器中的垃圾资源,大致如下:

3-1.引入依赖

首先在项目中引入Quartz的相关依赖:

    <dependency>

      <groupId>org.quartz-scheduler</groupId>

      <artifactId>quartz</artifactId>

    </dependency>

    <dependency>

      <groupId>org.quartz-scheduler</groupId>

      <artifactId>quartz-jobs</artifactId>

    </dependency>

3-2.配置定时器

在配置文件中对定时器进行配置,通过触发器可以指定任务触发的时间以及触发器的数量。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans					http://www.springframework.org/schema/beans/spring-beans.xsd			http://www.springframework.org/schema/mvc						http://www.springframework.org/schema/mvc/spring-mvc.xsd
							http://code.alibabatech.com/schema/dubbo
							http://code.alibabatech.com/schema/dubbo/dubbo.xsd
							http://www.springframework.org/schema/context
							http://www.springframework.org/schema/context/spring-context.xsd">

    <!--spring注解驱动-->
    <context:annotation-config></context:annotation-config>
    <!--注册自定义job-->
    <bean id="clearImgJob" class="cn.cc.jobs.ClearImgJob"></bean>
    <bean id="jobDetail"        
          class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <!-- 注入目标对象 -->
        <property name="targetObject" ref="clearImgJob"/>
        <!-- 注入目标方法 -->
        <property name="targetMethod" value="clearImg"/>
    </bean>
    <!-- 注册一个触发器,指定任务触发的时间 -->
    <bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <!-- 注入JobDetail -->
        <property name="jobDetail" ref="jobDetail"/>
        <!-- 指定触发的时间,基于Cron表达式 -->
        <property name="cronExpression">
            <value>0 0 2 * * ?</value>
        </property>
    </bean>
    <!-- 注册一个统一的调度工厂,通过这个调度工厂调度任务 -->
    <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <!-- 注入多个触发器 -->
        <property name="triggers">
            <list>
                <ref bean="myTrigger"/>
            </list>
        </property>
    </bean>
</beans>

3-3.编写代码

项目中还引入了redis,这里的思路是上传头像时的url存入redis的一个set集合中,接着点击保存后的url再存入另一个set集合,这里对保存的两个set集合进行差值计算,就可以得到那些垃圾图片的地址并删除了。

/**
 * 定时清理垃圾图片
 */
public class ClearImgJob {
    @Autowired
    private JedisPool jedisPool;
    public void clearImg(){
        //根据Redis中保存的两个set集合进行差值计算,获得垃圾图片名称集合
        Set<String> set = jedisPool.getResource().sdiff(RedisConstant.SETMEAL_PIC_RESOURCES, RedisConstant.SETMEAL_PIC_DB_RESOURCES);
        if (set != null){
            for (String picName : set) {
                //删除七牛云服务器上的图片
                QiniuUtils.deleteFileFromQiniu(picName);
                //从Redis集合中删除图片名称    
                jedisPool.getResource().srem(RedisConstant.SETMEAL_PIC_RESOURCES,picName);
                System.out.println(picName);
            }
        }
    }
}

小结

分布式任务调度是一个很实用也很有用的部分,可以让我们的系统功能更加完备。我目前就在考虑给自己的毕设中引入相关框架来为我按时生成账单(这是我系统中的一个功能),从而不用管理人员一个个手动去点,也算是个亮点吧!

参考资料

青训营资料