spring+quartz 기반 분포 식 정시 작업 프레임 워 크 구현

11397 단어 springquartz분포 식
문제 배경
당 사 는 신속히 발전 하 는 창업 회사 로 현재 200 명 이 있 습 니 다.주요 업 무 는 관광 과 호텔 과 관련 된 것 입 니 다.교체 업데이트 주기 가 비교적 빠 르 기 때문에 개발 자 들 은 더 많은 시간 을 들 여 더욱=교체 의 속 도 를 따라 잡 았 고 전체 시스템 에 대한 통제 가 부족 합 니 다.
군집 하기 전에 회사 의 정시 임무 실현 방식 이 없다.
초기 에 응 용 된 방 문 량 이 그리 크 지 않 았 고 한 대의 서버 가 사용 을 완전히 만족 시 켰 으 며 응용 프로그램 에서 정기 적 인 작업 을 수행 해 야 하 는 경우 가 많 았 다.
군집 이 생 긴 후 회사 의 정시 임 무 를 실현 하 는 방식.
사용자 가 증가 함 에 따라 방 문 량 도 증가 하고 한 대의 서버 가 높 은 병행 요 구 를 만족 시 키 지 못 하기 때문에 회 사 는 응용 을 클 러 스 터 에 배치 하고 전단 은 nginx 프 록 시(응용 서버 ip 은 방화벽 으로 격 리 되 어 ip+포트+응용 이름 으로 직접 방문 하 는 방식 을 피 할 수 있 습 니 다).
클 러 스 터 환경 에서 똑 같은 정시 임 무 는 클 러 스 터 에 있 는 모든 기계 에서 실 행 됩 니 다.그러면 정시 임 무 는 반복 적 으로 실 행 됩 니 다.서버 의 부담 을 증가 할 뿐만 아니 라 정시 임 무 를 반복 적 으로 수행 하기 때문에 예상 치 못 한 오 류 를 초래 할 수 있 습 니 다.따라서 회사 의 해결 방안 은 클 러 스 터 의 수량 에 따라자,정시 임무 중의 임 무 를 클 러 스 터 의 모든 기계 에 평균 적 으로 나 누 어 줍 니 다.
 현재 군집 중 정시 임무 실현 방식 의 결함
현재 회사 가 클 러 스 터 에서 정시 임 무 를 처리 하 는 방식 은 진정한 분포 식 처리 방식 이 아니 라 가짜 분포 식(회사 내부 에서 흔히 흙 방법 이 라 고 부른다)이다.이런 방식 에 현저 한 결함 이 존재 하 는데 바로 클 러 스 터 에서 기계 가 다운 되면 전체 정시 임 무 를 끊 거나 한꺼번에 다 뛰 지 못 하면 업무 에 심각 한 영향 을 줄 수 있다.
결함 에 대한 해결 방안(본 고의 중점 점)
spring+quartz 를 이용 하여 진정한 분포 식 정시 임무 시스템 을 구축 하고 관련 자 료 를 조회 한 결과 quartz 프레임 워 크 는 원래 분포 식 정시 임 무 를 지원 하 는 것 임 을 알 수 있다.
 개발 IDE:Intellij IDEA
JDK 버 전:1.8
Spring 버 전:4.2.6
Quartz 버 전:2.2.1
Spring 과 Quartz 통합 설정

<?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

  <context:component-scan base-package="com.aaron.clusterquartz.job"/>

  <bean name="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <!-- tomcat -->
    <!--<property name="jndiName" value="java:comp/env/jndi/mysql/quartz"/>-->

    <!-- jboss -->
    <property name="jndiName" value="jdbc/quartz"/>
  </bean>
  <!--         start -->

  <!--      -->
  <bean name="executor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="15"/>
    <property name="maxPoolSize" value="25"/>
    <property name="queueCapacity" value="100"/>
  </bean>

  <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
  </bean>

  <!--       -->
  <bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="configLocation" value="classpath:quartz.properties"/>
    <property name="dataSource" ref="dataSource"/>
    <property name="transactionManager" ref="transactionManager"/>

    <!--        ,         -->
    <property name="schedulerName" value="baseScheduler"/>

    <!--                    -->
    <property name="overwriteExistingJobs" value="true"/>
    <property name="applicationContextSchedulerContextKey" value="appli"/>

    <property name="jobFactory">
      <bean class="com.aaron.clusterquartz.autowired.AutowiringSpringBeanJobFactory"/>
    </property>

    <property name="triggers">
      <list>
        <ref bean="printCurrentTimeScheduler"/>
      </list>
    </property>
    <property name="jobDetails">
      <list>
        <ref bean="printCurrentTimeJobs"/>
      </list>
    </property>

    <property name="taskExecutor" ref="executor"/>

  </bean>

  <!--   Job   -->
  <bean name="printCurrentTimeJobs" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <property name="jobClass" value="com.aaron.clusterquartz.job.PrintCurrentTimeJobs"/>
    <!--      spring   ,          scheduler   -->
    <!--<property name="jobDataAsMap">
      <map>
        <entry key="clusterQuartz" value="com.aaron.framework.clusterquartz.job.ClusterQuartz"/>
      </map>
    </property>-->
    <property name="durability" value="true"/>
    <property name="requestsRecovery" value="false"/>
  </bean>

  <!--        -->
  <bean name="printCurrentTimeScheduler" class="com.aaron.clusterquartz.cron.PersistableCronTriggerFactoryBean">
    <property name="jobDetail" ref="printCurrentTimeJobs"/>
    <property name="cronExpression">
      <value>0/10 * * * * ?</value>
    </property>
    <property name="timeZone">
      <value>GMT+8:00</value>
    </property>
  </bean>

  <!--         end -->
