본문 바로가기
Python

[Python] gRPC로 양방향 통신하기

by teamnova 2025. 8. 22.
728x90

1. gRPC 개요 및 핵심 개념

gRPC는 Google에서 개발한 오픈소스 원격 프로시저 호출(RPC) 프레임워크입니다. HTTP/2와 Protocol Buffers(Protobuf)를 기반으로 하며, 마이크로서비스 아키텍처(MSA) 및 분산 시스템 환경에서 고성능·고효율 통신을 위해 설계되었습니다.

  • 모든 환경에서 동작: 데이터센터, 클라우드, 엣지, 모바일 등 다양한 환경 지원
  • 다국어 지원: Python, Java, Go 등 10여개 이상의 언어 지원
  • 자동 코드 생성: .proto 파일만 있으면 서버/클라이언트 코드가 자동 생성됨

1.1. RPC란?

RPC(Remote Procedure Call)는 클라이언트가 네트워크를 통해 원격 서버의 함수를 마치 로컬 함수처럼 호출할 수 있게 하는 프로토콜입니다.
→ 개발자는 네트워크 통신의 복잡성을 신경쓰지 않고, 함수 호출에 집중할 수 있습니다.

 

1.2. gRPC의 주요 특징

  • 고성능: Protobuf 이진 직렬화 + HTTP/2 멀티플렉싱으로 REST 대비 빠름
  • 스트리밍 지원: 단항, 서버/클라이언트/양방향 스트리밍 등 4가지 패턴 제공
  • 엄격한 타입 체크: 컴파일 타임 타입 검증
  • 코드 자동 생성: proto 파일만 있으면 여러 언어의 코드를 자동 생성
  • 보안 내장: TLS/SSL, mTLS 등 강력한 보안 지원

2. gRPC vs REST

구분 gRPC REST API
설계 방식 서비스(함수) 지향 리소스(엔터티) 지향
통신 모델 단항, 서버/클라이언트/양방향 스트리밍 요청-응답(단방향)
데이터 형식 Protobuf(이진), JSON(옵션) JSON(텍스트), XML, HTML 등
프로토콜 HTTP/2 HTTP 1.1
코드 생성 proto → 자동 코드 생성 서드파티 도구 필요
결합도 긴밀(계약 기반, proto 공유 필수) 느슨(동적 스펙)
적합한 용도 고성능, 대용량, 실시간, 다국어 서비스 공개 API, 브라우저, 단순 데이터

REST는 느슨한 결합, gRPC는 강력한 타입·계약 기반의 긴밀한 결합이 특징입니다.

 


3. Python gRPC 환경 설정

3.1. 필수 패키지 설치

pip install grpcio grpcio-tools
  • grpcio: Python gRPC 런타임
  • grpcio-tools: Protobuf 컴파일러 및 코드 생성 플러그인

3.2. 서비스 정의 (.proto 파일)

예시: Greeter 서비스

syntax = "proto3";

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest { string name = 1; }
message HelloReply { string message = 1; }

 

3.3. 코드 생성

python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. helloworld.proto
  • helloworld_pb2.py: 메시지 클래스 정의
  • helloworld_pb2_grpc.py: 클라이언트 스텁/서버 인터페이스

4. Python gRPC 서버/클라이언트 기본 예제

4.1. 서버 구현

import grpc
from concurrent import futures
import helloworld_pb2
import helloworld_pb2_grpc

class Greeter(helloworld_pb2_grpc.GreeterServicer):
    def SayHello(self, request, context):
        return helloworld_pb2.HelloReply(message=f"Hello, {request.name}!")

def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    server.wait_for_termination()

if __name__ == '__main__':
    serve()

 

4.2. 클라이언트 구현

import grpc
import helloworld_pb2
import helloworld_pb2_grpc

def run():
    with grpc.insecure_channel('localhost:50051') as channel:
        stub = helloworld_pb2_grpc.GreeterStub(channel)
        response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
        print("Greeter client received: " + response.message)

if __name__ == '__main__':
    run()

 

5. gRPC 스트리밍

gRPC의 진짜 매력은 스트리밍입니다.
한 번 연결로 여러 메시지를 주고받을 수 있어, 실시간 채팅·알림·대용량 데이터 송수신에 최적입니다.

