본문 바로가기

Google/ProtocolBuffers

Protocol Buffers : Developer Guide

Welcome to the developer documentation for protocol buffers – a language-neutral, platform-neutral, extensible way of serializing structured data for use in communications protocols, data storage, and more.
프로토콜 버퍼 개발자 설명서 – 언어 중립적이고 플랫폼 중립적이며 확장 가능한 방식으로 구조화된 데이터를 통신 프로토콜, 데이터 스토리지 등에 사용할수 있다.

This documentation is aimed at Java, C++, or Python developers who want to use protocol buffers in their applications. This overview introduces protocol buffers and tells you what you need to do to get started – you can then go on to follow the tutorials or delve deeper into protocol buffer encoding. API reference documentation is also provided for all three languages, as well as language and style guides for writing .proto files.
이 설명서는 애플리케이션에 프로토콜 버퍼를 사용하려는 Java, C++ 또는 Python 개발자를 대상으로 한다. 이 개요에서는 프로토콜 버퍼를 소개하고 시작하기 위해 필요한 작업을 설명한다. 그런 다음 튜토리얼을 따르거나 프로토콜 버퍼 인코딩을 자세히 살펴볼수 있다. API 참조 설명서는 또한 .proto 파일 작성을 위한 언어 및 스타일 가이드뿐만 아니라 세 가지 언어 모두에 대해 제공된다.

What are protocol buffers? 프로토콜 버퍼란?

Protocol buffers are a flexible, efficient, automated mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages. You can even update your data structure without breaking deployed programs that are compiled against the "old" format.
프로토콜 버퍼는 구조화된 데이터를 직렬화하는 유연하고 효율적이며 자동화된 메커니즘입니다. XML을 생각하되, 더 작고, 더 빠르고, 단순하다. 데이터를 한번 구조화하는 방법을 정의한 다음, 생성된 특수소스 코드를 사용하여 다양한 데이터스트림과 다양한 언어를 사용하여 구조화된 데이터를 쉽게 읽고, 쓸수 있다. "이전" 형식으로 컴파일된 배포된 프로그램을 중단하지 않고 데이터 구조를 업데이트할 수도 있다.

How do they work? 어떻게 일하는가?

You specify how you want the information you're serializing to be structured by defining protocol buffer message types in .proto files. Each protocol buffer message is a small logical record of information, containing a series of name-value pairs. Here's a very basic example of a .proto file that defines a message containing information about a person:
.proto 파일에서 프로토콜 버퍼 메시지 유형을 정의하여 직렬화하려는 정보를 구조화하는 방법을 지정한다. 각 프로토콜 버퍼 메시지는 일련의 이름-값 쌍을 포함하는 작은 논리적 정보 레코드다. 다음은 사용자에 대한 정보가 포함된 메시지를 정의하는 .proto 파일의 매우 기본적인 예이다.

message Person {
    required string name = 1;
    required int32 id = 2;
    optional string email = 3;
  
    enum PhoneType {
      MOBILE = 0;
      HOME = 1;
      WORK = 2;
    }
  
    message PhoneNumber {
      required string number = 1;
      optional PhoneType type = 2 [default = HOME];
    }
  
    repeated PhoneNumber phone = 4;
  }

As you can see, the message format is simple – each message type has one or more uniquely numbered fields, and each field has a name and a value type, where value types can be numbers (integer or floating-point), booleans, strings, raw bytes, or even (as in the example above) other protocol buffer message types, allowing you to structure your data hierarchically. You can specify optional fields, required fields, and repeated fields. You can find more information about writing .proto files in the Protocol Buffer Language Guide.
보시다시피 메시지 형식은 간단하다. 각 메시지 프로토콜에는 하나 이상의 고유번호 필드가 있고, 각 필드에는 이름 및 값 유형이 있으며, 여기서 값 유형은 숫자(정수 또는 부동 소수점), 부울 유형일수 있다. 계층적으로 선택적 필드, 필수필드 및 반복 필드를 지정할수 있다. .proto 파일 쓰기에 대한 자세한 내용은 프로토콜 버퍼 언어 안내서에서 확인할수 있다.

