본문으로 건너뛰기
Kreath Archive
TechProjectsBooksAbout
TechProjectsBooksAbout

내비게이션

  • Tech
  • Projects
  • Books
  • About
  • Tags

카테고리

  • AI / ML
  • 웹 개발
  • 프로그래밍
  • 개발 도구

연결

  • GitHub
  • Email
  • RSS
© 2026 Kreath Archive. All rights reserved.Built with Next.js + MDX
홈TechProjectsBooksAbout
//
  1. 홈
  2. 테크
  3. 4장: gRPC Streaming — 고성능 백엔드 통신
2026년 3월 24일·아키텍처·

4장: gRPC Streaming — 고성능 백엔드 통신

HTTP/2 기반 gRPC의 4가지 스트리밍 모드, Protobuf 직렬화, 마이크로서비스 간 추론 파이프라인 구현을 다룹니다. gRPC-Web의 제약과 Python/Go 구현 예제를 포함합니다.

16분639자10개 섹션
streamingai
공유
streaming-ai4 / 10
12345678910
이전3장: WebSocket — 양방향 실시간 통신다음5장: 스트리밍 LLM 응답 처리

학습 목표

  • gRPC의 핵심 개념과 HTTP/2 기반 통신 원리를 이해합니다
  • 4가지 스트리밍 모드(단항, 서버, 클라이언트, 양방향)를 구분합니다
  • Protobuf 직렬화의 성능 이점을 파악합니다
  • 마이크로서비스 간 추론 파이프라인에서의 gRPC 활용을 학습합니다
  • gRPC-Web의 제약과 대안을 분석합니다
  • Python과 Go에서의 gRPC 스트리밍 구현을 다룹니다

왜 gRPC인가

2장과 3장에서 다룬 SSE와 WebSocket은 주로 클라이언트(브라우저)와 서버 간 통신에 초점을 맞추었습니다. 그러나 실제 AI 시스템의 백엔드는 여러 마이크로서비스로 구성됩니다.

API Gateway에서 추론 라우터로, 추론 라우터에서 GPU 서버로 데이터를 전달할 때, HTTP REST API를 사용할 수도 있습니다. 하지만 다음과 같은 문제가 있습니다.

  • JSON 직렬화/역직렬화 오버헤드
  • 스키마 정의와 검증의 부재
  • 스트리밍 지원의 부족
  • HTTP/1.1의 Head-of-Line 블로킹

gRPC는 Google이 개발한 고성능 RPC 프레임워크로, 이 모든 문제를 해결합니다.

gRPC의 핵심 기술

HTTP/2 기반

gRPC는 HTTP/2 위에서 동작합니다. HTTP/2의 핵심 특성인 **멀티플렉싱(Multiplexing)**은 하나의 TCP 연결 위에서 여러 요청/응답을 동시에 처리할 수 있게 해줍니다.

HTTP/1.1 vs HTTP/2
text
[HTTP/1.1]
연결 1: 요청A ──────> 응답A
연결 2: 요청B ──────> 응답B    (별도 연결 필요)
연결 3: 요청C ──────> 응답C
 
[HTTP/2 멀티플렉싱]
연결 1: 스트림1(요청A) ──> 스트림2(요청B) ──> 스트림1(응답A)
         스트림3(요청C) ──> 스트림2(응답B) ──> 스트림3(응답C)
         (하나의 연결에서 동시 처리)

Protocol Buffers (Protobuf)

gRPC는 기본 직렬화 형식으로 **Protobuf(Protocol Buffers)**를 사용합니다. JSON 대비 직렬화 크기가 3-10배 작고, 처리 속도는 10-100배 빠릅니다.

inference.proto
protobuf
syntax = "proto3";
 
package inference;
 
service InferenceService {
  // 단항 RPC
  rpc Predict(PredictRequest) returns (PredictResponse);
  
  // 서버 스트리밍 RPC
  rpc StreamPredict(PredictRequest) returns (stream TokenResponse);
  
  // 클라이언트 스트리밍 RPC
  rpc StreamInput(stream AudioChunk) returns (TranscriptResponse);
  
  // 양방향 스트리밍 RPC
  rpc Converse(stream ConversationInput) returns (stream ConversationOutput);
}
 
