Linux/기타

Locust와 gRPC 연동 문제 해결(DEADLINE_EXCEEDED)

miracle21 2026. 2. 1. 17:15
반응형

1. 개요

목표

Locust를 사용하여 gRPC 서비스에 대한 부하테스트 실행

 

Pod 구성

  • Locust Pod
    • locustfile.py 를 통해 gRPC 호출하는 클라이언트
    • my-service pod와 동일한 namespace와 image 사용
    • 사용된 yaml: locust-deployment.yaml, locust-configmap.yaml
  • gRPC 서버
    • 요청을 받는 대상 (my-service pod)

 

문제 상황

  • 현상: Locust Pod에서 locustfile.py로 직접 gRPC 호출 시 DEADLINE_EXCEEDED 에러 발생(클라이언트 측 타임아웃).
  • 특이점: Locust pod 내에서 my-service.py 스크립트는 정상 동작하나, locustfile.py는 서버 측에 로그조차 남기지 못함.
gRPC Recognize: <_MultiThreadedRendezvous of RPC that terminated with:
status = StatusCode.DEADLINE_EXCEEDED
details = "Deadline Exceeded"
debug_error_string = "UNKNOWN:Error received from peer {grpc_message:"Deadline Exceeded", grpc_status:4, ...}"

 

2. 원인 분석

원인
Locust(Gevent 기반)와 gRPC Python 라이브러리 간의 동시성 모델 비호환성으로 인한 충돌.

  • Gevent 환경에서는 모든 I/O가 Gevent 이벤트 루프에 통합되어야 함.
  • gRPC Python은 자체 스레드를 사용하므로 Gevent와 충돌이 발생하여 요청이 서버까지 도달하지 않음.

Locust vs gRPC Python 동작 비교

구분 Locust (Gevent 기반) gRPC Python (스레드 기반)
동시성 모델 Gevent 라이브러리 기반 스레드 기반
작업 단위 Greenlet (코루틴) 스레드 (Thread)
동작 방식 비동기적 (작업 교차 수행) 동기적 (동시 실행)
I/O 처리 Gevent가 전체 관리 gRPC 내부 스레드가 처리


3. 해결 방안

방법 1. gRPC 호출을 subprocess로 분리

Locust 태스크 내에서 gRPC 호출을 직접 수행하지 않고, 정상 동작하는 별도의 스크립트를 subprocess로 실행.

@task
def recognize_audio(self):
    import subprocess
    result = subprocess.run(
        ["python", "/app/my-service.py", GRPC_HOST, AUDIO_FILE_PATH],
        capture_output=True, text=True
    )

 

방법 2. grpc.experimental.gevent.init_gevent() 사용

gRPC 채널 생성 전 호출하여 Gevent 루프와 호환되도록 설정.

import grpc.experimental.gevent
grpc.experimental.gevent.init_gevent()


4. 결론

Locust(Gevent)와 gRPC Python(스레드) 모델의 충돌이 원인이므로, 호출 로직을 별도 프로세스로 분리하거나 호환성 패치(init_gevent)를 적용하여 독립적인 네트워크 I/O 환경을 확보해야 함.

반응형