GPU 연산을 분리한 비동기 처리 아키텍처 설계

2026. 2. 7. 19:22·개발 기록/프로젝트 - BUKAE

0. 서론

현재 진행 중인 프로젝트 BUKAE는 실제 창업을 전제로 준비 중인 서비스다.
이 프로젝트는 다음과 같은 현실적인 조건을 가진다.

  • 전체 예산이 제한적이다.
  • 고성능 GPU는 학교에서 대여한 서버를 사용한다.
  • 영상 인코딩이라는 고부하 워크로드를 포함한다.
  • 영상 생성 시 크레딧(금전성 자산)이 실제로 소모된다.

즉, 이 프로젝트는 성능, 비용, 안정성, 신뢰성을 동시에 고려해야 하는 구조다.

이 글은 이러한 환경에서
GPU 연산을 API 서버에서 분리하고, 비동기 워커 기반으로 처리하도록 설계한 아키텍처에 대한 정리다.

 

1. 프로젝트의 제약 조건

1.1 비용과 인프라 제약

이 프로젝트는 다음과 같은 제약을 전제로 한다.

  • 웹/API 서버는 소수의 CPU 인스턴스로 운영해야 한다.
  • GPU 서버는 학교에서 빌린 자원이므로 항상 사용 가능하다고 가정할 수 없다.
  • 장애 발생 시 즉각적인 증설도 어렵다.

따라서 GPU 자원은 최대한 효율적으로,
정말 필요한 작업에만 사용해야 한다.

 

1.2 워크로드 특성 분리의 필요성

서비스 요청은 크게 두 가지로 나뉜다.

  • 로그인, 조회, 설정 변경 같은 경량 API
  • FFMPEG 인코딩, 필터 처리, 합성 등을 포함한 장시간·고부하 작업

이 두 요청을 동일한 프로세스에서 동기적으로 처리할 경우 다음 문제가 발생한다.

  • 고부하 작업이 웹 서버 스레드를 장시간 점유한다.
  • 요청 지연이 누적되며 경량 API까지 영향을 받는다.
  • 결과적으로 전체 서비스 안정성이 급격히 떨어진다.

따라서 설계의 핵심 목표는 명확하다.

고부하 영상 처리 작업이 서비스 전체의 응답성과 안정성에 영향을 주지 않도록 분리한다.

 

2. 아키텍처 설계 목표

2.1 사용자 경험

  • 영상 처리 요청은 즉시 수락한다.
  • 실제 처리는 비동기로 수행한다.
  • 경량 API는 항상 빠른 응답을 유지한다.

2.2 비용 효율

  • GPU는 영상 인코딩과 AI 연산에만 사용한다.
  • API, DB, 비즈니스 로직은 CPU 서버에서 처리한다.

2.3 운영 단순성

  • 도메인 상태와 트랜잭션은 한 곳에서 관리한다.
  • 과도한 서비스 분리로 인한 운영 복잡성은 피한다.

2.4 확장 가능성

  • 초기에는 단일 DB 구조로 시작한다.
  • 향후 도메인 단위 분리가 가능하도록 구조적 여지를 남긴다.

 

3. 검토했던 대안과 배제 이유

3.1 단일 Spring Boot 서버에서 FFMPEG 실행

가장 단순한 접근은 Spring Boot 애플리케이션 내부에서
FFMPEG 프로세스를 직접 실행하는 방식이다.

구현은 빠르지만 다음 문제가 있다.

  • FFMPEG 인코딩은 수십 초~수 분 동안 CPU/GPU를 점유한다.
  • 동기 처리 시 웹 서버 스레드 풀이 고갈된다.
  • 트래픽 증가 시 전체 서비스 장애로 이어질 수 있다.

단기적으로는 편하지만,
운영 리스크가 지나치게 크다고 판단했다.

 

3.2 처음부터 풀 MSA 구조

각 도메인마다 서비스와 DB를 분리하는 정통 MSA 구조도 고려했다.

하지만 현 시점에서는 다음 이유로 과하다고 판단했다.

  • 서비스 수 증가에 따른 운영 복잡도
  • 팀 규모 대비 인프라 관리 부담
  • 아직 명확하지 않은 도메인 경계

이 단계에서 필요한 것은
도메인 분리보다 부하 특성 분리였다.

 

4. 최종 선택: Event-Driven Async Worker Architecture

4.1 전체 구조 개요

최종적으로 선택한 구조는 다음과 같다.

Spring Boot API 서버와 Python 기반 Worker를 메시지 큐로 연결하고,
영상 처리와 같은 고부하 작업을 비동기 워커로 분리한 이벤트 기반 아키텍처

 

구성 요소는 다음과 같다.

 

Spring Boot API 서버

  • HTTP 요청 처리
  • 비즈니스 로직 및 트랜잭션 관리
  • 단일 DB 접근
  • Job 메시지 발행 (Producer)

