semaphore 설정 - 100-hours-a-week/5-yeosa-wiki GitHub Wiki

1. 세마포어(Semaphore) 설정 목적

a. 설정 배경

  • 온기의 이미지 처리 파이프라인에서는 다음과 같은 특징이 존재

    작업 단계 특징
    Embedding CPU 연산량이 많고, 메모리 점유율도 높은 CPU-bound 작업
    후속 작업들 (e.g. categories, quality, score) 상대적으로 가벼운 작업이며, 동시에 병렬로 처리할 수 있어야 효율적

b. 문제 인식

  • Embedding 작업이 너무 많은 스레드를 독점할 경우, 후속 작업들이 스레드를 얻지 못해 병목 현상이 발생함

    전체 요청 처리 시간 증가, 지연(latency) 상승

c. 핵심 전략

  • max_workers는 8로 고정
  • embedding 작업에 대해서만 별도 세마포어(4) 도입
    • 사용하는 CPU 서버의 코어 수가 4 → 각 embedding 작업이 독립적인 코어에 배정되어 최대 효율로 실행됨
    • 동시 실행 수가 코어 수를 초과할 경우 CPU 간 컨텍스트 스위칭 및 자원 경쟁 발생
    • 테스트
  • 요청이 들어올 때 embedding은 제한된 개수만 동시에 실행되며, 후속 작업은 나머지 스레드를 활용하여 즉시 처리

2. 개선 후 코드

EMBEDDING_SEMAPHORE_SIZE = 4
embedding_semaphore = asyncio.Semaphore(EMBEDDING_SEMAPHORE_SIZE)

@router.post("", status_code=201)
@log_flow
async def embed(req: ImageRequest, request: Request):
    async with embedding_semaphore:
        return await embed_controller(req, request)
  • embedding_semaphore는 embedding 요청이 동시에 최대 4개만 실행되도록 제한
  • 다른 embedding 요청은 큐에 대기하고 순차적으로 실행됨

3. 개선 효과

  • 테스트 결과

    목적 설명
    리소스 점유율 제어 embedding이 너무 많은 스레드를 동시에 사용하지 못하게 제한함
    후속 작업 보호 후속 작업들(categories, duplicates, quality 등)이 병렬 처리될 수 있도록 스레드 여유 확보
    전체 응답시간 최적화 일부 요청이 embedding 때문에 밀리는 현상을 막고 전체 요청 처리 성능을 개선
    처리량 향상 VU 수가 증가해도 안정적으로 서비스 처리 가능