Once you've defined your messages, you run the protocol buffer compiler for your application's language on your .proto file to generate data access classes. These provide simple accessors for each field (like name() and set_name()) as well as methods to serialize/parse the whole structure to/from raw bytes – so, for instance, if your chosen language is C++, running the compiler on the above example will generate a class called Person. You can then use this class in your application to populate, serialize, and retrieve Person protocol buffer messages. You might then write some code like this:
메시지를 정의한 후에 .proto 파일에서 응용프로그램 언어에 대한 프로토콜 버퍼 컴파일러를 실행하여 데이터 액세스 클래스를 생성한다. 각 필드(예: name() 및 set_name()에 대한 간단한 접근자와 전체구조를 직렬화하고 원시 바이트에서 구문분석하기 위한 방법을 제공한다. 예를 들어 선택한 언어가 C인 경우). 그런 다음 응용프로그램에서 이 클래스를 사용하여 사용자 프로토콜 버퍼 메시지를 채우고, 직렬화하고, 검색할수 있다. 다음과 같은 코드를 작성할수 있다.

Person person;
    person.set_name("John Doe");
    person.set_id(1234);
    person.set_email("jdoe@example.com");
    fstream output("myfile", ios::out | ios::binary);
    person.SerializeToOstream(&output);

다음과 같이 읽어들일수 있다.

fstream input("myfile", ios::in | ios::binary);
    Person person;
    person.ParseFromIstream(&input);
    cout << "Name: " << person.name() << endl;
    cout << "E-mail: " << person.email() << endl;

You can add new fields to your message formats without breaking backwards-compatibility; old binaries simply ignore the new field when parsing. So if you have a communications protocol that uses protocol buffers as its data format, you can extend your protocol without having to worry about breaking existing code.
이전 이진파일은 구문분석할 때 새 필드를 무시하기만 하면 이전 호환성이 끊어지지 않고 메시지 형식에 새 필드를 추가할수 있다. 따라서 프로토콜 버퍼를 데이터형식으로 사용하는 통신프로토콜이 있는 경우 기존코드를 손상시킬 염려없이 프로토콜을 확장할수 있다.

You'll find a complete reference for using generated protocol buffer code in the API Reference section, and you can find out more about how protocol buffer messages are encoded in Protocol Buffer Encoding.
생성된 프로토콜 버퍼 코드를 사용하기 위한 전체 참조는 API 참조 섹션에서 찾을수 있으며 프로토콜 버퍼 메시지가 프로토콜 버퍼 인코딩으로 인코딩되는 방법에 대해 자세히 알아볼수 있습니다.

Why not just use XML? XML만 사용하지 않는 이유는 무엇입니까?

Protocol buffers have many advantages over XML for serializing structured data. Protocol buffers:
프로토콜 버퍼는 구조화된 데이터를 직렬화하는 데 XML에 비해 많은 이점이 있습니다. 프로토콜 버퍼는 :

  • are simpler
    더 간단하다.
  • are 3 to 10 times smaller
    3배에서 10배 더 작다.
  • are 20 to 100 times faster
    20~100배 더 빠르다.
  • are less ambiguous
    덜 모호하다
  • generate data access classes that are easier to use programmatically
    프로그래밍 방식으로 사용하기 쉬운 데이터 액세스 클래스를 생성한다.

For example, let's say you want to model a person with a name and an email. In XML, you need to do:
예를 들어, 이름과 이메일을 가진 사람을 모델링한다고 가정해보자. XML에서 다음을 수행한다.

<person>
    <name>John Doe</name>
    <email>jdoe@example.com</email>
</person>

while the corresponding protocol buffer message (in protocol buffer text format) is:
프로토콜 버퍼 메시지(프로토콜 버퍼 텍스트 형식)는 다음과 같다.

# Textual representation of a protocol buffer.
# This is *not* the binary format used on the wire.
person {
    name: "John Doe"
    email: "jdoe@example.com"
}

When this message is encoded to the protocol buffer binary format (the text format above is just a convenient human-readable representation for debugging and editing), it would probably be 28 bytes long and take around 100-200 nanoseconds to parse. The XML version is at least 69 bytes if you remove whitespace, and would take around 5,000-10,000 nanoseconds to parse.
이 메시지가 프로토콜 버퍼 바이너리 형식(위의 텍스트 형식은 디버깅과 편집을 위해 인간이 읽을 수 있는 편리한 표현일 뿐)으로 인코딩되면 28바이트의 길이이며 100-200나노초의 파싱이 필요할 것이다. 공백을 제거하면 XML 버전은 69바이트 이상이며 파싱하는 데 약 5,000~10,000나노초 정도 소요된다.

