'spring framework/spring-batch'에 해당되는 글 4건

  1. 2013.11.13 JAXP DOM4J, JDOM2의 성능 비교
  2. 2013.01.11 Spring Batch Admin
  3. 2012.08.28 JobLauncher, SimpleJobLauncher
  4. 2012.08.25 JobParametersIncrementer의 사용.

DZONE의 Java&XML에 관련된 글 3개가 마무리된 듯하다.

http://java.dzone.com/articles/java-and-xml-part-1

http://java.dzone.com/articles/java-and-xml-part-2

http://java.dzone.com/articles/java-and-xml-part-3-jaxb


기존의 RDB에 데이터를 저장하는것으로는 한계에 부딪쳐서, Key-Document 형태로  저장한다. 이 Document는 XML이며 여기에서 XPath기반으로 데이터를 추출해야한다. 뭐 몇건안되면 문제가 안되겠지만.. 몇건이 된다는 거다. 
6core * cpu 2개, 메모리16G  2대로 이 키워드 추출 부분을 소화해내야 하는데 하루에 몇억건이므로 성능을 무시할 수는 없다

현재는 StAX을 커스텀 마이징한 XML리더와, XPATH를 사용하기 위한 DOM(Java6)을 사용하고 있다. 여기에서 JDOM2으로 변경을 확인해보고 싶어서. 실제로 사용하는 1.2GB XML파일 아.. 다운받는데도 몇분이야 130MB의 welformed XML을 가지고 테스트 하였다.


XPath 표현식은 1개/ 3개일 경우를 테스트 했고, 가능한 로직은 동일하게 했다


1. DOM

for(int index=0; index<expres.size(); index++){

NodeList nodes = (NodeList) xPath.compile( expres.get(index) ).evaluate(document, XPathConstants.NODESET);

total = total + nodes.getLength(); 

}


2. JDOM2 (2.0.2)

for(int index=0; index<exps.size(); index++){

List<Object> nodes = xpathFactory.compile( exps.get(index) ).evaluate(document);

total = total + nodes .size();

}




 

 TOTAL

  DOM4J

 JDOM2 

 XPATH 1건 

 127286

  약 25 - 30초

  약 5-6초

 XPATH 3건

 636430

  안끝나... 

  약 20초


현재 알파버전이다 JDK 기본 파서를 이용하고 있지만, 고려하고 있던 VTD와, JDOM2등... 적용로직마다 최적의 파서를 선택하는게 중요한 일임을 다시 한번 깨닫는다 (안끝나...) , 물론 이번에 만든 파서도 개량하는것도 중요하고...


ps, 쓰고보니.. 사내 위키에 VTD, JDOM, StAX등의 성능 비교글이 있네... ㅠㅠ; 단 2011년 글이고 내가 정말 필요한 XPath글은 아니라 참고만 하면될듯하다.

신고

'spring framework > spring-batch' 카테고리의 다른 글

JAXP DOM4J, JDOM2의 성능 비교  (0) 2013.11.13
Spring Batch Admin  (0) 2013.01.11
JobLauncher, SimpleJobLauncher  (0) 2012.08.28
JobParametersIncrementer의 사용.  (0) 2012.08.25

Spring Batch Admin

spring framework/spring-batch 2013.01.11 17:34 posted by dev.bistro


단순히, Batch모듈을 쓰고 있다가. Integration과 함께 무엇을 할 것인가에 대한 고민중이다.

앞서, 이전 프로젝트에서는 Batch가 어떻게 얼마나 잘 돌았는지 보려고 Batch Admin이라는 유틸성 프로젝트를 연결해보았다. 



내가 쓰던 JobRepository를 연결하고, 실행하면 내 잡들 목록과, BatchAdmin의 기본 잡 2개가 리스트에 나온다. 




각 Job의 실행값들과 결과를 알수있고, Step단계로도 확인할 수 있다.

Step 까지 클릭해서 들어가면 Exit Message도 볼수 있어 배치 실패 이슈를 쉽게 파악할 수 있다.


문제는....

1. 기존의 신규 배치가 아직, 잘 돌아가는 구 배치들이 JobRepository에 맞춰서 (기존 logfile이 아닌, remote log를 쌓아줘야하고...) 또는 SpringBatch로 만들거나...

2. Remote Launch가 프로젝트 파티셔닝 상황에서 잘 되는지도 봐야하고...

