저번에 gRPC에 대해 알아보는 글을 적었었는데,
그 과정에서 gRPC는 JSON이 아닌 프로토콜 버퍼를 이용하여 데이터를 전송한다고 했었다.
오늘은 그래서 프로토콜 버퍼가 무엇인지,
JSON에 비해 왜 좋다고 하는 건지 정리를 해보자 !
Protocol Buffer?
구조화 된 데이터를 직렬화 하는 방식
직렬화(Serialization)란 , 데이터를 파일로 저장하거나 네트워크 통신에 사용하기 위한 byte stream형태로 변환하는 것이다.
server - client 간 데이터를 교환 할 때 주로 JSON을 사용하는데,
gRPC에서 ProtoBuf를 사용하는 이유는 무엇일까?
JSON과의 차이점?
{name : "minah", age : 27} 이라는 객체가 있다고 했을 때,
1. JSON 포맷으로 직렬화 할 경우
let person = { name : "jinny" age : 27 };
//JS객체 -> JSON 문자열로 변경
let serializedJson = JSON.stringify(person);
// 데이터 크기는 총 25byte
//serializedJson = {"name":"jinny","age":27}
2. 프로토콜 버퍼 포맷으로 직렬화 할 경우
* 프로토 파일 : 프로토콜 버퍼 방식을 사용하기 위해 필요한 파일
message Person
{
string name = 1; //필드 넘버
int32 age = 27;
}
프로토콜 버퍼를 사용할 경우에는 속성 값 (name, age)을 필드 넘버로 대체하기 때문에, 총 9byte를 사용하게 하게 된다.
name?
■( 최초 1 byte => 필드 넘버와 타입을 표기하는데 사용 ) ■ (다음에 올 데이터 길이) ■ ■ ■ ■ ■ (데이터)
<최초 1byte>
□ □ □ □ □ (필드 넘버) □ □ □ (필드 타입)
age?
■ (필드 태그와 넘버) ■ (데이터)
Field Type
프로토콜 버퍼의 메세지에서 사용할 수 있는 필드 타입은 한정적으로 정해져 있는데,
내가 사용하는 유니티. 즉 c#에서 자주 사용하는 필드 타입만 정리해보겠다.
| .proto | c# |
| double | double |
| float | float |
| int32 | int |
| int64 | long |
| uint32 | uint |
| uint64 | ulong |
| bool | bool |
| string | string |
또한 c++ 의 헤더 참조 (#include)처럼 .proto또한 import 문을 추가 하여 다른 .proto파일을 참조할 수 있다.
예를 들어 아래와 같은 ItemBase 를 정의해놓은 파일이 있다고 가정해보자.
// item_base.proto 라고 가정할 때
message ItemBase
{
int32 id = 1;
string name = 2;
int32 amount = 3;
}
만약, 다른 프로토 파일에서 해당 message 유형을 사용하고 싶을 경우
아래와 같이 사용할 수 있다.
import "protos/item_base.proto";
message ItemWeapon
{
ItemBase data = 1;
bool is_equip = 2;
int32 weapon_option = 3;
}
그 외 repeated 타입을 이용하여 C++의 Vector (C#의 List) ,
map 을 이용하여 페어링 된 키 - 필드 자료 구조를 사용할 수 있다.
(C++의 unordered_map (정렬 되지않은 해시셋이라고 생각하면 될 것 같음) / C#의 Dictionary)
관련한 자료의 링크를 첨부함.
https://protobuf.dev/programming-guides/encoding/#maps%EF%BB%BF
Encoding
Explains how Protocol Buffers encodes data to files or to the wire.
protobuf.dev
그러나 map의 value는 repeated가 될 수 없다
즉 내가 애용하는...
map<string,vector<T>> 의 형태가 불가능 하다는 것....
그치만 message유형은 저장이 가능하기에 조금 번거롭긴 하지만
실무에서는 대충 이런 느낌으로 사용 중...
message ItemBase
{
int32 id = 1;
int32 amount = 2;
}
message ItemList
{
repeated ItemBase item_lists = 1;
}
message UserEquipments
{
map<string,ItemList> all_user_equipments = 1;
}
프로토콜 버퍼에 대한 공식 문서를 추가로 첨부하고
글을 마치겠음.
[구글에서 제시한 스타일 가이드]
https://protobuf.dev/programming-guides/style/
Style Guide
Provides direction for how best to structure your proto definitions.
protobuf.dev
[protocol buffers]
https://protobuf.dev/overview/
Overview
Protocol Buffers are a language-neutral, platform-neutral extensible mechanism for serializing structured data.
protobuf.dev