RabbitMQ

  • Job 큐 역할
  • 요청 수락과 실제 처리의 시간적 분리
  • ACK 기반 메시지 처리 보장

Python Worker (Celery)

  • 메시지 소비 (Consumer)
  • ffmpeg-python 기반 GPU 영상 처리
  • DB 직접 접근 없음

GPU 서버

  • Worker 전용 계산 노드
  • DB 접근 없이 메시지 브로커와 스토리지만 사용

 

4.2 MQ 선택 – RabbitMQ를 선택한 이유

영상 생성 워크플로우는 단순한 비동기 작업 처리가 아니다.
이 시스템에서 MQ는 영상 제작 요청의 상태를 보존하는 핵심 인프라이며,
곧 크레딧 차감의 신뢰성과 직결된다.

MQ 선택 기준은 다음이었다.

  • 메시지를 절대 잃지 않는가
  • 장애 상황에서도 상태를 복구할 수 있는가
  • 크레딧 차감과 Job 상태 사이의 정합성을 유지할 수 있는가

이 기준에서 RabbitMQ가 가장 현실적인 선택이었다.

 

4.2.1 Redis를 MQ로 사용하지 않은 이유

Redis는 기본적으로 메모리 기반 시스템이다.
RDB/AOF로 내구성을 보완할 수는 있지만,
이 프로젝트에서 요구하는 수준의 금전 자산과 연결된 강한 영속성을 보장하려면
추가적인 운영 부담이 크다.

특히 다음 상황을 모두 안전하게 커버해야 한다.

  • Redis 인스턴스 장애
  • AOF 손상 또는 복구 실패
  • 복제 지연으로 인한 데이터 불일치
  • 재시작 타이밍 이슈

이 프로젝트에서 메시지 하나는
이미 크레딧이 차감된 Job 한 건을 의미한다.

메시지가 유실되면

크레딧은 차감되었는데 영상은 생성되지 않는
가장 치명적인 상태 불일치가 발생한다.

 

Redis는 캐싱이나 덜 민감한 작업 큐에는 훌륭하지만,
이 프로젝트에서는 크레딧과 직결된 Job 상태를 완전히 의존할 수 있는 저장소로는 부적합하다고 판단했다.

 

4.2.2 Kafka / SQS를 선택하지 않은 이유

Kafka를 선택하지 않은 이유

  • 로그 스트리밍 플랫폼에 가깝다.
  • Task Queue 용도로는 과하다.
  • 운영 복잡도 대비 얻는 이점이 크지 않다.

SQS를 선택하지 않은 이유

  • 클라우드 벤더 종속이 발생한다.
  • 온프레미스 GPU 서버와의 네트워크 구성이 번거롭다.
  • 초기 단계에서는 자체 통제 가능한 MQ가 더 중요했다.

 

4.2.3 RabbitMQ를 선택한 결정적인 이유

RabbitMQ는 이 문제에 정확히 맞는 특성을 제공한다.

  • 메시지 영속화 (Durable Queue, Persistent Message)
  • Consumer ACK 기반 처리 보장
  • 실패 시 자동 재전달
  • Dead Letter Queue 구성 용이
  • 작업 단위의 명확한 생명주기 관리

즉,

“이 작업이 끝날 때까지 메시지가 사라지지 않도록 설계할 수 있다”

 

라는 보장을 MQ 레벨에서 직접 제공한다.

 

4.2.4 Worker → API 서버 결과 큐를 분리한 이유

영상 생성 완료 후 Worker는 결과를 API 서버로 전달해야 한다.
이 경로를 HTTP 콜백이 아닌 전용 결과 큐로 분리했다.

이유는 다음과 같다.

  • API 서버 장애 시에도 결과 유실 방지
  • 네트워크 단절 시 재전송 보장
  • Worker가 API 서버 상태에 종속되지 않도록 하기 위함

결과적으로 다음 두 큐가 분리된다.

  • 작업 요청 큐: API 서버 → Worker
  • 작업 결과 큐: Worker → API 서버

 

4.2.5 장애 지점과 설계 철학

이 구조에서는 장애를 전제로 설계한다.

  • Worker 장애
  • MQ 장애
  • API 서버 장애
  • 네트워크 분리

중요한 것은 어디에서 멈추더라도 상태가 남아 있는가다.

RabbitMQ 기반 구조에서는 다음이 보장된다.

  • ACK 이전에는 메시지가 절대 소멸되지 않는다.
  • 재시작 후에도 동일 작업을 다시 처리할 수 있다.

즉,
장애가 발생해도 크레딧과 작업 상태가 어긋나지 않는다.

 

5. 요청 처리 흐름

