티스토리 뷰
현재 몸담고 있는 회사에서 Spring Batch 버전 업그레이드를 준비중이다. 규모가 작거나 문제가 발생해도 금방 고칠 수 있다면 쉽게 진행하겠지만 그렇지 못하기에 굉장히 조심스럽게 작업을 진행하고 있다.
이 작업을 준비하다 보니, 예전 처음 Spring Batch를 만났을 때가 기억이 나서 블로그에 기록으로 남긴다.
1.
2007년. 벌써 14년전에 Spring Batch를 처음 대규모 업무에 적용하려고 했다. 당시 정식 버전도 아닌 베타 버전이 나왔던 때였고 거기다 배치를 자바로 한다는 것은 말도 안된다고 생각하던 때이다. 배치는 역시 C여야 한다는 시대였다. 그런데 자바에다가 Spring Batch를 적용한다는 것은 쉬운 결정이 아니였다.
처음 계획은 OLTP는 자바, 배치는 C 였지만 굉장히 어렵고 지루한 검증과 테스트를 거쳐 결국 둘다 자바로 결정했었다.
2.
Spring Batch에 대한 개념을 개발자들이나 설계자들에게 이해시키는 것도 쉽지 않았다. Spring Batch에 대한 Reference 문서를 살펴보면 첫 단원에 다음 문장이 나온다.
SpringSource and Accenture have collaborated to change this. Accenture's hands-on industry and technical experience in implementing batch architectures, SpringSource's depth of technical experience, and Spring's proven programming model together mark a natural and powerful partnership to create high-quality, market relevant software aimed at filling an important gap in enterprise Java.
SpringSource의 기술과 Accenture의 경험을 조합해서 만들었다고 하는데 Accenture가 관여해서 그런지 구조나 방향이 굉장히 이상적이였고, 그래서인지 프로젝트에서 너무 컨셉만 요란하다는 공격을 받았다. 한마디로 너희가 배치를 알아? 라는 이야기이다.
(위의 그림은 Spring Batch 2.0의 도식으로 1.0 에는 ItemProcessor가 없었다.)
위의 그림은 Spring Batch 개념을 이해하기 위해 그리고 다른 사람에게 설명하기 위해 많이 사용했던 것이고 또한 지금 생각해도 참 잘 정리된 것이라 생각한다.
그림에서 보는 것과 같이 배치 Job이 있고 그 안에 여러개의 절차(Step)가 있으며 하나의 절차에는 대량건의 데이터를 읽어서(Reader) 이를 처리(Processor)하고 그 결과를 저장(Writer)하는 요소로 구성되어 있다. 아마도 이보다 더 배치를 잘 설명한 그림은 없을 것이다.
많은 배치를 여기에 맞게 개발할 수 있지만 항상 문제가 되는 것은 특별히 예외가 되는 배치들이다. 그리고 그 예외적인 배치들이 업무적으로 굉장히 중요하기에 무시하고 넘어갈 수가 없다.
대표적으로 읽어들여야 하는 데이터의 원천 소스가 굉장히 많을 경우, 그리고 조건에 따라 그것이 달라지는 경우, 저장해야 하는 대상 역시 복잡하게 엮여 있는 경우이다. 실제로 개념 검증(파일럿 프로젝트)을 위해 코볼로 작성되어 있던 배치가 지금 기억으로는 "월말에 보험료 계산해서 청구"하는 것이였는데 입력되는 기준 데이터는 1억건이 넘었고 거기에 연관되어 있는 다른 데이터들, 복잡한 계산 로직, 연계된 타 기관들이 있었으며 저장해야 하는 것 역시 DB 뿐만 아니라 DM 업체, 대용량 프린터, 대외 기관, 은행 등 다양했다. 이 모든게 하나의 코볼 소스에 다 정의 되어 있었다.
3.
프로젝트를 준비하면서 베타버전이 1.0 정식버전으로 발표되었는데 당시 사용할 수 있는 ItemReader / ItemWriter가 DB, FILE, XML 정도였다. 여러가지 논의 끝에 Spring Batch는 배치 JOB과 흐름을 정의하는 용도로만 사용하기로 했다. STEP에 대응하는 Tasklet을 정의하고 그 내부는 기존 배치 스타일 처럼 POJO 기반으로 개발자가 직접 모든 Input/Output을 정의해서 개발하도록 가이드했다.
여러가지 사유가 있었지만, 당시 배치 개발자의 가장 최고의 덕목은 대량의 데이터를 가장 빠르게 처리하도록 개발하는 것이고 또한 프로젝트는 납기를 맞춰 제때 끝내는게 중요했다. 그래서 가급적 STEP 으로 흐름을 제어하되 그 내부는 개발자의 역량에 맡겼다.
4.
처음 설계자들이 배치 JOB을 정의할 때 어려움을 겪었지만 한 두번 시행 착오를 거친 후 그 사상을 이해하고 빠르게 적응했다. 개발자들은 하나의 소스 코드에 JOB의 흐름과 Input / Output을 모두 때려 넣는 방식에서 흐름과 구현을 분리가 가능하게 된 부분에 대해 만족해 했다. 특히 대량 처리를 위해 기존에는 개발자들이 병렬 처리를 직접 구현하였지만 JOB에서 flow를 정의하고 병렬로 동작할 수 있도록 함으로 쉽게 이를 구현이 가능했다. (개발자들이 제일 만족했던 부분이다.)
그래서 데이터 처리가 많은 배치들의 경우 다음과 같은 순서로 많이 정의 되었다.
DB에서 FILE로 대량 데이터를 Unloading 한다 (Unloaindg 도구와 연계했다) -> FILE을 원하는 쓰레드 개수 만큼 분리한다 (파일 처리 솔루션을 연계했다.) -> 파일 개수 만큼 병렬 처리한다 -> 최종 결과를 취합한다 -> 결과를 DB에 Loading 한다 (SQL*Loader를 연계했다.)
또한 Spring Batch에 익숙해지면서 복잡한 배치들은 제외하고 그 외에 단순한 DB to DB, DB to FILE, FILE to DB, FILE to FILE 등의 패턴의 배치는 ItemReader와 ItemWriter를 이용해서 개발에 들어갔다.
5.
그리고 개발자들이 좀 더 Spring Batch를 잘 사용할 수 있도록 많이 사용하는 기능들을 기본 Tasklet으로 정의해서 배포하였다. 대표적으로 Data Unloading (전용 도구 연동) / Data Loading (SQL*Loader 연동) / 파일 분할 / 분할 조합 / FTP / HTTP 호출 / 파일 압축 및 해제 / 암복호화 등이였다. DB는 특히 개발자들에게 ID/PASSWORD를 숨겨야 했기에 이를 고려해서 템플릿 형태의 구성을 하였다.
6.
Spring Batch는 기능적인 면이나 설계적인 면으로도 훌륭하지만 개념적으로도 훌륭하다. 아마도 그 개념을 잡는데 Accenture가 큰 역할을 했을 것이다. 그리고 버전 업그레이드가 되면서도 그 기반이 되는 개념은 변화되지 않고 계속 유지되고 있다. 이러한 점 때문에 Spring Batch가 개인적으로는 참 마음에 든다.
'IT > Practical 모던 자바' 카테고리의 다른 글
[PMJ] var 관련 오류 수정 - 키워드(Keywords), 식별자 (Identifiers) (0) | 2021.03.13 |
---|---|
[PMJ] Spring Batch에 대한 생각 (2) (0) | 2021.03.06 |
[PMJ] Practical 모던 자바 - 자바 언어 변경 내용 확인 방법 (0) | 2020.12.17 |
[PMJ] Practical 모던 자바 - 레코드 (Records) (0) | 2020.10.12 |
[PMJ] Practical 모던 자바 - 텍스트 블록 (Text Blocks) (2) | 2020.10.07 |
- Total
- Today
- Yesterday
- 한라산
- MySQL 8.0
- 티티카카 플라이트 F8
- 서울둘레길
- 한강
- 성판악
- 북경
- 한양도성
- 탄천
- 빈펄 롱비치
- 삼천리자전거
- Practical 모던 자바
- 나트랑
- 베이징
- 티티카카
- 이문열
- TITICACA FLIGHT F8
- 군산오름
- 윗세오름
- 삼국지
- 호캉스
- 영실
- 칼라스10
- 제주
- 자바
- 장윤기
- 중문
- 인사이트
- 백록담
- 나관중
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |