자동화 slecs

블로그 배치 처리 속도와 파싱 정확도를 동시에 높인 방법

목차

배치 작업은 늘 이중 과제다. 하나는 속도, 하나는 정확도인데, 이번엔 둘 다 개선할 수 있었다. 블로그 글 강화 배치의 v2로 나아가면서 ThreadPool 기반의 병렬 처리와 구분자 파싱 로직을 새로 적용했고, 그 과정에서 배치 시스템을 어떻게 진화시켜야 하는지 다시 생각해볼 기회였다.

v1에서 본 병목, 그리고 결정

사실 처음부터 병렬화가 필요했던 건 아니었다. v1은 단순했다. 블로그 글들을 순차적으로 처리하면서 텍스트를 강화하는 작업인데, 데이터가 쌓이고 글의 개수가 늘어나니 처리 시간이 선형으로 증가했다. 뭔가 해야 할 때가 왔다.

병렬 처리를 도입할지는 단순한 기술 선택이 아니었다. 이 배치는 야간에 스케줄되어 있었고, 동시성 도입이 데이터베이스 커넥션이나 API 호출에 영향을 미칠 수 있다는 점을 먼저 체크했다. ThreadPool을 선택한 건 GIL이 있는 파이썬의 한계를 알면서도, 이 작업이 I/O 바운드(API 호출, 데이터 읽기)라는 판단 때문이었다. 스레드 수도 신중하게 설정했다. 무작정 크게 하면 리소스 고갈이 될 수 있으니까.

구분 v1 (순차 처리) v2 (ThreadPool)
처리 방식 1개씩 순차 N개 동시 처리
I/O 대기 각 작업이 완료될 때까지 블로킹 대기 중 다른 작업 진행
리소스 관리 단순함 스레드 수 관리 필요
디버깅 용이 경합 상태(race condition) 주의

구분자 파싱: 데이터 정확도를 위한 선택

v2에서 또 다른 개선점은 구분자 파싱이었다. 블로그 글 강화 과정에서 텍스트를 여러 섹션으로 나누고, 각 섹션을 다르게 처리해야 하는 상황이 있었다. v1은 정규식이나 간단한 문자열 split으로 처리했는데, 엣지 케이스(단락 중 특수 문자, 마크다운 구분자 혼재 등)에서 자주 실패했다.

구분자를 명시적으로 정의하고, 파싱 로직을 더 견고하게 짜면:

# 패턴: 구분자 기반 파싱으로 정확한 경계 추출
lines = content.split('\n')
sections = []
current_section = []
for line in lines:
    if DELIMITER in line:  # 명확한 구분자 체크
        if current_section:
            sections.append('\n'.join(current_section))
            current_section = []
    else:
        current_section.append(line)

이런 식으로 개선하니 처리 실패율이 눈에 띄게 줄었다. 데이터 품질이 높아지니 다운스트림에서 문제 보고도 줄었다.

회고: 언제 최적화하고, 언제 멈출까

배치 작업 최적화를 하다 보니 느끼는 게, 타이밍이 정말 중요하다는 것. 너무 일찍 병렬화하면 복잡도만 올라가고 이득이 없을 수도 있다. 그런데 필요한 시점에 너무 미루면, 한 번 할 때 한계까지 가야 해서 리뷰도 어려워진다.

이번엔 운 좋게도:
- 데이터 증가 추이를 보고 타이밍을 잡을 수 있었음
- 병렬 처리 + 파싱 개선을 동시에 묶을 수 있어서 한 PR로 리뷰 받을 수 있었음
- 배치 성공률과 속도 양쪽 메트릭을 모니터링할 수 있었음

비슷한 배치 작업들도 앞으로 이 패턴을 참고할 것 같다. 성능과 정확도는 다른 축인 것처럼 보이지만, 결국 같은 방향을 바라본다. 속도만 높이면 실수가 늘고, 정확도만 챙기면 처리 시간이 길어진다. 둘을 함께 개선하는 게 운영 효율성을 정말 높인다.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.