Protocol Buffers Reference
protobuf 메시지 정의 문법, 타입, 서비스 레퍼런스
Protocol Buffers Reference 소개
Protocol Buffers 레퍼런스는 gRPC 서비스와 고성능 데이터 저장소에 사용되는 Google의 언어 중립 이진 직렬화 형식인 Protocol Buffers(protobuf) 버전 3의 모든 필수 구문을 체계적으로 정리한 검색 가능한 가이드입니다. 타입(스칼라 타입: double, float, int32, int64, uint32, uint64, bool, string, bytes), 메시지(메시지 정의, enum, 유니온 타입을 위한 oneof, map<K,V>, 배열을 위한 repeated, 중첩 메시지), 서비스(gRPC를 위한 service와 rpc 정의, stream 키워드를 이용한 단방향 및 양방향 스트리밍), 옵션(import, package 네임스페이스, go_package/java_package 같은 언어별 코드 생성 옵션), 인코딩(호환성 문제 방지를 위한 reserved 필드/이름, Varint/64-bit/길이 구분/32-bit 와이어 타입 참조) 5개 카테고리로 구성됩니다.
백엔드 엔지니어, 플랫폼 아키텍트, 모바일 개발자들이 gRPC API 설계, 마이크로서비스 통신을 위한 데이터 스키마 정의, 성능을 위한 JSON/XML에서 이진 직렬화로의 마이그레이션, 스트리밍 RPC 패턴 구현 시 이 레퍼런스를 활용합니다. Protocol Buffers는 gRPC의 기본 직렬화 형식으로, 효율적이고 강타입의 서비스 간 통신이 필요한 Google, Uber, Netflix 등 대형 기업에서 대규모로 사용됩니다.
각 항목은 실제 마이크로서비스 컨텍스트에서 필드 선언이나 서비스 정의를 보여주는 구체적인 .proto 파일 예제와 함께 proto3 구문을 제공합니다. 필드 번호 할당 규칙, 열거형 제로 값의 중요성(UNKNOWN = 0 관례), oneof 필드와 optional 필드의 차이, map<string, int32>가 repeated 키-값 메시지와 어떻게 다른지, 이진 인코딩에 사용되는 4가지 와이어 타입도 다룹니다.
주요 기능
- 모든 proto3 스칼라 타입: double, float, int32, int64, uint32, uint64, bool, string, bytes와 필드 번호 할당
- 단일 .proto 파일에서 중첩 메시지와 여러 필드 타입을 포함한 메시지 정의
- 필수 제로 값(UNKNOWN = 0) 관례와 정수 매핑을 포함한 열거형 정의
- 한 번에 하나의 값만 설정할 수 있는 상호 배타적 필드를 위한 oneof
- 허용 키 타입을 포함한 키-값 쌍(dict/HashMap과 동일)을 위한 map<K, V>
- 모든 스칼라 또는 메시지 타입의 배열/리스트 필드를 위한 repeated 키워드
- gRPC service와 rpc 정의: 단방향 RPC, 서버 스트리밍, 클라이언트 스트리밍, 양방향 스트리밍
- 이진 인코딩 이해를 위한 와이어 타입 참조: Varint(0), 64-bit(1), 길이 구분(2), 32-bit(5)
자주 묻는 질문
Protocol Buffers(protobuf)란 무엇이고 JSON 대신 왜 사용하나요?
Protocol Buffers는 Google의 언어 중립, 플랫폼 중립 이진 직렬화 형식입니다. JSON과 비교하면 데이터를 3-10배 더 작게 직렬화하고 5-10배 빠르며, 강력한 스키마 강제(정의되지 않은 필드 전송 불가), 단일 .proto 정의에서 여러 언어의 타입 안전 코드 생성, 스키마 진화(이전 클라이언트 손상 없이 새 필드 추가) 지원 등의 장점이 있습니다.
proto2와 proto3의 차이는 무엇인가요?
proto3는 required 필드 제거(모든 필드가 기본적으로 optional), 기본값 제거(필드는 제로/빈 값으로 기본 설정), 스칼라 타입의 필드 존재 추적 제거로 proto2를 단순화했습니다. proto3는 특히 gRPC와 함께 새 프로젝트에 권장되는 버전입니다. 주요 차이점: required 키워드 없음, 커스텀 기본값 없음, 첫 번째 enum 값은 반드시 0이어야 함.
protobuf에서 첫 번째 열거형 값이 0이어야 하는 이유는?
proto3에서 열거형 필드의 기본값은 첫 번째로 정의된 값이며 그 값은 반드시 0이어야 합니다. 이는 메시지를 역직렬화할 때 열거형 필드가 없거나 인식되지 않으면 제로 값으로 기본 설정되도록 보장합니다. 관례적으로 제로 값의 이름은 UNKNOWN 또는 UNSPECIFIED로 하여 "설정되지 않음" 또는 "기본값" 상태를 명시적으로 나타냅니다.
protobuf에서 oneof와 optional 필드를 각각 언제 사용해야 하나요?
한 번에 하나만 설정할 수 있는 상호 배타적 필드 집합이 있을 때(유니온 타입처럼) oneof를 사용합니다. oneof는 하나의 필드를 설정하면 그룹의 다른 모든 필드가 자동으로 지워지는 것을 보장합니다. 일반 optional 필드는 독립적으로 동시에 여러 개를 설정할 수 있습니다. oneof는 다형성 메시지(예: 문자열 text, int32 코드, bool 플래그 중 하나를 포함하는 Result)에 유용합니다.
protobuf에서 gRPC 스트리밍 RPC를 정의하는 방법은?
요청이나 응답 타입 앞에 stream 키워드를 추가합니다. 서버 스트리밍: `rpc ListUsers(ListRequest) returns (stream User)` — 서버가 여러 User 메시지를 전송. 클라이언트 스트리밍: `rpc UploadFile(stream Chunk) returns (UploadResponse)` — 클라이언트가 여러 청크를 전송. 양방향 스트리밍: `rpc Chat(stream Message) returns (stream Message)` — 양쪽에서 여러 메시지를 전송.
protobuf의 reserved 필드는 무엇이고 왜 중요한가요?
메시지에서 필드를 제거할 때 향후 개발자가 해당 필드 번호를 재사용하지 못하도록 예약해야 합니다. 새 필드가 이전 번호를 재사용하면 이전 클라이언트와 새 클라이언트가 서로의 데이터를 자동으로 잘못 해석합니다. `reserved 2, 15, 9 to 11;`으로 필드 번호를 예약하고 `reserved "old_field_name";`으로 이름을 예약하여 재사용을 방지하세요.
protobuf의 int32와 sint32의 차이는?
int32는 표준 Varint 인코딩을 사용하는데 음수에는 비효율적입니다(-1 값은 10바이트를 사용). sint32는 ZigZag 인코딩을 사용하여 음수에 효율적입니다(양수와 음수 정수를 부호 없는 정수로 매핑). 필드에 음수 값이 자주 포함된다면 sint32 또는 sint64를 사용하세요. 음수가 없는 값에는 uint32가 가장 공간 효율적입니다.
proto3 필드 번호는 어떻게 작동하고 예약된 범위는 무엇인가요?
proto3 메시지의 각 필드는 1부터 536,870,911 사이의 고유 필드 번호를 가져야 합니다. 필드 번호 1-15는 인코딩에 1바이트를 사용하므로(자주 설정되는 필드에 사용) 자주 쓰는 필드에 할당하고, 16-2047은 2바이트를 사용합니다. 필드 번호 19000-19999는 Google의 protobuf 구현이 예약하여 사용 불가합니다. 한번 할당 및 배포된 필드 번호를 변경하면 하위 호환성이 깨집니다.