5.1. 4가지 스트리밍 패턴

gRPC는 아래 4가지 통신 패턴을 지원합니다.

패턴 설명 예시 활용
Unary 1개 요청 → 1개 응답 로그인, 조회 등
Server Streaming 1개 요청 → 여러 응답(스트림) 실시간 피드, 대용량 데이터 다운로드
Client Streaming 여러 요청(스트림) → 1개 응답 대용량 업로드, 센서 데이터 수집
Bidirectional 여러 요청/응답을 양방향 스트림으로 동시 교환 실시간 채팅, 게임, 협업 도구

5.2. 양방향 스트리밍 예제

stream_example.proto

syntax = "proto3";

service StreamService {
  rpc StreamData (stream StreamRequest) returns (stream StreamResponse);
}

message StreamRequest { string data = 1; }
message StreamResponse { string result = 1; }

 

서버

class StreamService(stream_example_pb2_grpc.StreamServiceServicer):
    def StreamData(self, request_iterator, context):
        for request in request_iterator:
            yield stream_example_pb2.StreamResponse(result=f"Received: {request.data}")

 

클라이언트

def generate_requests():
    for i in range(5):
        yield stream_example_pb2.StreamRequest(data=f"Message {i}")

def run():
    with grpc.insecure_channel('localhost:50051') as channel:
        stub = stream_example_pb2_grpc.StreamServiceStub(channel)
        responses = stub.StreamData(generate_requests())
        for response in responses:
            print(f"응답: {response.result}")

 

6. gRPC 에러 처리 및 보안

6.1. 에러/상태 코드

상태 코드 설명
CANCELLED 작업이 클라이언트에 의해 취소됨
INVALID_ARGUMENT 잘못된 인수
DEADLINE_EXCEEDED 마감 시간 초과
NOT_FOUND 리소스 없음
PERMISSION_DENIED 권한 없음
INTERNAL 내부 서버 에러
UNAVAILABLE 서비스 불가
UNAUTHENTICATED 인증 실패

 

서버에서 에러 반환 예시

def MyMethod(self, request, context):
    if not request.valid:
        context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
        context.set_details('입력값이 잘못되었습니다.')
        return MyResponse()

 

클라이언트에서 에러 처리

try:
    response = stub.MyMethod(MyRequest())
except grpc.RpcError as e:
    status = e.code()
    print(f"gRPC 에러: {status}, {e.details()}")

 

 

6.2. 보안 (TLS/SSL, mTLS)

  • TLS/SSL: 서버 인증서 기반 암호화 통신
  • mTLS: 서버와 클라이언트 모두 인증서로 신원 검증 (양방향 인증)
  • Python 예시
# 서버
server_credentials = grpc.ssl_server_credentials([(private_key, certificate_chain)])
server.add_secure_port('[::]:50051', server_credentials)

# 클라이언트
credentials = grpc.ssl_channel_credentials(root_certificates=ca_cert)
channel = grpc.secure_channel('localhost:50051', credentials)

 

7. 마이크로서비스 아키텍처(MSA)에서 gRPC의 역할

  • 고성능 통신: 서비스 간 빈번한 데이터 교환을 빠르고 효율적으로 처리
  • 언어 중립성: Python, Java, Go 등 다양한 언어 조합 가능
  • 강력한 타입 체크: 서비스 계약이 명확함 (컴파일 시점 검증)
  • 스트리밍 지원: 실시간 데이터, 대용량 데이터 처리에 최적
  • 코드 자동 생성: .proto 파일만 관리하면 모든 서비스가 일관된 인터페이스로 통신 가능

Tip:
중앙화된 proto 관리 시스템(예: 별도 git repo)에서 .proto 파일을 관리하고, 각 서비스에서 빌드 파이프라인으로 자동 배포하는 것이 실무적입니다.

8. gRPC 테스트 및 디버깅 도구

  • Apidog: gRPC 스트리밍까지 지원하는 웹 기반 API 테스트/디버깅 도구
    • 다양한 언어 지원, .proto 기반 문서 자동화
    • 요청/응답 모니터링, 스트리밍 실시간 확인
  • gRPCurl: 터미널에서 gRPC API 호출 및 테스트
  • BloomRPC: GUI 기반 gRPC 클라이언트