반응형
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 환경을 확보해야 함.
반응형
'Linux > 기타' 카테고리의 다른 글
| systemd 서비스 삭제 방법 (0) | 2025.06.27 |
|---|---|
| systemd에 서비스 등록하기(서비스 자동 실행 & 모니터링 설정) (0) | 2025.03.14 |
| ^M 삭제 (0) | 2025.02.07 |
| [item2]IP 주소 하이라이트(IP 주소 글자색 바꾸기) (1) | 2024.01.09 |