quartz mysql索引_分布式系统中的定时任务全解(二)

在实际项目中,通常需要用到定时任务(定时作业),spring框架提供了很好的实现。 1、  下载spring-quartz插件包 这里默认当前系统中是集成了spring框架的基本功能的。去网上下载spring定时器的jar包,这里用的是quartz-all-1.8.4.jar,下载完成之后添加的项

概述

上一篇分布式系统中的定时任务全解(一)中对定时任务和定时任务的基础使用方式进行了说明。这一小节,把分布式场景下的定时任务进行一个大致的讲解。

什么是分布式场景呢,当单台服务器服务能力不够的时候,就需要更多的服务器进行水平向的扩展,由多台服务器分工(任务量上的水平划分,而非业务线上的垂直划分)的方式来增强服务能力,提供更强的并发请求处理,更短的时间响应。

像第一节说到的定时任务使用场景,大多是一次任务执行仅能有一个服务器在执行,如果是所有服务器都在执行相同的任务,一个是会造成错误,就算不会造成错误,很多服务器在做重复的工作也是极大的浪费。

所以,分布式场景下定时任务要做的一个基本难点就是:怎么让某一个定时任务,在一个触发时点上仅有一台服务器在执行。

更进一步,如果,你的定时任务涉及到很多同类型的数据要处理,比如说要处理100个输入文件,处理方式相同;再比如说你的数据库已经做了分库处理,业务数据被写入到了10个数据库实例中,处理方式相同。那么此时,可以让更多台服务器执行定时任务,每台执行其中的一部分,比如10个输入文件;再比如1个数据库实例中的业务数据。

以上两种场景怎么办呢?第一种很简单,后续会提供三种方式去做:1.设置某一台为任务执行服务器,其他服务器不执行;2.使用quartz的集群功能,实现某一台执行;3.使用当当开源的elastic-job,实现某一台执行。第二种场景只有第一种场景中的第3中方式可以做到。

接下来逐个看一下。

实现分布式的方式

设置某一台为任务执行服务器

这种方式可以采用环境变量的方式来实现,定时任务运行时检查本机的环境变量值是否为可执行,如果是则执行定时任务,如果不是则直接返回。

@Value("${ISTIMERRUNNER}")

private String isTimerRunner;

@Scheduled(cron="0 0 0 * * ? ")

public void task(){

try {

if("true".equals(isTimerRunner)){

//do something.....

}

} catch (Exception e) {

e.printStackTrace();

}

}

这里有一个需要注意的事项,如果集群环境下,你使用了脚本部署的方式,而且是类似于作者的方式。也就是先把文件拷贝到一台服务器,启动好后,调用脚本(脚本参见:http://blog.csdn.net/buqutianya/article/details/51062384),逐个部署到其他服务器。那么,你就需要注意一下了。

远程ssh调用startup.sh时,tomcat取不到环境变量,这里需要把startup.sh的顶部进行修改:

#!/bin/sh --login

当然这里还有另外一种方式,就是在tomcat的bin目录中添加一个setenv.sh文件,startup.sh执行时会加载其中的内容。

export ISTIMERRUNNER=true

这种方式有十分明显的缺陷:1.单点,当任务执行节点出现问题时,整个定时任务全部over;2.资源分配不均衡,随着定时任务的增多,任务执行服务器的资源占用压力会越来越大。

当然了,这是在技术能力不够的时候,最简单有效的实现方式。

使用quartz的集群功能

quartz这个老牌的定时任务执行工具,在集群方面也提供了很好的支持。quartz的集群是借助数据库来实现的,所有的服务器实例共享一套数据库表中存储的任务、触发器和调度器信息,实现一个时间点,同一个任务仅有一台服务器在执行。而且提供了负载均衡和failover失败转移功能。

quartz的负载均衡大概是这样的策略:对于需要调度很多任务的调度器,会近似随机的选择服务器执行;对于调度的任务数比较少的(1个或者2个)的触发器,会尽量的在同一台服务器上执行。(可以参见这里:http://www.quartz-scheduler.org/documentation/quartz-2.2.x/tutorials/tutorial-lesson-11.html)一、Quartz的特点 按作业类的继承方式来分,主要有以下两种: 作业类继承org.springframework.scheduling.quartz.QuartzJobBean类的方式作业类不继承org.springframework.scheduling.quartz.QuartzJobBean类的方式 注:个人比较推崇第二种,因为这种方式下的

quartz的集群使用也不复杂,接下来一起看一下:

1.导入数据库表

quartz的集群是基于数据库实现的,所以首先要把数据库表结构创建好。创建脚本在quartz的完整下载包里可以找到(官网下载地址:http://www.quartz-scheduler.org/downloads/)。

解压之后,在docs/dbTable目录下可以找到你想要的所有常见数据库类型的创建脚本。

7b153d272f10cac2a55eea739f6b95f4.png

我使用的是sql数据库,所以使用了tables_mysql_innodb.sql。

这里导入的时候遇到了一个问题,就是创建索引时索引字段过长。这里我采用的方法是把所有的scheduler的长度变成了50,修改之后也就是会限制所有的scheduler的名字在50个字节以内。

2.创建支持集群的scheduler

集群和非集群的配置不同,关键就在于scheduler,集群时需要给scheduler配置数据源、将org.quartz.jobStore.isClustered设置为true、以及配置quartz.properties属性文件。详细的实现方式可以参见:http://sundoctor.iteye.com/blog/486055

使用elastic-job

elastic-job是基于quartz实现的,最大的不同点是elastic-job把做为共享中心的数据库换成了zookeeper。所以要使用elastic-job首先要安装zookeeper。

安装好zookeeper之后,使用elastic-job也不难,它做了很好的spring集成支持,只需要配置注册中心和执行任务的job即可。

以下是一个配置文件的示例:

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:reg="http://www.dangdang.com/schema/ddframe/reg"

xmlns:job="http://www.dangdang.com/schema/ddframe/job"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.dangdang.com/schema/ddframe/reg http://www.dangdang.com/schema/ddframe/reg/reg.xsd http://www.dangdang.com/schema/ddframe/job http://www.dangdang.com/schema/ddframe/job/job.xsd ">

这里简单的说一下elastic-job相对于quartz的优势:

1.使用zookeeper做为协调,更加轻量级,这一点对于使用者来说也是一个困难项,因为无论再小的服务也有一个数据库,所以定时任务也使用数据库,那么用起来省事一点。但使用zookeeper一方面速度快,另一方面是不占用现有数据库的连接和计算资源。

2.支持任务的分片,quartz同一时点,同一任务只能在一台机器上运行,但是elastic-job可以在多台机器上运行,并且能够指定每台服务器上运行的输入分片。比如业务数据在10个数据库,这里总共有5台服务器,那么每台服务器在同一个时点,仅处理其中的2个数据库。做到将可纵向切分的任务,切分给不同的服务器,充分利用资源,加快计算速度。

elastic-job怎么做到的分片,在不同的场景下我们该怎么使用elastic-job,接下来的一节将从源代码的角度进行讲解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值