message PredictRequest {
  string model_id = 1;
  string prompt = 2;
  int32 max_tokens = 3;
  float temperature = 4;
}
 
message TokenResponse {
  string token = 1;
  int32 index = 2;
  bool is_finished = 3;
  TokenMetadata metadata = 4;
}
 
message TokenMetadata {
  float log_probability = 1;
  int64 latency_ms = 2;
}
 
message AudioChunk {
  bytes data = 1;
  int32 sample_rate = 2;
  string encoding = 3;
}
Info

Protobuf는 필드 번호 기반으로 직렬화합니다. 필드를 추가할 때 기존 번호를 재사용하지 않으면 하위 호환성이 유지됩니다. 이는 마이크로서비스의 독립 배포에 핵심적인 특성입니다.

4가지 스트리밍 모드

gRPC의 차별점은 4가지 통신 모드를 지원한다는 것입니다.

1. 단항 RPC (Unary)

일반적인 요청-응답 패턴입니다. REST API와 유사하지만, Protobuf와 HTTP/2의 성능 이점을 누립니다.

단항 RPC 흐름
text
클라이언트 ── 요청 ──> 서버
클라이언트 <── 응답 ── 서버

2. 서버 스트리밍 (Server Streaming)

클라이언트가 하나의 요청을 보내면, 서버가 스트림으로 여러 응답을 보냅니다. LLM 토큰 스트리밍에 가장 적합한 모드입니다.

서버 스트리밍 흐름
text
클라이언트 ── 요청 ──> 서버
클라이언트 <── 토큰1 ── 서버
클라이언트 <── 토큰2 ── 서버
클라이언트 <── 토큰3 ── 서버
클라이언트 <── 완료 ── 서버

3. 클라이언트 스트리밍 (Client Streaming)

클라이언트가 여러 메시지를 스트림으로 보내고, 서버가 하나의 응답을 반환합니다. 실시간 음성 입력에서 오디오 청크를 연속 전송할 때 사용됩니다.

클라이언트 스트리밍 흐름
text
클라이언트 ── 오디오청크1 ──> 서버
클라이언트 ── 오디오청크2 ──> 서버
클라이언트 ── 오디오청크3 ──> 서버
클라이언트 <── 전체 인식 결과 ── 서버

4. 양방향 스트리밍 (Bidirectional Streaming)

양쪽이 동시에 스트림을 보냅니다. 실시간 음성 대화(사용자 발화 + AI 응답이 동시에 진행)에서 사용됩니다.

Python 구현: 서버 스트리밍

Python에서 gRPC 서버 스트리밍을 구현하는 예제입니다.

inference_server.py
python
import grpc
from concurrent import futures
import inference_pb2
import inference_pb2_grpc
 
 
class InferenceServicer(inference_pb2_grpc.InferenceServiceServicer):
    """gRPC 추론 서비스 구현"""
 
    def StreamPredict(self, request, context):
        """서버 스트리밍: 토큰 단위로 응답"""
        model_id = request.model_id
        prompt = request.prompt
 
        # 모델 로드 및 추론
        model = get_model(model_id)
        generator = model.generate(
            prompt,
            max_tokens=request.max_tokens,
            temperature=request.temperature,
        )
 
        for index, (token, log_prob) in enumerate(generator):
            # 클라이언트가 연결을 끊었는지 확인
            if context.is_active():
                yield inference_pb2.TokenResponse(
                    token=token,
                    index=index,
                    is_finished=False,
                    metadata=inference_pb2.TokenMetadata(
                        log_probability=log_prob,
                        latency_ms=get_latency_ms(),
                    ),
                )
            else:
                # 클라이언트가 취소함
                return
 
        # 완료 신호
        yield inference_pb2.TokenResponse(
            token="",
            index=-1,
            is_finished=True,
        )
 
    def Converse(self, request_iterator, context):
        """양방향 스트리밍: 실시간 대화"""
        for request in request_iterator:
            if not context.is_active():
                return
 
            # 입력 처리 및 응답 생성
            response = process_input(request)
            for token in response:
                yield inference_pb2.ConversationOutput(
                    text=token,
                    speaker="assistant",
                )
 
 