Also, manipulating a protocol buffer is much easier:
또한 프로토콜 버퍼를 조작하는 것이 훨씬 쉽다.

cout << "Name: " << person.name() << endl;
cout << "E-mail: " << person.email() << endl;

Whereas with XML you would have to do something like:
반면 XML에서는 다음과 같은 작업을 수행해야 한다.

cout << "Name: "
    << person.getElementsByTagName("name")->item(0)->innerText()
    << endl;
cout << "E-mail: "
    << person.getElementsByTagName("email")->item(0)->innerText()
    << endl;

However, protocol buffers are not always a better solution than XML – for instance, protocol buffers would not be a good way to model a text-based document with markup (e.g. HTML), since you cannot easily interleave structure with text. In addition, XML is human-readable and human-editable; protocol buffers, at least in their native format, are not. XML is also – to some extent – self-describing. A protocol buffer is only meaningful if you have the message definition (the .proto file).
그러나 프로토콜 버퍼가 XML보다 항상 나은 솔루션은 아니다. 예를 들어, 프로토콜 버퍼가 마크업(예: HTML)으로 텍스트 기반 문서를 모델링하는 좋은 방법은 아니다. 또한 XML은 사람이 읽을수 있고, 사용자가 편집할수 있다; 프로토콜 버퍼는 기본형식에는 최소한 없다. XML은 어느정도 자체 설명이 가능하다. 프로토콜 버퍼는 메시지 정의(.proto 파일)가 있는 경우에만 의미가 있다.

Sounds like the solution for me! How do I get started? 나한테 해결책이 될 것 같아! 어떻게 시작해야 합니까?

Download the package – this contains the complete source code for the Java, Python, and C++ protocol buffer compilers, as well as the classes you need for I/O and testing. To build and install your compiler, follow the instructions in the README.
패키지 다운로드 – Java, Python 및 C++ 프로토콜 버퍼 컴파일러의 전체 소스코드와 I/O 및 테스트에 필요한 클래스를 포함한다. 컴파일러를 제작하고 설치하려면 README의 지침을 따르세요.

Once you're all set, try following the tutorial for your chosen language – this will step you through creating a simple application that uses protocol buffers.
모든 것을 설정하고 나면 선택한 언어에 대한 튜토리얼을 따르세요. 그러면 프로토콜 버퍼를 사용하는 간단한 애플리케이션을 만드는 과정을 안내한다.

Introducing proto3

Our most recent version 3 release introduces a new language version - Protocol Buffers language version 3 (aka proto3), as well as some new features in our existing language version (aka proto2). Proto3 simplifies the protocol buffer language, both for ease of use and to make it available in a wider range of programming languages: our current release lets you generate protocol buffer code in Java, C++, Python, Java Lite, Ruby, JavaScript, Objective-C, and C#. In addition you can generate proto3 code for Go using the latest Go protoc plugin, available from the golang/protobuf Github repository. More languages are in the pipeline.
가장 최근 버전3 릴리스에서는 새로운 언어버전 - Protocol Buffers language version 3(선도3), 기존 언어 버전(선도2)의 몇 가지 새로운기능을 소개한다. Proto3는 프로토콜 버퍼 언어를 단순화하여 사용하기 쉽고 광범위한 프로그래밍 언어로 사용할수 있도록 한다. 현재 릴리즈에서는 Java, C+, C+, Python, Java Lite, Ruby로 프로토콜 버퍼 코드를 생성할수 있다. 또한 golang/protobuf Github 리포지토리에서 사용할수 있는 최신 Go protoc 플러그인을 사용하여 Go에 대한 proto3 코드를 생성할수 있다. 더 많은 언어들이 파이프라인 안에 있다.

Note that the two language version APIs are not completely compatible. To avoid inconvenience to existing users, we will continue to support the previous language version in new protocol buffers releases.
두 언어 버전 API는 완전히 호환되지 않는다. 기존 사용자의 불편을 피하기 위해, 새로운 프로토콜 버퍼 릴리스에서 이전 언어 버전을 계속 지원할 것이다.

You can see the major differences from the current default version in the release notes and learn about proto3 syntax in the Proto3 Language Guide. Full documentation for proto3 is coming soon!
릴리스 정보에서 현재 기본버전과 주요차이를 확인하고 Proto3 언어 가이드에서 proto3 구문에 대해 배울수 있다. 프로토3에 대한 전체문서가 곧 출시될 것이다!

