前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >分布式架构下的定时任务及分布式任务锁实现

分布式架构下的定时任务及分布式任务锁实现

作者头像
攻城狮的那点事
发布2019-06-28 11:13:39
1.3K0
发布2019-06-28 11:13:39
举报

定时任务的需求在众多应用系统中广泛存在, 从实现的技术上来分类,目前主要有三种技术:

1,Java自带的java.util.Timer类。

这个类允许你调度一个java.util.TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行。

代码语言:javascript
复制
class MyTask extends TimerTask{    @Override    public void run() {        System.out.println("This is a test data!");    }}public class Job {    public static void main(String[] args) {        //创建定时器对象        Timer t=new Timer();   long delay = 0;//延时执行时间,单位毫秒   long intevalPeriod = 1 * 1000;        t.schedule(new MyTask(), delay, intevalPeriod);    }}

2,使用Quartz。

这是一个功能比较强大的的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行,配置起来稍显复杂。

在Spring中声明并且配置作业调度的触发方式:

代码语言:javascript
复制
<!-- 任务类 -->    <bean id="taskJob" class="com.XXX.MyTask />
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="group" value="job_work" />
    <property name="name" value="job_work_name" />
    <!--false表示等上一个任务执行完后再开启新的任务 -->
    <property name="concurrent" value="false" />
    <property name="targetObject">
        <ref bean="taskJob" />
    </property>
    <property name="targetMethod">
        <value>job</value>
    </property>
</bean>
<bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">      
    <property name="name" value="work_default_name" />
    <property name="group" value="work_default" />
    <property name="jobDetail">
        <ref bean="jobDetail" />
    </property>
    <property name="cronExpression" value="0/10 * 09-16 * * ?"/>
</bean>
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="myTrigger"/>
        </list>
    </property>
</bean>

任务执行类:

代码语言:javascript
复制
public class MyTask{
    public void job(){
        //TODO 要执行的方法
        System.out.println("quartz task ......");
代码语言:javascript
复制
    }
}

这里 Quartz的作业触发器有两种,分别是:

org.springframework.scheduling.quartz.SimpleTriggerBean

org.springframework.scheduling.quartz.CronTriggerBean

第一种SimpleTriggerBean,只支持按照一定频度调用任务,如每隔一段时间运行一次。

第二种CronTriggerBean,支持到指定时间运行一次,如每天12:00运行一次。

3,Spring3.0以后自带的task。

可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多。

代码语言:javascript
复制
@Componentpublic class SchedulerJob {

	/**	 * 每天0点执行一次	 *	 */	@Scheduled(cron = "0 0 0 * * ?")	public void job1(){		//TODO 要执行的任务	}		/**	 * 每5秒执行一次	 *	 */	@Scheduled(fixedRate = 5000)	public void job2(){		//TODO 执行的任务	}
}

在分布式环境中,当带定时任务的服务做集群时,怎么才能确保计划任务最多同时执行一次呢?这时我们就需要用任务锁来解决,如果正在一个节点上执行任务,它将获取一个锁,以防止从另一个节点(或线程)执行相同任务。具体实现方式很多,如支持Mongo、数据库、redis、hazelcast或zookeeper等协调的spring scheduled task。这里我讲讲用mysql数据库和Redis的实现。

1,用mysql实现定时任务锁

代码语言:javascript
复制
CREATE TABLE `job_manager` (
`job_id` int(20) NOT NULL PRIMARY KEY COMMENT '主键',  `job_name` varchar(50) NOT NULL COMMENT '名称',  `job_desc` varchar(50)  COMMENT 'job描述',  `server_ip` varchar(50) NOT NULL COMMENT '服务器ip',  `is_locked` tinyint(1) DEFAULT 0 COMMENT '任务是否锁定 0-否,1-是',  `update_date` datetime NOT NULL COMMENT '更新时间') ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='job管理'

当某一节点上的任务获取锁时,就修改数据库job_manager中的is_locked 字段到1,另一个节点在执行前获取此任务信息,并判断锁定状态,如果已经锁定,就不在执行,这样就防止多节点同时执行某一定时任务。

2,通过Redis实现任务锁

下面为 Redis加锁和解锁的方法实现,在加锁时,为防止任务执行完不能释放,因此给锁设了过期机制。

代码语言:javascript
复制
/**
 *  加锁
 */
public boolean lock(String key, String value){     boolean bool = stringRedisTemplate.opsForValue().setIfAbsent(key, value);     if(bool){       	//锁有效期5分钟       	stringRedisTemplate.expire(key, 300, TimeUnit.SECONDS);     }     return bool;}

/**
 *  解锁
 */
public void unLock(String key){	stringRedisTemplate.delete(key);}

任务实现方式:

代码语言:javascript
复制
@Componentpublic class SchedulerJob {

	/**	 * 每5分钟执行一次	 */	@Scheduled(cron = "0 0/5 * * * ?")	public void job1(){		String key = "test";		String value = "test";		if(!cacheService.isExistLock(key)){			try {				if(cacheService.lock(key, value)){					//TODO 要执行的任务				}			} catch (Exception e) {				//异常处理			}finally {				if(cacheService.isExistKey(key)){
                    //解锁
					cacheService.unLock(key);				}			}		}	}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-12-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 攻城狮的那点事 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档