def serve():
    server = grpc.server(
        futures.ThreadPoolExecutor(max_workers=10),
        options=[
            ("grpc.max_send_message_length", 50 * 1024 * 1024),
            ("grpc.max_receive_message_length", 50 * 1024 * 1024),
            ("grpc.keepalive_time_ms", 30000),
            ("grpc.keepalive_timeout_ms", 10000),
        ],
    )
    inference_pb2_grpc.add_InferenceServiceServicer_to_server(
        InferenceServicer(), server
    )
    server.add_insecure_port("[::]:50051")
    server.start()
    server.wait_for_termination()

Go 구현: 추론 라우터

Go에서 gRPC 클라이언트로 여러 추론 서버를 라우팅하는 예제입니다.

router/main.go
go
package main
 
import (
	"context"
	"io"
	"log"
 
	pb "inference/proto"
	"google.golang.org/grpc"
)
 
type InferenceRouter struct {
	pb.UnimplementedInferenceServiceServer
	backends []pb.InferenceServiceClient
}
 
func (r *InferenceRouter) StreamPredict(
	req *pb.PredictRequest,
	stream pb.InferenceService_StreamPredictServer,
) error {
	// 최적의 백엔드 선택 (로드 기반)
	backend := r.selectBackend(req.ModelId)
 
	// 백엔드에 스트리밍 요청
	ctx := stream.Context()
	backendStream, err := backend.StreamPredict(ctx, req)
	if err != nil {
		return err
	}
 
	// 백엔드 응답을 클라이언트에 중계
	for {
		token, err := backendStream.Recv()
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return err
		}
 
		if err := stream.Send(token); err != nil {
			return err
		}
	}
}
 
func (r *InferenceRouter) selectBackend(
	modelId string,
) pb.InferenceServiceClient {
	// 라운드 로빈, 최소 연결, GPU 사용률 기반 등
	// 실제 구현은 모니터링 메트릭에 기반
	return r.backends[0]
}

gRPC-Web: 브라우저에서의 제약

gRPC는 HTTP/2의 저수준 기능을 활용하기 때문에, 브라우저에서 직접 사용할 수 없습니다. 브라우저의 fetch API가 HTTP/2 프레임에 대한 세밀한 제어를 제공하지 않기 때문입니다.

gRPC-Web은 이 문제를 해결하기 위한 프록시 기반 접근법입니다.

gRPC-Web의 한계

한계설명
프록시 필요Envoy 등 별도 프록시 서버 운영 필수
오버헤드30-40% 직렬화/역직렬화 오버헤드
스트리밍 제한서버 스트리밍만 지원 (양방향 불가)
생태계클라이언트 라이브러리 성숙도가 낮음
Warning

프론트엔드-백엔드 간 통신에 gRPC-Web을 도입하는 것은 대부분의 경우 과도한 복잡성을 추가합니다. LLM 토큰 스트리밍에는 SSE가, 양방향 통신에는 WebSocket이 더 실용적입니다. gRPC는 백엔드 서비스 간 통신에 집중하는 것이 바람직합니다.

성능 비교

동일한 추론 결과를 전송할 때의 프로토콜별 성능 차이를 비교합니다.

지표REST (JSON)gRPC (Protobuf)개선율
직렬화 크기1.0x (기준)0.3-0.5x50-70% 감소
직렬화 속도1.0x5-10x5-10배 빠름
지연시간 (P99)15ms3ms5배 감소
처리량10,000 req/s40,000 req/s4배 증가

이 수치는 마이크로서비스 간 통신이 빈번한 추론 파이프라인에서 누적 효과가 큽니다. 하나의 사용자 요청이 내부적으로 5-10번의 서비스 간 호출을 발생시킨다면, 각 호출의 지연시간 감소가 전체 응답 시간에 직접적으로 반영됩니다.

마이크로서비스 추론 파이프라인

실제 AI 시스템에서 gRPC가 어떻게 활용되는지, 전체 파이프라인을 살펴보겠습니다.