</beans>

quartz 속성 파일

#============================================================================
# Configure JobStore
# Using Spring datasource in quartzJobsConfig.xml
# Spring uses LocalDataSourceJobStore extension of JobStoreCMT
#============================================================================
org.quartz.jobStore.useProperties=true
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 5000
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.txIsolationLevelReadCommitted = true

# Change this to match your DB vendor
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate


#============================================================================
# Configure Main Scheduler Properties
# Needed to manage cluster instances
#============================================================================
org.quartz.scheduler.instanceId=AUTO
org.quartz.scheduler.instanceName=MY_CLUSTERED_JOB_SCHEDULER
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false


#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

관련 클래스 설명
AutowiringSpringBeanJobFactory 클래스 는 scheduler 에서 spring 주 해 를 사용 할 수 있 도록 하기 위해 서 입 니 다.주 해 를 사용 하지 않 으 면 이 클래스 를 적용 하지 않 고 직접 사용 할 수 있 습 니 다.
SpringBeanJobFactory

package com.aaron.clusterquartz.autowired;

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;

/**
 * @author 
 * @description  job   spring     
 * @date 2016-05-27
 */
public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware
{
  private transient AutowireCapableBeanFactory beanFactory;

  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
  {
    beanFactory = applicationContext.getAutowireCapableBeanFactory();
  }


  @Override
  protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception
  {
    Object job = super.createJobInstance(bundle);
    beanFactory.autowireBean(job);
    return job;
  }
}


package com.aaron.clusterquartz.job;

import com.arron.util.DateUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.util.Date;

/**
 * @author 
 * @description            
 * @date 2016-05-23
 */
public class PrintCurrentTimeJobs extends QuartzJobBean
{
  private static final Log LOG_RECORD = LogFactory.getLog(PrintCurrentTimeJobs.class);

  //           AutowiringSpringBeanJobFactory     @Autowired  ,                 
  @Autowired
  private ClusterQuartz clusterQuartz;


  protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException
  {
    LOG_RECORD.info("begin to execute task," + DateUtils.dateToString(new Date()));

    clusterQuartz.printUserInfo();

    LOG_RECORD.info("end to execute task," + DateUtils.dateToString(new Date()));

  }
}

테스트 결과:
컴퓨터 가 한 대 밖 에 없 기 때문에 저 는 8080 과 8888 두 개의 포트 를 열 어 테스트 했 습 니 다.위의 정시 임 무 는 10 초 에 한 번 씩 실 행 됩 니 다.
내 가 8080 포트 를 시작 할 때 콘 솔 이 10 초 마다 문 구 를 인쇄 하 는 것 을 볼 수 있다.

두 포트 가 동시에 시 작 된 비교 테스트 에서 볼 수 있 듯 이 한 포트 만 이 정시 작업 을 하고 있다.
 
 이것 은 정시 작업 을 하고 있 는 포트 를 닫 은 후,이전의 다른 뛰 지 않 은 포트 가 연결 되 기 시작 하여,정시 작업 을 계속 실행 합 니 다.

이로써 우 리 는 분포 식 정시 임무(또는 군집)에서 같은 시간 에 하나의 정시 임무 만 운행 하 는 것 을 똑똑히 볼 수 있다.
전체 demo 주소:http://xiazai.jb51.net/201701/yuanma/spring-cluster-quartz_jb51.rar
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기