gRPC는 Google에서 개발한 오픈 소스 원격 프로시저 호출(Remote Procedure Call) 프레임워크로, HTTP/2를 기반으로 한 효율적인 통신을 제공합니다. 이를 통해 멀티플렉싱, 헤더 압축, 스트리밍 등의 기능을 지원하며, 다양한 프로그래밍 언어와 호환됩니다. 또한, 데이터 직렬화를 위해 Protocol Buffers(Protobuf)를 사용하여 빠르고 효율적인 데이터 전송을 가능하게 합니다.



Protocol Buffers (Protobuf)


Protocol Buffers는 Google에서 개발한 데이터 직렬화 포맷으로, .proto 파일을 사용하여 데이터 구조를 정의합니다. JSON이나 XML보다 더 작고 빠르게 데이터를 직렬화할 수 있는 효율성을 제공합니다. Protobuf의 포맷은 메시지 구조를 정의한 뒤 이를 컴파일러를 통해 특정 언어에 맞는 파일로 변환하여 사용합니다.

포맷 정의 과정:

  1. .proto 파일 작성: 데이터 구조와 서비스 정의를 작성합니다.
  2. 컴파일: protoc 컴파일러를 사용하여 언어별 메시지 및 gRPC 파일을 생성합니다.
  3. 사용: 생성된 파일을 사용하여 데이터 직렬화 및 역직렬화를 수행합니다.

예시:

syntax = "proto3";

package example;

message User {
    string id = 1;
    string name = 2;
    int32 age = 3;
}

service UserService {
    rpc GetUser (UserRequest) returns (User);
}

message UserRequest {
    string id = 1;
}

  • package 예약어는 생성된 코드의 네임스페이스를 정의하며, 주로 프로젝트 구조에 맞게 설정합니다.
  • service는 gRPC 메서드를 정의하며, 각 메서드는 요청 및 응답 메시지 타입을 명시합니다.
  • 주요 예약어: syntax, message, service, rpc, package 등.


Protobuf로 생성되는 파일


Protobuf 컴파일러는 .proto 파일을 컴파일하여 다음과 같은 파일을 생성합니다:

  1. 메시지 파일
    • 역할: .proto 파일에서 정의된 메시지 타입을 직렬화 및 역직렬화할 수 있는 코드를 생성합니다.
    • 예시: User 메시지를 정의한 경우, 해당 메시지의 데이터를 처리할 수 있는 클래스 또는 구조체가 생성됩니다.
    • 디폴트 파일 이름: example.pb.go (Go), example_pb2.py (Python)
  2. gRPC 서비스 파일
    • 역할: gRPC 서비스의 클라이언트와 서버 인터페이스를 생성합니다.
      • 클라이언트 측: 서버 메서드를 호출할 수 있는 메서드가 포함된 클래스 제공
      • 서버 측: 서비스 구현을 위한 추상 클래스 생성
    • 디폴트 파일 이름: example_grpc.pb.go (Go), example_pb2_grpc.py (Python)


gRPC 통신 방법


gRPC는 네 가지 주요 통신 방법을 제공합니다:

  1. Unary RPC

    • 클라이언트가 단일 요청을 보내고 서버가 단일 응답을 반환합니다.
    • 사용 예시: 파일 상태 확인, 사용자 인증 요청

    예시:

    service FileService {
        rpc CheckFile (FileRequest) returns (FileResponse);
    }
    
    message FileRequest {
        string filename = 1;
    }
    
    message FileResponse {
        bool exists = 1;
        int64 size = 2;
    }
    
    

    Go 서버 예시:

    func (s *server) CheckFile(ctx context.Context, req *pb.FileRequest) (*pb.FileResponse, error) {
        // 파일 상태 확인 로직
        return &pb.FileResponse{Exists: true, Size: 1024}, nil
    }
    
    

    Go 클라이언트 예시:

    res, err := client.CheckFile(ctx, &pb.FileRequest{Filename: "example.txt"})
    if err != nil {
        log.Fatalf("Error checking file: %v", err)
    }
    log.Printf("File exists: %v, Size: %d", res.Exists, res.Size)
    
    
  2. Server Streaming RPC
    • 클라이언트가 요청을 보내면 서버가 여러 응답을 스트리밍합니다.
    • 사용 예시: 실시간 로그 스트리밍, 대규모 데이터 전송
  3. Client Streaming RPC
    • 클라이언트가 여러 요청을 스트리밍으로 보내고 서버가 단일 응답을 반환합니다.
    • 사용 예시: 클라이언트의 배치 데이터 처리
  4. Bidirectional Streaming RPC

    • 클라이언트와 서버가 동시에 스트리밍 데이터를 주고받습니다.
    • 사용 예시: 채팅 애플리케이션, 실시간 협업 도구

    Bidirectional Streaming 예시:

    service ChatService {
        rpc Chat(stream ChatMessage) returns (stream ChatMessage);
    }
    
    message ChatMessage {
        string sender = 1;
        string content = 2;
    }
    
    

    Go 서버 예시:

    func (s *server) Chat(stream pb.ChatService_ChatServer) error {
        for {
            msg, err := stream.Recv()
            if err == io.EOF {
                return nil
            }
            if err != nil {
                return err
            }
            log.Printf("Received message from %s: %s", msg.Sender, msg.Content)
            if err := stream.Send(&pb.ChatMessage{
                Sender:  "Server",
                Content: fmt.Sprintf("Hello, %s!", msg.Sender),
            }); err != nil {
                return err
            }
        }
    }
    
    

    Go 클라이언트 예시:

    stream, err := client.Chat(ctx)
    if err != nil {
        log.Fatalf("Error starting chat: %v", err)
    }
    go func() {
        for {
            msg, err := stream.Recv()
            if err == io.EOF {
                break
            }
            if err != nil {
                log.Fatalf("Error receiving message: %v", err)
            }
            log.Printf("Server: %s", msg.Content)
        }
    }()
    for _, content := range []string{"Hi!", "How are you?", "Goodbye!"} {
        if err := stream.Send(&pb.ChatMessage{
            Sender:  "Client",
            Content: content,
        }); err != nil {
            log.Fatalf("Error sending message: %v", err)
        }
    }
    stream.CloseSend()
    
    


Go와 Python에서 필요한 플러그인


  1. Go

    • protoc-gen-go: Protobuf 메시지 파일 생성
    • protoc-gen-go-grpc: gRPC 서비스 파일 생성
    • 설치:

      go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
      go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
      
      
  2. Python

    • grpcio: gRPC 라이브러리
    • grpcio-tools: Protobuf 및 gRPC 파일 생성
    • 설치:

      pip install grpcio grpcio-tools