각 구간의 프로토콜 선택 근거는 다음과 같습니다.

  1. 클라이언트-Gateway: SSE (브라우저 호환, 무상태 스케일링)
  2. Gateway-라우터: gRPC 서버 스트리밍 (저지연, 타입 안전)
  3. 라우터-GPU: gRPC 서버 스트리밍 (최소 오버헤드)
  4. 라우터-캐시: gRPC 단항 (빠른 조회)
  5. GPU-모니터링: gRPC 단항 (메트릭 비동기 전송)
Tip

gRPC 서비스 정의(.proto 파일)는 API 계약서 역할을 합니다. 프론트엔드, 백엔드, ML 팀이 동일한 .proto 파일을 공유하면, 각 언어에 맞는 클라이언트/서버 코드가 자동 생성됩니다. 이는 팀 간 커뮤니케이션 오류를 크게 줄입니다.


정리

이번 장에서는 백엔드 서비스 간 고성능 통신을 위한 gRPC Streaming을 살펴보았습니다.

  • gRPC는 HTTP/2 멀티플렉싱과 Protobuf 직렬화를 결합하여 JSON REST 대비 5-10배의 성능 향상을 제공합니다
  • 4가지 스트리밍 모드(단항, 서버, 클라이언트, 양방향)로 다양한 통신 패턴을 지원합니다
  • 서버 스트리밍 모드는 LLM 토큰 전달에, 양방향 스트리밍은 실시간 음성 대화에 적합합니다
  • gRPC-Web은 브라우저 접근을 가능하게 하지만, 30-40% 오버헤드와 기능 제한이 있습니다
  • 프로덕션에서는 클라이언트-서버에 SSE/WebSocket, 서버-서버에 gRPC를 사용하는 하이브리드 구성이 최적입니다

다음 장에서는 프로토콜 레벨을 넘어, LLM 응답을 실제로 어떻게 처리하고 렌더링하는지를 다룹니다. OpenAI, Anthropic, Google의 스트리밍 API 차이, 구조화된 출력의 파셜 파싱, 그리고 Vercel AI SDK를 활용한 React 스트리밍 UI 구현을 살펴보겠습니다.

이 글이 도움이 되셨나요?

관련 주제 더 보기

#streaming#ai

관련 글

아키텍처

5장: 스트리밍 LLM 응답 처리

OpenAI, Anthropic, Google의 스트리밍 API 차이를 비교하고, 구조화된 출력의 파셜 파싱, React 스트리밍 UI 렌더링, Vercel AI SDK 활용법을 다룹니다.

2026년 3월 26일·15분
아키텍처

3장: WebSocket — 양방향 실시간 통신

WebSocket의 핸드셰이크, 프레이밍 구조, 양방향 통신의 강점과 상태 관리의 복잡성을 분석합니다. AI 채팅에서의 생성 중단, Socket.IO, 스케일링 전략을 다룹니다.

2026년 3월 22일·17분
아키텍처

6장: 실시간 추론 파이프라인 설계

vLLM의 스트리밍 입력, Continuous Batching, 시맨틱 캐싱, 추론 라우터, 멀티모달 실시간 처리 등 백엔드 추론 파이프라인의 핵심 아키텍처를 다룹니다.

2026년 3월 28일·17분
이전 글3장: WebSocket — 양방향 실시간 통신
다음 글5장: 스트리밍 LLM 응답 처리

댓글

목차

약 16분 남음
  • 학습 목표
  • 왜 gRPC인가
  • gRPC의 핵심 기술
    • HTTP/2 기반
    • Protocol Buffers (Protobuf)
  • 4가지 스트리밍 모드
    • 1. 단항 RPC (Unary)
    • 2. 서버 스트리밍 (Server Streaming)
    • 3. 클라이언트 스트리밍 (Client Streaming)
    • 4. 양방향 스트리밍 (Bidirectional Streaming)
  • Python 구현: 서버 스트리밍
  • Go 구현: 추론 라우터
  • gRPC-Web: 브라우저에서의 제약
    • gRPC-Web의 한계
  • 성능 비교
  • 마이크로서비스 추론 파이프라인
  • 정리