Small Asteroid Blog

[Python] Gradio streaming, 로컬환경에서는 되고 왜 쿠버환경에서는 안 됐을까? 본문

백엔드/Python

[Python] Gradio streaming, 로컬환경에서는 되고 왜 쿠버환경에서는 안 됐을까?

작은소행성☄️ 2025. 6. 28. 16:52
728x90

gradio 에서 textbox 를 사용해 텍스트를 스트리밍 형태로 출력하고 싶었다. 

 

로컬 환경에서 배포하면 스트리밍으로 출력이 되는데

동일한 코드를 쿠버 환경에 배포하면 스트리밍으로 출력이 되지 않고 한번에 출력 결과가 나왔다. 

 

Gradio 5.x 버전 부터는 stream=True 의 옵션이 없어져서 해당 옵션을 주어도 스트리밍으로 출력되지 않았다. 

 

streaming 동작 조건

1. 함수가 yield를 통해 데이터를 작은 단위로 반환해야 함
2. chunk된 결과가 클라이언트에게 바로 flush되어야 함
3. 웹 서버 (FastAPI, Uvicorn) 와 프록시 (Nginx, Ingress, LoadBalancer 등)가 chunked encoding을 제대로 지원해야 함

 

 

로컬환경에서는 왜 스트리밍처럼 보였을까?

로컬에서는 웹 서버와 클라이언트 사이의 거리가 짧고, Nginx나 Ingress 등의 중간 버퍼링 계층이 없기 때문에 flush 타이밍이 빠르다.
→ 따라서 yield로 나눠 보낸 데이터가 바로 렌더링되어 스트리밍처럼 보였다.

 

반면, 쿠버네티스 환경에서는 Ingress Controller나 Nginx가 기본적으로 버퍼링을 하기 때문에, 일정 크기 이상의 데이터가 쌓여야만 클라이언트로 전송된다.
→ 결국 스트리밍이 작동하지 않고, 모든 출력이 한 번에 몰려서 표시되는 문제가 발생했다.

 

 

진짜 스트리밍처럼 보이게 하려면, 코드를 수정해 yield로 데이터 chunk를 작게 나눠 반환하는 방법으로 

 

 

해결 방법

Nginx Ingress 버퍼링 설정 비활성화

metadata:
  annotations:
    # ─────── SSE 필수 ───────
    nginx.ingress.kubernetes.io/proxy-buffering: "off"
    nginx.ingress.kubernetes.io/proxy-request-buffering: "off"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" # 1시간
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    # ───────  HTTP/2 → 1.1 강제(브라우저 ↔ Ingress) ───────
    nginx.ingress.kubernetes.io/use-http2: "false"
    nginx.ingress.kubernetes.io/proxy-http-version: "1.1"  # ngress-→ pod 구간을  HTTP/1.1
    nginx.ingress.kubernetes.io/connection-proxy-header: "keep-alive"

 

 

Dockerfile 에서 stdout 버퍼링 비활성화 

ENV PYTHONUNBUFFERED=1

 

 

yield 단위 + sleep 지연 추가

너무 큰 chunk 를 한번에 보내면 버퍼링이 발생할 수 있기 때문에 문자 단위로 yield 하면서 sleep 을 주어 브라우저에 렌더링 하도록 유도했다. 

sleep 을 0.01 이라도 주지 않으면 스트리밍 출력이 안된다. 

async def stream_textbox_output(...):
    for char in content: # for문으로 content 를 나눠서 반환하는게 포인트
        yield char
        await asyncio.sleep(0.01)

 

 

 

Lesson Learned

단순한 기능 구현뿐만 아니라 인프라 계층이 UI/UX 계층에도 영향을 주는 것을 확인할 수 있었다. 

스트리밍 UI 를 구현할 때는 end-to-end 흐름을 고려해서 작업해야겠다. 

 

728x90
반응형