본문 바로가기
프로그래밍/기타

[gRPC] protocol buffer3를 실제로 사용해보자

by 사바라다 2021. 7. 25.

안녕하세요. 오늘은 gRPC의 2번째 시간입니다. 오늘은 gRPC에서 사용하는 IDL(Interface Defintion Language)인 protocol buffer을 실제로 사용해보도록 하겠습니다. 

기본

프로토콜 버퍼(protocol buffer)는 .proto의 확장자를 파일명으로 가집니다. 그리고 내부의 기본적인 구성은 아래와 같습니다.

syntax = "proto3";

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}

위의 구성을 통해 알 수 있는 내용을 보면 아래와 같습니다.

  • 첫 라인에는 syntax로 proto3를 사용한다고 명시해줍니다. 명시하지않으면 기본 값으로 proto2의 문법이 적용되기때문에 필수적입니다.
  • message는 모델을 만드는 키워드입니다. qeury, page_number, result_per_page라는 3개의 필드를 가지는 모델인 SearchRequest에 대해서 정의하고 있다고 생각하시면 됩니다.
  • 프로토콜 버퍼에서 모든 필드는 scalar type을 가집니다. 위 에제는 2개의 정수 변수와 1개의 문자열 변수를 선언했습니다.
  • 모든 필드는 고유한 숫자(unique number)를 하나씩 가집니디. 프로토콜 버퍼는 통신시 byte stream으로 전달되기 때문에 직렬화/역직렬화시 이 숫자는 순서를 나타내며 중요하며 필수적입니다.

위의 예제는 프로토콜 버퍼를 사용할 때 가장 기본이되는 구성을 가지고 있습니다. 여기에 조금 더 추가한 아래의 예제를 보도록 하겠습니다.

syntax = "proto3";

/*
 * 요청 Model
 */
message SearchRequest {
    string query = 1;           // 이렇게도 주석을 사용할 수 있어요
    int32 page_number = 2;
    int32 result_per_page = 3;
}

/*
 * 응답 Model
 */
message SearchResponse {
    int32 code = 1;

    enum Corpus {
        UNIVERSAL = 0;
        WEB = 1;
        IMAGES = 2;
        LOCAL = 3;
        NEWS = 4;
        PRODUCTS = 5;
        VIDEO = 6;
    }

    Corpus corpus = 3;
}

위의 구성을 통해 알 수 있는 내용을 보면 아래와 같습니다.

  • 프토토콜 버퍼는 // 키워드를 이용하여 1줄짜리 주석을 사용할 수 있으며, /**/를 이용하여 여러줄 짜리 주석을 사용할 수 있습니다. 이 주석은 java 등 다른 언어로 만들어질때 함께 들어갑니다.
  • enum 타입을 지정할 수 있습니다. 위 코드에서는 Corpus enum 타입을 정의한 후 사용하고 있습니다. enum 또한 고유한 0을 포함한 자연수의 숫자를 필요로 합니다. enum에 option allow_alias = true;를 추가하면 숫자를 겹치게하여 사용할 수도 있습니다.

더 나아가기

또 다른 프로토콜 버퍼 예제를 하나 보도록 하겠습니다.

message SearchResponse3 {
    repeated Result results = 1;
}

message Result {
    string url = 1;
    string title = 2;
    repeated string snippets = 3;
    map<string, string> projects = 4;
}
  • 프로토콜 버퍼는 내부에 또 다른 message를 포함할 수 있습니다. 위의 예제에서는 SearchResponse3 모델에서 Result 모델을 참조하고 있습니다.
  • SearchResponse3에서 result와 Result에서 snippets 모두 repeated라는 키워드를 사용하고 있습니다. 해당 키워드릴 사용하면 List로써 필드를 다루게 됩니다.
  • Result 모델에 map<string, stirng> 을 타입으로 사용한 것을 보실 수 있습니다. 프로토콜 버퍼에서는 맵 자료구조를 지원합니다. 이 타입은 repeated 키워드는 지원하지 않기 때문에 주의가 필요합니다.

그 외

기본값

  • string 타입은 empty string을 기본값으로 가집니다.
  • byte 타입은 empty byte를 기본값으로 가집니다.
  • bool 타입은 false를 기본값으로 가집니다.
  • 숫자형 타입은 0을 기본값으로 가집니다.
  • enum 타입은 첫번째 값을 기본값으로 가집니다.
  • message 타입은 기본값이 없습니다. 이에 대한 처리는 각각 언어에 따라 달라집니다.

package

프로토콜 버퍼에서 package를 선언할 수 있습니다. 이렇게 선언하면 해당 파일에 선언되는 message 들은 java에서 그 패키지에 위치하게 됩니다.

package me.sabarada;

Service 정의

RPC에서 프로토콜 버퍼를 사용하기 위해서는 service의 정의가 필요합니다. service 정의에 의해서 통신에 필요한 구성요소들이 만들어지게 됩니다.

service HelloService {
    rpc SayHello (HelloRequest) returns (HelloResponse);
    rpc LotsOfReplies (HelloRequest) returns (stream HelloResponse);
    rpc LotsOfGreetings (stream HelloRequest) returns (HelloResponse);
    rpc BidiHello (stream HelloRequest) returns (stream HelloResponse);
}

Option

option은 프로토콜 버퍼에서 추가적으로 제공하는 기능입니다. 이 기능은 각자 언어에 따라 달라질 수 있습니다. 여기서는 java에서 주로 사용되는 옵션 2개를 설명드리겠습니다. java_outer_classname 옵션은 java에서 생성될 클래스의 이름을 나타냅니다. 기본적으로 java로 변환하면 하나의 파일이 하나의 클래스로 변환됩니다. 그 class 파일의 이름이라고 보시면됩니다.

option java_outer_classname = "Sample"; // options --> 클래스 이름
public final class Sample {
  private Sample() {}
  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistryLite registry) {
  }

  public static void registerAllExtensions(
      com.google.protobuf.ExtensionRegistry registry) {
    registerAllExtensions(
        (com.google.protobuf.ExtensionRegistryLite) registry);
  }
  public interface SearchRequestOrBuilder extends
      // @@protoc_insertion_point(interface_extends:me.sabarada.SearchRequest)
      com.google.protobuf.MessageOrBuilder {
[...하략...]

다음 옵션은 하나의 proto 파일에서 설정된 값을 여러개의 클래스 파일로 나누어서 생성하게끔하는 옵션입니다. java_multile_files 옵션은 기본적으로 false이며 true로 변경하면 여러개의 클래스 파일로 하나의 proto 파일을 생성합니다.

option java_multiple_files = true; // option --> 1개의 proto 파일에서 여러개의 클래스 파일이 생성 가능

마무리

오늘은 이렇게 프로토콜 버퍼에 대해서 알아보는 시간을 가져보았습니다.

감사합니다.

참조

developers_google_docs_proto3

 

댓글0