Jenkins 로 돌리던 Spring Batch trigger 속도 올리기 (1분 내에 여러번 배치 돌리기)

들어가며

Jenkins로 Batch 를 돌리고 있었는데 1분에 한번씩 돌리던 배치를 10초 이내로 줄여야했다.

Jenkins는 Batch 전용 인터페이스도 아니긴 하지만 어쨌던 다른 데몬을 구현하기는 귀찮았다.  Cron이나 Quartz 도 1분 이내로 빨리 돌리는 방법은 없다. 꼼수는 존재하더라. Jenkins도 꼼수는 존재하지만.. 여튼 빠르게 인터넷을 검색했다.

일단 인터넷에 검색해보니 mkyong 님의 가이드는 존재했다. 인터넷에서 Spring 관련 글을 검색하면 나오는 그것.

정석

1
2
3
4
5
6
7
<task:scheduled-tasks>
  <task:scheduled ref="runScheduler" method="run" fixed-delay="5000" />
</task:scheduled-tasks>
<task:scheduled-tasks>
  <task:scheduled ref="runScheduler" method="run" cron="*/5 * * * * *" />
</task:scheduled-tasks>

2가지 타입이 존재하는데 위의것은 5초의 딜레이를 주는 것이고 아래것은 5초에 한번씩 돌도록 하는 것이다.
배치라면 병행해서 돌면 안되니까 위의 것으로 선택하는게 맞겠다.

그런데… 나는 가이드가 있다는 내용만 개발자에게 넘기고 개발이 완료 되었다고 해서 Merge 하고 테스트 해보니 잘 되어서 운영에 올렸다.

문제 발생

그런데 개발에서 MySQl이 에러를 내기 시작했다.
MySQL이 “Deadlock found when trying to get lock; try restarting transaction” Exception
뭐가 잘못된 것일까 운영에서도 곧 에러가 생길까? 일단 하루가 지났는데 운영에는 별 문제가 없었고 개발을 살펴보고 있다가 MySQL에서는 read 할 때 uncommited, commited, repeatable read 등 여러가지 select option 이 존재하는 것을 확인하였다.

1
2
3
4
5
<batch:job-repository id="5jobRepo"
 data-source="dataSourcePool"
 transaction-manager="transactionManager"
 isolation-level-for-create="READ_COMMITTED"
 table-prefix="BATCH_" />

그래서 Deadlock 이 걸린 원천적인 이유도 확인하지 않고
이걸 해결 하기 위해서 job-repository 의 isolation-level-for-create을 READ_COMMITED 로 바꾸는 실수를 범한다.
나중에 알게 되었지만 1분 이내의 배치 개발은 Mkyong 님의 가이드 중 2번째 것이 선택 되었고 parallel 로 돌기 시작한 것이다.

아차.. 똑같은 배치가 2번 돌때의 데이터가 무너지는 낭패가 발생할 수 있는 상황!!!

일단 LOOP 배치를 내리고 빨리 Mkyong 님의 가이드 중에서 첫번째 것을 적용하기 전에 (소슬 바꾸어야 하므로) Jenkins의 설정을 빠르게 읽어내려갔다.

그러다 JOB이 끝나면 다음 JOB을 트리거 할 수 있는데 자기 자신도 선택 할 수 있다는 사실을 알았다.

JOB과 JOB을 트리거 걸고 그 사이에 sleep 을 준 후 Jenkins 시작시에 JOB을 시작하게 하면 이보다 더 좋은 LOOP Batch 는 없을 것 같다는 생각이 들었다.

해결 방법

1. jenkins에 startup trigger plugin 설치

1-1. JOB에 시작시 실행 옵션을 지정

2. JOB 실행 완료후 POST build 에 같은 JOB을 지정

3. Execute Sheel 에 “sleep 15s” 를 추가하여서 매 JOB 사에 잠깐의 휴식시간을 줌.

개이득

만일 처음부터 Mkyong 님의 가이드 중 fixed-delay를 사용했더라면 어땠을까? 일단 sleep time이 source 에 박힌다. jenkins는 UI상에서 delay time을 조정할 수 있다.  물론 Jenkins를 이용해서 배치를 trigger 하고 있는 상황에서나 가능한 설정이지만 말이다. 유용한 툴은 언제나 유용하다.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다