(If the names proto2 and proto3 seem a little confusing, it's because when we originally open-sourced protocol buffers it was actually Google's second version of the language – also known as proto2. This is also why our open source version number started from v2.0.0).
(만약 proto2와 proto3의 이름이 약간 혼란스럽게 보인다면, 그것은 우리가 원래 오픈소스 프로토콜 버퍼를 만들었을 때, proto2로도 알려진 구글의 두번째 언어버전이었기 때문이다. 오픈소스 버전번호가 v2.0.0에서 시작된 것도 이 때문이다.

A bit of history 약간의 역사

Protocol buffers were initially developed at Google to deal with an index server request/response protocol. Prior to protocol buffers, there was a format for requests and responses that used hand marshalling/unmarshalling of requests and responses, and that supported a number of versions of the protocol. This resulted in some very ugly code, like:
프로토콜 버퍼는 처음에 색인서버 요청/응답 프로토콜을 처리하기 위해 Google에서 개발되었다. 프로토콜 버퍼 이전에는 요청과 응답의 수동 marshalling/unmarshalling를 사용하고 다수의 프로토콜 버전을 지원하는 요청 및 응답 형식이 있었다. 그 결과 다음과 같은 매우 추한 코드가 발생했다.

 if (version == 3) {
    ...
} else if (version > 4) {
    if (version == 5) {
        ...
    }
    ...
}

Explicitly formatted protocols also complicated the rollout of new protocol versions, because developers had to make sure that all servers between the originator of the request and the actual server handling the request understood the new protocol before they could flip a switch to start using the new protocol.
명시적으로 포맷된 프로토콜은 요청의 발신자와 요청을 처리하는 실제서버 사이의 모든 서버가 새 프로토콜을 이해했는지 확인해야 했기 때문에 새 프로토콜의 롤아웃도 복잡했다.

Protocol buffers were designed to solve many of these problems:
프로토콜 버퍼는 다음과 같은 많은 문제를 해결하기 위해 설계되었다.

  • New fields could be easily introduced, and intermediate servers that didn't need to inspect the data could simply parse it and pass through the data without needing to know about all the fields.
    새로운 필드를 쉽게 도입할수 있고, 데이터를 검사할 필요가 없는 중간 서버는 단순히 데이터를 구문분석하고 모든 필드에 대해 알 필요 없이 데이터를 전달할 수 있다.
  • Formats were more self-describing, and could be dealt with from a variety of languages (C++, Java, etc.)
    형식은 더욱 자기 설명적이며, 다양한 언어(C++, Java 등)로 처리할수 있다.

However, users still needed to hand-write their own parsing code.
그러나 사용자는 여전히 자신의 구문분석 코드를 직접 작성해야 했다.

As the system evolved, it acquired a number of other features and uses:
시스템이 발전함에 따라 다음과 같은 다양한 기능과 용도를 확보했다.

  • Automatically-generated serialization and deserialization code avoided the need for hand parsing.
    자동으로 생성된 직렬화 및 역직렬화 코드로 인해 수동 구문분석할 필요가 없다.
  • In addition to being used for short-lived RPC (Remote Procedure Call) requests, people started to use protocol buffers as a handy self-describing format for storing data persistently (for example, in Bigtable).
    단기 RPC(Remote Procedure Call)요청에 사용되는것 외에도, 사람들은 데이터를 지속적으로 저장할수 있는 편리한 자체설명 형식으로 프로토콜 버퍼를 사용하기 시작했다(예: Bigtable).
  • Server RPC interfaces started to be declared as part of protocol files, with the protocol compiler generating stub classes that users could override with actual implementations of the server's interface.
    프로토콜 컴파일러가 스텁 클래스를 생성하여 사용자가 서버 인터페이스의 실제 구현으로 재 정의할수 있는 서버RPC 인터페이스가 프로토콜 파일의 일부로 선언되기 시작했다.

Protocol buffers are now Google's lingua franca for data – at time of writing, there are 48,162 different message types defined in the Google code tree across 12,183 .proto files. They're used both in RPC systems and for persistent storage of data in a variety of storage systems.
로토콜 버퍼는 이제 데이터를 위한 Google의 언어 프랑카이다. 작성 시점에 Google 코드 트리에서 정의된 메시지 유형은 12,183개 .proto 파일에 걸쳐 48,162개다. RPC 시스템과 다양한 스토리지 시스템의 지속적인 데이터 저장에 모두 사용된다.