ProtoBuf

 

Protocol Buffer(ProtoBuf)

Google에서 구조화된 데이터를 직렬화된 바이트 스트림이다. JSON의 형식보다 가벼워 통신에 있어 속도의 이점을 지닐 수 있다. Request나 Response의 message를 정의하여 언어가 상이한 서버에서도 동일한 Message를 관리할 수 도 있다. 현재 서비스하는 프로젝트에서도 IDL로써 클라이언트, 웹 백엔드, 웹 프론트에서 각 언어에 맞게 컴파일하여 사용하고 있다.

protobuf

 

ProtoFile

.proto 파일은 message, package, option, service 등으로 구성되어 있다.

// item.proto

syntax = "proto3";

package proto.example;
option java_package = "yearlune.lab.proto.example";
option java_outer_classname = "ItemDTO";

message ItemRequest {
	repeated Item items = 1;
}

message Item {
	message Manufacturer {
		string id = 1;
		string name = 2;
	}
	string id = 1;
	string name = 2;
	int64 price = 5;
	
	Manufacturer manufacturer = 10;
}

 

Message

메시지는 필드 이름, 필드 타입, 필드 넘버로 구성되어 있다. message 이름은 camel case를 권장하며, Field 이름은 snake case를 권장한다. repeated 를 통해서 List를 표현할 수 있다.

message ItemRequest {
	repeated Item items = 1;
}

message Item {
	message Manufacturer {
		string id = 1;
		string name = 2;
	}
	string id = 1;
	string name = 2;
	int64 price = 5;
	
	Manufacturer manufacturer = 10;
}

 

Field Type

스칼라타입, Message, Enum 등을 필드 타입으로 설정할 수 있다.

Scalar Value Type

우리에게 익숙한 double, float, int32, int64, uint32, uint64, bool, string, bytes 등이 있다.

https://developers.google.com/protocol-buffers/docs/proto3#scalar

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

 

Message Type

파일 내 message의 참조, nested message의 참조가 가능하며, 다른 .proto 의 message 참조가 가능하다.

// item.proto
syntax = "proto3";

package proto.example;
option java_package = "yearlune.lab.proto.example";
option java_outer_classname = "ItemDTO";

// message 참조
message ItemRequest {
	repeated Item items = 1;
}

// nested message 참조
message Item {
	message Manufacturer {
		string id = 1;
		string name = 2;
	}
	string id = 1;
	string name = 2;
	int64 price = 5;
	
	Manufacturer manufacturer = 10;
}

--------
// order.proto

syntax = "proto3";

import "item.proto";

package proto.example;
option java_package = "yearlune.lab.proto.example";
option java_outer_classname = "OrderDTO";

// other proto message 참조
message OrderRequest {
    string id = 1;
    repeated Item items = 10;
}

 

Default value

  • string: empty string
  • bytes: empty bytes
  • bool: false
  • numeric type(int): 0
  • enum type: enum value 0

Enum

allow_alias로 동일한 enum value를 두어 별칭처럼 둘 수 있다.

enum OrderStatusType {
  UNKNOWN = 0;
	WAIT = 1;
  PROCEEDING = 2;
  DONE = 3;
  FAILED = 4;
  TIMEOUT= 5;
}

enum EnumAllowingAlias {
  option allow_alias = true;
  UNKNOWN = 0;
  STARTED = 1;
  RUNNING = 1;
}

 

Field Number

필드의 고유 넘버를 부여하여 식별하는 데 사용된다. 필드 넘버는 최소 1부터 536,870,911까지 지정 가능하다. 19000 ~ 19999까지는 프로토콜 버퍼 구현에 이미 사용되고 있다.

 

Package

proto message 이름끼리 구분하여 충돌하지 않기 위해 사용된다. C++의 네임스페이스와 같은 역할을 담당한다.

 

Option


java_package
기본적으로 package에 따라 자바 클래스가 생성되지만, 잘못 생성될 가능성이 존재하여, 자바로 활용하기 위해서는 이를 필히 작성하여 명시하는 것이 좋다.
java_outer_classname
기본적으로 .proto 파일의 이름을 camel case로 자바 클래스가 생성된다. 이는 원하는 자바 클래스 이름을 사용할때 사용된다.
java_multiple_files
기본 값은 false이며, 이 경우 .proto파일을 하나의 class로 생성한다. 파일 내 message나 enum 등은 해당 class의 내부 클래스로 선언된다. true인 경우 .proto 파일 내에 존재한 message, enum 등 마다 class로 생성된다.
option java_package = "yearlune.lab.proto.example";
option java_outer_classname = "ItemDTO";

 

Service

RPC서비스의 인터페이스를 정의할 수 있다. 기본은 unary rpc를 지원하며, stream 을 통해서 stream rpc를 지원한다.

service SearchService {
	// Unary RPC
	rpc SearchItemsByName(ItemSearchRequest) returns (ItemSearchResponse);

	// Stream RPC
	rpc Subscribe(ItemSubscribeRequest) returns (stream ItemSubscribeResponse);
}

 

참고문헌

proto3 official document

nbp-기술-경험-시대의-흐름-grpc-깊게-파고들기-1

json-vs-protocol-buffer-simplified

schema-evolution-in-avro-protocol-buffers-thrift

Leave a comment