요청 처리 흐름은 다음과 같다.

  1. 클라이언트가 영상 처리 요청을 전송한다.
  2. API 서버가 Job을 생성하고 상태를 PENDING으로 저장한다.
  3. Job ID와 파라미터를 RabbitMQ에 발행한다.
  4. Worker가 메시지를 소비하고 Job을 RUNNING으로 전이한다.
  5. GPU 기반 영상 처리를 수행한다.
  6. 결과를 스토리지에 저장한다.
  7. 결과 메시지를 API 서버로 전달한다.
  8. API 서버가 Job 상태를 SUCCESS 또는 FAILED로 갱신한다.
  9. 클라이언트는 상태 조회 API로 진행 상황을 확인한다.

 

6. Worker와 DB를 분리한 이유

6.1 상태는 한 곳에서만 관리한다

  • Job 상태와 도메인 데이터는 API 서버와 DB에서만 관리한다.
  • Worker는 계산만 수행하는 순수 Compute Node로 동작한다.

6.2 분산 트랜잭션 회피

  • Worker가 DB를 직접 수정하지 않는다.
  • 분산 트랜잭션 설계가 필요 없다.
  • eventual consistency 수준의 일관성을 전제로 한다.

6.3 보안 및 네트워크 단순화

  • GPU 서버에 DB 접근 권한을 주지 않는다.
  • 침해 사고 발생 시 피해 범위를 제한한다.

 

7. 메시지 처리 보장과 장애 시나리오

이 구조는 at-least-once 전달 모델을 전제로 한다.
exactly-once 처리를 보장하려 하지 않는다.

대신,

  • 중복 실행 가능성을 인정한다.
  • Job을 idempotent하게 설계한다.

7.1 장애 시나리오

  • Worker 크래시 → 메시지 재노출
  • GPU OOM / ffmpeg 실패 → 재시도 후 실패 처리
  • ACK 이전 크래시 → 중복 결과 방지 로직으로 처리

7.2 큐 폭주와 백프레셔

  • 큐 길이가 임계치를 넘으면 신규 요청을 제한한다.
  • 일정 시간 초과 시 자동 환불 또는 운영자 검토 대상으로 전환한다.

 

8. Job 상태 모델

Job은 다음 상태 머신으로 관리한다.

  • PENDING
  • RUNNING
  • SUCCESS
  • FAILED
  • RETRYING (선택)
  • TIMEOUT (선택)

기본 흐름은 다음과 같다.

PENDING → RUNNING → { SUCCESS | FAILED }

 

9. Celery + ffmpeg-python + GPU 조합

영상 처리는 다음 조합으로 구현한다.

  • Celery: 태스크 관리, 재시도, 동시성 제어
  • ffmpeg-python: 파이프라인 코드화
  • GPU 서버: 계산 전용 노드

이를 통해 유연성과 안정성의 균형을 유지한다.

 

10. 정리

제한된 예산과 빌린 GPU 서버라는 현실적인 조건을 고려해서,
고부하 영상 처리와 경량 API를 물리적으로 분리하면서도
운영이 너무 복잡해지지 않도록 설계했다.

핵심은 다음 세 가지를 함께 만족하려 한 점이다.

  • 고부하 영상 처리와 경량 API의 물리적 분리
  • 크레딧(금전성 자산)을 고려한 메시지 신뢰성 우선 설계
  • 운영이 단순하면서도, 나중에 확장할 수 있는 여지를 남긴 구조

이 설계는 현재 단계에서 할 수 있는 안전하고 현실적인 비동기 처리 구조라고 생각한다.

'개발 기록 > 프로젝트 - BUKAE' 카테고리의 다른 글

Redis 없이 외부 API Rate Limit 설계하기  (0) 2026.01.04
'개발 기록/프로젝트 - BUKAE' 카테고리의 다른 글
  • Redis 없이 외부 API Rate Limit 설계하기
gepetton
gepetton
공부하며 얻은것들을 공유합니다!
  • gepetton
    gepetton의 블로그
    gepetton
  • 전체
    오늘
    어제
    • 분류 전체보기 (16)
      • 개발 기록 (3)
        • 프로젝트 - BUKAE (2)
        • 프로젝트 - GULON (1)
      • 공부 (10)
        • DB (1)
        • JAVA (5)
        • CS (4)
      • 자격증 (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • github
  • 공지사항

  • 인기 글

  • 태그

    비동기 아키텍처
    Celery
    spring boot
    자격증
    58회 SQLD
    java record
    Python
    API제한
    springboot
    정보처리기사2025
    인덱스 성능
    2025년3회정보처리기사
    정보처리기사필기후기
    FailFast
    ratelimit
    파이썬 TTS
    정보처리기사실기후기
    WebSocket 인증
    토큰버킷알고리즘
    SQLD 2025
    java
    리눅스마스터 1급 후기
    큐기반비동기
    Python Worker
    자바
    태크스큐
    리눅스마스터1급 2502
    리눅스마스터 2502
    이벤트 기반 처리
    PK 설계
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
gepetton
GPU 연산을 분리한 비동기 처리 아키텍처 설계
상단으로

티스토리툴바