LLM 파이프라인의 안정성: 엔진 교체와 슬롯 기반 병렬화 설계
프롬프트 DB 영속화와 콜백 Best-effort 계약으로 안정성을 확보하고, 슬롯 충원 모델로 배치 처리의 병목과 장애 반경을 해소한 설계 결정과 그 대가를 공유합니다.
대규모 텍스트 데이터를 LLM 파이프라인으로 처리할 때 흔히 마주하는 딜레마가 있다. 새로운 모델을 빠르게 실험하고 싶지만, 기존 시스템의 중단 없이 교체해야 하며, 외부 API의 불안정성으로 인한 데이터 유실도 피해야 한다는 점이다. 물류 플랫폼인 우리 솔루션에서도 이미지에서 구조화된 정보를 추출하는 OCR 파이프라인을 운영하며, 이러한 안정성과 확장성 사이의 균형을 어떻게 맞췄는지 그 판단 과정을 공유한다.
제약
이 시스템의 설계는 다음 경계 조건 안에서 이루어졌다.
- 외부 의존성 비가용성: LLM 제공사의 API는 언제든지 지연되거나 중단될 수 있으며, 우리는 이를 통제할 수 없다.
- 데이터 정합성 우선: 추출된 결과가 유실되거나 중복되어서는 안 되며, 최종 상태는 반드시 조회를 통해 확인할 수 있어야 한다.
- 운영 부담 최소화: 모델 교체나 프롬프트 변경 시 재배포 없이 구성만으로 반영할 수 있어야 한다.
- 병렬 처리의 예측 가능성: 대량 배치 처리 시 특정 건의 지연이 전체 파이프라인을 마비시켜서는 안 된다.
한 줄 요약: 프롬프트와 모델을 DB로 분리해 운영 부담을 줄이고, 슬롯 충원 모델로 배치 처리의 장애 반경을 제한했다.
선택지
파이프라인의 안정성을 확보하기 위해 고려한 주요 대안들은 다음과 같다.
1. 단일 엔진 경로 vs 전략 패턴
- 장점: 단일 엔진 경로는 초기 구현이 간단하지만, 모델 교체 시 코드 수정과 재배포가 필수적이다.
- 단점: 전략 패턴은 인터페이스 설계 비용이 발생하지만, 엔진 교체를 런타임 또는 설정으로 가능하게 하여 운영 유연성을 높인다.
2. 배치 배리어 vs 슬롯 충원
- 장점: 배치 배리어는 모든 건이 완료될 때까지 다음 클레임을 차단하므로 순서가 명확하다.
- 단점: 한 건의 지연이 전체 대기열을 막아 장애 반경이 넓어지고, 응답 시간이 예측 불가능해진다.
3. 외부 API 상태 vs DB 영속화
- 장점: 외부 API에 프롬프트를 저장하면 초기 설정이 빠르다.
- 단점: API 셧다운이나 객체 폐기 시 데이터가 영구 손실되며, 버전 관리와 롤백이 어렵다.
결정
우리는 전략 패턴을 통한 엔진 분리와 DB 기반 프롬프트 영속화를 선택했다. 외부 LLM 제공사의 정책 변화(예: API 셧다운)에 대비해 프롬프트 본문과 출력 스키마를 자체 데이터베이스에 저장하기로 했다. 이는 단순한 백업이 아니라, 프롬프트 변경 시 재배포 없이 즉시 반영할 수 있는 운영 인프라다. 엔진 교체 역시 OcrEngine 인터페이스를 통해 구현 클래스를 교체하는 방식으로 처리하여, 코드 수정 없이 설정만으로 새로운 모델을 실험할 수 있도록 했다.
배치 처리의 병렬화 전략에서는 슬롯 충원 모델을 채택했다. 기존 배치 엔진은 모든 건이 완료될 때까지 다음 클레임을 차단하는 배리어 방식을 사용했다. 이는 처리 시간이 긴 한 건이 전체 대기열을 막아 다른 건들의 처리를 지연시키는 문제가 있었다. 대신 세마포어 기반의 슬롯 충원 모델을 도입해, 고정된 워커 풀이 슬롯이 비어질 때만 다음 건을 가져오도록 했다. 이를 통해 특정 건의 지연이 전체 파이프라인의 마비를 막고, 장애 반경을 개별 건으로 제한할 수 있었다.
콜백 계약에는 Best-effort(최선의 노력) 원칙을 명시했다. 외부 시스템으로 결과를 전송하는 과정은 실패할 수 있으며, 이는 파이프라인의 최종 상태가 아님을 분명히 했다. 호출자는 원장(이중 타임스탬프)과 스위퍼 패턴을 통해 유실된 콜백을 보정하도록 설계했다. 이는 파이프라인 내부의 안정성을 외부 시스템의 신뢰성에 의존하지 않도록 분리한 결정이다.
결과와 한계
- 얻은 것: 모델 교체 시 재배포 없이 설정만으로 가능해졌으며, 프롬프트 변경 시 즉각 반영이 가능해졌다.
- 잃은 것: 슬롯 충원 모델은 순서 보장 없이 병렬 처리를 가능하게 하므로, 순서가 중요한 태스크에는 추가적인 정렬 로직이 필요하다.
- 되돌릴 조건: DB 영속화된 프롬프트의 관리 복잡도가 운영 부담을 상회한다면, 다시 외부 API 의존으로 전환할 수 있다.
다른 시스템에 적용할 때, 외부 API의 안정성이 보장되지 않는 경우 반드시 DB 영속화와 Best-effort 계약을 고려해야 한다. 또한 배치 처리의 병목이 시스템 전체의 가용성에 영향을 준다면, 슬롯 기반 병렬화를 통해 장애 반경을 분리하는 것이 효과적이다.
팀에 남긴 규칙: "외부 API의 실패는 시스템의 실패가 아니며, 최종 상태는 반드시 조회로 확인한다." 이 결정을 다시 봐야 할 조건: 외부 LLM 제공사의 SLA가 99.9% 이상으로 안정화되고, 프롬프트 버전 관리가 단순해졌을 때.