EC2의 CPU 사용량이 100%에 도달하면서 실행중인 SpringBatch 서버와 Job이 비정상적으로 종료됐다.
DB엔 Job과 Step이 진행중이라는 상태로 남겨졌다.
이러면 다시 Batch 서버를 돌려 다른 Job을 진행하려 해도 이미 진행중인 Job이 있다고 예외를 반환한다.
로그를 뒤져봤을 때 파일내의 중복된 데이터를 제거하는 Step에서 발생했다.
비정상 종료된 Step은 다음 세부 과정으로 진행된다.
(MultiResourcePartitioner
를 사용하고 1525개의 파일이 있다.)
- 중복 책 필터링 MasterStep
- 중복된 {책ID, 도서관ID} 제거.
{1,1},{2,1},{1,1} => {1,1},{2,1}
- 중복 책 필터링 SlaveStep (ChunkSize - 800)
BookIdSet
을@StepScope
로 생성- Reader: 정제된 도서관 소장 도서 csv 파일 읽기 -
close()
호출 시 읽은 파일 삭제- Processor:
BookIdSet
에 존재하면 필터링. 존재하지 않는다면add(BookId)
- Writer: 중복을 제거한 도서관 소장 도서 파일 생성
정말 다행스럽게도 FileReader에서 close()
호출 시에 source 파일을 제거한다는 것이다.
source 파일과 결과 파일은 다른 디렉토리를 사용하게 설계를 해놨다.
그래서 source 디렉토리에 남아있는 파일들만 처리하고 넘어가면 된다.
그래서 단순하게 Job에 파라미터를 약간 바꿔서 시작하는 방식으로 해결했다.
Job 파라미터가 잘못된 부분이 있어서 어짜피 변경해야 했다.
일단 STARTED
, STARTING
상태의 Job과 Step이 있으니 파라미터를 바꾼다고 바로 시작할 수 있는 건 아니다.
비정상 종료된 Step과 Job을 복구하자.
-- JOB 조회 - Job이 많다면 where문에 status = 'STARTED' 추가할 것
select je.job_execution_id, ji.job_name, je.start_time, je.status
from BATCH_JOB_EXECUTION je
join BATCH_JOB_INSTANCE ji on je.job_instance_id = ji.job_instance_id
order by je.job_execution_id;
+------------------+-------------------+----------------------------+-----------+
| job_execution_id | job_name | start_time | status |
+------------------+-------------------+----------------------------+-----------+
...
| 8 | bookSyncJob | 2025-06-15 17:10:38.903384 | COMPLETED |
| 9 | loanAggregatedJob | 2025-06-15 18:02:41.168821 | COMPLETED |
| 10 | bookSpotParentJob | 2025-06-16 00:36:46.240469 | STARTED |
| 11 | stockSyncJob | 2025-06-16 00:36:46.510996 | STARTED |
+------------------+-------------------+----------------------------+-----------+
select status, count(status) from BATCH_STEP_EXECUTION group by status;
+-----------+---------------+
| status | count(status) |
+-----------+---------------+
| COMPLETED | 4968 |
| FAILED | 6 |
| STARTED | 3 |
| STARTING | 1141 |
+-----------+---------------+
-- STARTED: 진행중에 BATCH 서버 다운
-- STARTING: 진행 대기 중에 BATCH 서버 다운
SELECT STEP_NAME, START_TIME, END_TIME, READ_COUNT, WRITE_COUNT, FILTER_COUNT, STATUS
FROM BATCH_STEP_EXECUTION
WHERE STATUS = 'STARTED';
+----------------------------------------+----------------------------+----------+------------+-------------+--------------+---------+
| STEP_NAME | START_TIME | END_TIME | READ_COUNT | WRITE_COUNT | FILTER_COUNT | STATUS |
+----------------------------------------+----------------------------+----------+------------+-------------+--------------+---------+
| stockSyncJobStep | 2025-06-16 00:36:46.449216 | NULL | 0 | 0 | 0 | STARTED |
| duplicatedBookFilterMasterStep | 2025-06-16 01:33:10.853705 | NULL | 0 | 0 | 0 | STARTED |
| duplicatedBookFilterStep:partition1459 | 2025-06-16 03:03:45.321325 | NULL | 80000 | 63123 | 16877 | STARTED |
+----------------------------------------+----------------------------+----------+------------+-------------+--------------+---------+
-- 문제가 발생한 Job Execution(10, 11)의 상태를 FAILED로 변경
UPDATE BATCH_JOB_EXECUTION
SET
STATUS = 'FAILED',
END_TIME = NOW(), -- 종료 시간을 현재로 설정
EXIT_CODE = 'FAILED',
EXIT_MESSAGE = 'MANUALLY UPDATED TO FAILED DUE TO ABNORMAL SHUTDOWN'
WHERE
JOB_EXECUTION_ID IN (10, 11) AND STATUS = 'STARTED';
-- 문제가 발생한 Job Execution(10, 11)에 속한 Step들의 상태를 FAILED로 변경
UPDATE BATCH_STEP_EXECUTION
SET
STATUS = 'FAILED',
END_TIME = NOW(), -- 종료 시간을 현재로 설정
EXIT_CODE = 'FAILED',
EXIT_MESSAGE = 'MANUALLY UPDATED TO FAILED DUE TO ABNORMAL SHUTDOWN'
WHERE
JOB_EXECUTION_ID IN (10, 11) AND (STATUS = 'STARTED' OR STATUS = 'STARTING');
Job에서 처리되는 파일 형식은 파일ID_날짜_파일내용.csv
로 돼있다.
filteredStock
, cleansingStock
두 디렉토리에 있는 겹치는 파일을 확인해본다.
comm -12 \
<(ls cleansingStock | cut -d'_' -f1 | sort | uniq) \
<(ls filteredStock | cut -d'_' -f1 | sort | uniq) \
| while read id; do
ls cleansingStock/${id}_*.csv 2>/dev/null
ls filteredStock/${id}_*.csv 2>/dev/null
echo "-------------------------"
done
다음과 같은 결과를 얻을 수 있었다.
아마 이 두 파일이 작업 도중에 CPU 100%로 멈춘 작업들인 것 같다.
cleansingStock/365_2025-06-02_cleansing.csv
filteredStock/365_2025-06-02_filtered.csv
-------------------------
cleansingStock/735_2025-06-01_cleansing.csv
filteredStock/735_2025-06-01_filtered.csv
-------------------------