3. UI도 맘에 안들고-.-;;; 


신고

'spring framework > spring-batch' 카테고리의 다른 글

JAXP DOM4J, JDOM2의 성능 비교  (0) 2013.11.13
Spring Batch Admin  (0) 2013.01.11
JobLauncher, SimpleJobLauncher  (0) 2012.08.28
JobParametersIncrementer의 사용.  (0) 2012.08.25

JobLauncher, SimpleJobLauncher

spring framework/spring-batch 2012.08.28 15:43 posted by dev.bistro

휴가중(진짜 심심해서 쓰는 ) 포스팅. 작성중


JobLauncher 의 유일한 구현체 SimpleJobLauncher이다.

1. 유일한 public method 'run'을 보면 Job , JobParameters 를 아귀먼트로 받는것을 확인할 수 이고,  return 은  JobExecution이다.

2. JobExecution은 Entity를 상속받는 상태를 나타내는 클래스라 생각해도 된다.



/*
 * Copyright 2006-2008 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.batch.core.launch.support;

/**
 * Simple implementation of the {@link JobLauncher} interface. The Spring Core
 * {@link TaskExecutor} interface is used to launch a {@link Job}. This means
 * that the type of executor set is very important. If a
 * {@link SyncTaskExecutor} is used, then the job will be processed
 * within the same thread that called the launcher. Care should
 * be taken to ensure any users of this class understand fully whether or not
 * the implementation of TaskExecutor used will start tasks synchronously or
 * asynchronously. The default setting uses a synchronous task executor.
 * 
 * There is only one required dependency of this Launcher, a
 * {@link JobRepository}. The JobRepository is used to obtain a valid
 * JobExecution. The Repository must be used because the provided {@link Job}
 * could be a restart of an existing {@link JobInstance}, and only the
 * Repository can reliably recreate it.
 * 
 * @author Lucas Ward
 * @Author Dave Syer
 * 
 * @since 1.0
 * 
 * @see JobRepository
 * @see TaskExecutor
 */

public class SimpleJobLauncher implements JobLauncher, InitializingBean {
	protected static final Log logger = LogFactory.getLog(SimpleJobLauncher.class);
	private JobRepository jobRepository;
	private TaskExecutor taskExecutor;

	/**
	 * Run the provided job with the given {@link JobParameters}. The
	 * {@link JobParameters} will be used to determine if this is an execution
	 * of an existing job instance, or if a new one should be created.
	 * 
	 * @param job the job to be run.
	 * @param jobParameters the {@link JobParameters} for this particular
	 * execution.
	 * @return JobExecutionAlreadyRunningException if the JobInstance already
	 * exists and has an execution already running.
	 * @throws JobRestartException if the execution would be a re-start, but a
	 * re-start is either not allowed or not needed.
	 * @throws JobInstanceAlreadyCompleteException if this instance has already
	 * completed successfully
	 * @throws JobParametersInvalidException
	 */

	public JobExecution run(final Job job, final JobParameters jobParameters)
			throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException,
			JobParametersInvalidException {

		Assert.notNull(job, "The Job must not be null.");
		Assert.notNull(jobParameters, "The JobParameters must not be null.");

		final JobExecution jobExecution;
		JobExecution lastExecution = jobRepository.getLastJobExecution(job.getName(), jobParameters);
		if (lastExecution != null) {
			if (!job.isRestartable()) {
				throw new JobRestartException("JobInstance already exists and is not restartable");
			}
		}

		// Check the validity of the parameters before doing creating anything
		// in the repository...
		job.getJobParametersValidator().validate(jobParameters);

		/*
		 * There is a very small probability that a non-restartable job can be
		 * restarted, but only if another process or thread manages to launch
		 * and fail a job execution for this instance between the last
		 * assertion and the next method returning successfully.
		 */

		jobExecution = jobRepository.createJobExecution(job.getName(), jobParameters);

		try {
			taskExecutor.execute(new Runnable() {

				public void run() {
					try {
						logger.info("Job: [" + job + "] launched with the following parameters: [" + jobParameters
								+ "]");
						job.execute(jobExecution);
						logger.info("Job: [" + job + "] completed with the following parameters: [" + jobParameters
								+ "] and the following status: [" + jobExecution.getStatus() + "]");
					}
					catch (Throwable t) {
						logger.info("Job: [" + job
								+ "] failed unexpectedly and fatally with the following parameters: [" + jobParameters
								+ "]", t);
						rethrow(t);
					}
				}

				private void rethrow(Throwable t) {
					if (t instanceof RuntimeException) {
						throw (RuntimeException) t;
					}
					else if (t instanceof Error) {
						throw (Error) t;
					}
					throw new IllegalStateException(t);
				}
			});
		}
		catch (TaskRejectedException e) {
			jobExecution.upgradeStatus(BatchStatus.FAILED);
			if (jobExecution.getExitStatus().equals(ExitStatus.UNKNOWN)) {
				jobExecution.setExitStatus(ExitStatus.FAILED.addExitDescription(e));
			}
			jobRepository.update(jobExecution);
		}

		return jobExecution;
	}

	public void setJobRepository(JobRepository jobRepository) {
		this.jobRepository = jobRepository;
	}

	public void setTaskExecutor(TaskExecutor taskExecutor) {
		this.taskExecutor = taskExecutor;
	}

	public void afterPropertiesSet() throws Exception {
		Assert.state(jobRepository != null, "A JobRepository has not been set.");
		if (taskExecutor == null) {
			logger.info("No TaskExecutor has been set, defaulting to synchronous executor.");
			taskExecutor = new SyncTaskExecutor();
		}
	}

}

---
public class JobExecution extends Entity {
	private JobInstance jobInstance;
	private volatile Collection stepExecutions = new CopyOnWriteArraySet();
	private volatile BatchStatus status = BatchStatus.STARTING;
	private volatile Date startTime = null;
	private volatile Date createTime = new Date(System.currentTimeMillis());
	private volatile Date endTime = null;
	private volatile Date lastUpdated = null;
	private volatile ExitStatus exitStatus = ExitStatus.UNKNOWN;
	private volatile ExecutionContext executionContext = new ExecutionContext();
	private transient volatile List failureExceptions = new CopyOnWriteArrayList();

       하략 ... 대부분 생성자/Get/Set



참고#1: http://chanwook.tistory.com/797

요약 : 4년전 교육 받았을때도 느꼈지만... 박찬욱님 짱 :)

신고

'spring framework > spring-batch' 카테고리의 다른 글

JAXP DOM4J, JDOM2의 성능 비교  (0) 2013.11.13
Spring Batch Admin  (0) 2013.01.11
JobLauncher, SimpleJobLauncher  (0) 2012.08.28
JobParametersIncrementer의 사용.  (0) 2012.08.25


Job Parameter를 자동으로 Increment 하기 위해서 사용.

(Job의 구현체를 구분하는 방법은 Job + Job Parameter이기 때문에, Parameter없이는 같은 job을 계속 실행하면 안된다)





@Component
public class SimpleJobParametersIncrementer implements JobParametersIncrementer {

	static final SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd-hhmmss");
	public JobParameters getNext(JobParameters parameters) {
		String id = format.format(new Date());
		return new JobParametersBuilder().addString("run.id", id).toJobParameters();
	}

}
	
        
	    
	

	
		


요약
1. JobParametersIncrementer 구현
2. JobExplorerFactoryBean bean 설정
3. job에 increment로 1번 설정
4. 실행은 xmlfile jobanme [-next] 를 추가

참고

http://numberformat.wordpress.com/2010/02/07/multiple-batch-runs-with-spring-batch/


참고2 [BATCH_JOB_PARAMS] 테이블

JOB_INSTANCE_ID TYPE_CD KEY_NAME STRING_VAL DATE_VAL LONG_VAL DOUBLE_VAL

3 STRING run.id 20120825-124631 1970-01-01 09:00:00 0 0

4 STRING run.id 20120825-125909 1970-01-01 09:00:00 0 0


참고3. 기본적으로 제공하는 crementer는

org.springframework.batch.core.launch.support.RunIdIncrementer 가 있고 key를 프로퍼티로 받는다. 

https://fisheye.springsource.org/browse/spring-batch/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/RunIdIncrementer.java?r=488ba7a37b70c62a2ac40d6c945ea940408add80


신고

'spring framework > spring-batch' 카테고리의 다른 글

JAXP DOM4J, JDOM2의 성능 비교  (0) 2013.11.13
Spring Batch Admin  (0) 2013.01.11
JobLauncher, SimpleJobLauncher  (0) 2012.08.28
JobParametersIncrementer의 사용.  (0) 2012.08.25


티스토리 툴바