Protobuf — co to jest, binarny format danych i zasada działania

Autor: IT Sectr Opublikowano: 2026-03-08 Czas czytania: 8 min

Protocol Buffers (Protobuf) — to binarny format serializacji danych strukturalnych, opracowany przez Google do efektywnej wymiany informacji między serwisami. Format wymaga wcześniejszego zdefiniowania schematu w plikach .proto, z których generowany jest kod dla różnych języków. Według oficjalnej dokumentacji Google, Protobuf zapewnia rozmiar wiadomości 3-10 razy mniejszy niż JSON. Protobuf jest używany w gRPC, Google Maps i tysiącach wewnętrznych serwisów.

Najważniejsze

  • Protobuf — binarny format Google do serializacji z kompaktową reprezentacją danych
  • Schematy .proto — ściśle typowany opis struktury danych z kompilacją do kodu
  • Wydajność — serializacja 3-10 razy szybsza i bardziej kompaktowa niż JSON
  • Wsteczna kompatybilność — ewolucja schematów bez psucia istniejących klientów
  • gRPC — główna technologia transportowa dla Protobuf w mikrousługach

Co to są Protocol Buffers?

Protocol Buffers — to opracowany przez Google mechanizm serializacji danych strukturalnych, podobny do JSON i XML, ale z zasadniczą różnicą: dane są kodowane w formacie binarnym. Oznacza to, że wiadomość Protobuf nie może być odczytana gołym okiem, ale zajmuje znacznie mniej miejsca i jest przetwarzana szybciej niż tekstowe odpowiedniki.

Protobuf został stworzony wewnątrz Google do rozwiązywania problemów wydajnościowych przy wymianie danych między serwisami. W 2008 roku technologia stała się otwartym projektem z obsługą wielu języków: C++, Java, Python, Go, JavaScript, Kotlin, Swift, Dart i innych. Wersja proto3, wydana w 2016 roku, uprościła składnię i dodała obsługę większej liczby języków.

Kluczowa różnica między Protobuf a JSON — konieczność zdefiniowania schematu przed rozpoczęciem wymiany danych. Plik schematu (.proto) opisuje strukturę wiadomości: pola, typy i unikalne numery pól. Z tego schematu kompilator protoc generuje klasy w języku docelowym do serializacji i deserializacji.

Ekostystem Protobuf

  • gRPC — wysokowydajny framework RPC, domyślnie używający Protobuf
  • protoc — kompilator schematów .proto do kodu w różnych językach programowania
  • Google API — większość publicznych API Google używa Protobuf
  • Envoy Proxy — używa Protobuf do konfiguracji i wymiany danych

Architektura Protobuf

Architektura Protobuf obejmuje trzy kluczowe komponenty: język definicji schematu (.proto), kompilator protoc i biblioteki runtime dla konkretnych języków. Deweloper opisuje strukturę danych w pliku .proto, uruchamia kompilację i otrzymuje gotowe klasy do pracy z tymi danymi.

Każde pole w wiadomości Protobuf ma unikalny numer (field number) — nie jest to numer porządkowy, ale tag używany w formacie binarnym do identyfikacji pola. Numery od 1 do 15 kodowane są jednym bajtem, od 16 do 2047 — dwoma. Dlatego ważne pola o wysokiej częstotliwości używania warto numerować od 1 do 15 w celu optymalizacji rozmiaru.

Typy danych Protobuf

Protobuf obsługuje szeroki zakres typów: skalarne (int32, int64, float, double, bool, string, bytes), wyliczenia (enum), złożone (message) i specjalne (oneof, map). Każdy typ ma określoną binarną reprezentację, zoptymalizowaną pod odpowiedni scenariusz użycia.

Typ .proto Typ C++ Java/Kotlin Opis
double double double Liczba zmiennoprzecinkowa 64-bit
float float float Liczba zmiennoprzecinkowa 32-bit
int32 int32 int 32-bit, variable-length encoding
int64 int64 long 64-bit, variable-length encoding
string string String Ciąg UTF-8
bytes string ByteString Dowolne bajty
bool bool boolean true / false

Zalety formatu binarnego

Protobuf daje trzy kluczowe zalety w porównaniu z formatami tekstowymi: rozmiar wiadomości, szybkość serializacji i ścisłe typowanie. W systemach o wysokim obciążeniu i aplikacjach mobilnych z ograniczonym ruchem sieciowym zalety te stają się krytyczne.

Binarna reprezentacja Protobuf używa variable-length encoding (Varint) dla liczb: małe liczby zajmują 1 bajt, duże — do 10 bajtów. Pozwala to efektywnie kodować identyfikatory, flagi i liczniki, które w JSON lub XML zajęłyby dziesiątki bajtów jako ciągi tekstowe. Na przykład liczba 150 w Protobuf zajmuje 2 bajty, w JSON — 3 bajty (jako tekst „150”), w XML — 3 bajty + znaczniki.

Dodatkową zaletą jest wsteczna kompatybilność. Dodanie nowego pola do schematu nie psuje starych klientów: po prostu ignorują one nieznane pola. Usunięcie pola wymaga jedynie zarezerwowania jego numeru, aby uniknąć kolizji w przyszłości.

Definiowanie schematu .proto

Schemat .proto opisuje strukturę danych w specjalnym języku. Plik zaczyna się od określenia składni (proto3), pakietu i importu zależności. Każda wiadomość jest definiowana za pomocą słowa kluczowego message z polami, gdzie każde pole ma typ, nazwę i unikalny numer.

Zasady dobrego schematu: numery pól od 1 do 15 dla często używanych pól, sensowne nazwy, grupowanie powiązanych pól w osobne message, używanie oneof dla pól, które mogą być tylko jednym z kilku wariantów.

protobuf
syntax = "proto3";

package mobileapp;

message User {
  string user_id = 1;
  string name = 2;
  string email = 3;
  int32 age = 4;
  UserRole role = 5;
  repeated string tags = 6;
  map<string, string> metadata = 7;
}

enum UserRole {
  USER_ROLE_UNSPECIFIED = 0;
  USER_ROLE_USER = 1;
  USER_ROLE_ADMIN = 2;
  USER_ROLE_MODERATOR = 3;
}

Zagnieżdżone wiadomości

Wiadomości mogą być zagnieżdżone: pole profile typu Profile będzie zawierać w sobie dane użytkownika. Obsługa zagnieżdżania pozwala opisywać złożone hierarchiczne struktury bez powielania definicji.

protobuf
syntax = "proto3";

package mobileapp;

message Order {
  string order_id = 1;
  repeated OrderItem items = 2;
  double total_price = 3;
  PaymentInfo payment = 4;
}

message OrderItem {
  string product_id = 1;
  string title = 2;
  int32 quantity = 3;
  double price = 4;
}

message PaymentInfo {
  string method = 1;
  string transaction_id = 2;
  double amount = 3;
}

Generowanie kodu z .proto

Kompilator protoc przekształca pliki .proto w kod źródłowy w docelowym języku. Dla Kotlin/Java używany jest parametr --java_out, dla Swift --swift_out (poprzez wtyczkę Apple Swift Protobuf), dla Dart --dart_out. Wygenerowane klasy zawierają metody builder do konstruowania wiadomości oraz metody serializacji/deserializacji.

W Androidzie do pracy z Protobuf używana jest wtyczka com.google.protobuf w wersji 0.9+ w Gradle. Po dodaniu wtyczki i wskazaniu plików .proto, kompilacja automatycznie generuje klasy Kotlin gotowe do użycia w aplikacji.

kotlin
import com.google.protobuf.kotlin.toByteString
import com.example.mobileapp.UserOuterClass.User

fun createUser(): User {
    return User.newBuilder()
        .setUserId("usr_001")
        .setName("IT Sectr")
        .setEmail("team@itsectr.com")
        .setAge(5)
        .setRole(UserOuterClass.UserRole.USER_ROLE_ADMIN)
        .addTags("mobile")
        .addTags("backend")
        .build()
}

fun serializeAndDeserialize(user: User): User {
    // Serializacja do formatu binarnego
    val bytes = user.toByteArray()

    // Deserializacja z formatu binarnego
    return User.parseFrom(bytes)
}

Przykłady użycia Protobuf

Protobuf jest szczególnie efektywny w architekturze mikroserwisowej i aplikacjach mobilnych. Rozważmy typowy scenariusz: aplikacja mobilna pobiera listę produktów z serwera przez gRPC. Wiadomość Protobuf zawiera informacje o produkcie, w tym identyfikator, nazwę, cenę i kategorię. Format binarny zmniejsza rozmiar odpowiedzi 5-8 razy w porównaniu z JSON.

Serwis gRPC w Kotlin

Przykład serwisu gRPC z Protobuf po stronie serwerowej. Serwis deklaruje metodę RPC GetProducts, która przyjmuje zapytanie z parametrami paginacji i zwraca listę produktów. Implementacja w Kotlinie używa wygenerowanych klas do pracy z zapytaniami i odpowiedziami.

kotlin
import com.example.mobileapp.ProductServiceGrpcKt
import com.example.mobileapp.ProductOuterClass.Product
import com.example.mobileapp.ProductOuterClass.GetProductsRequest
import com.example.mobileapp.ProductOuterClass.GetProductsResponse

class ProductService : ProductServiceGrpcKt.ProductServiceCoroutineImplBase() {

    override suspend fun getProducts(
        request: GetProductsRequest
    ): GetProductsResponse {
        val products = fetchProductsFromDb(
            page = request.page,
            limit = request.limit
        )

        return GetProductsResponse.newBuilder()
            .addAllProducts(products)
            .setTotalCount(products.size)
            .build()
    }
}

Konfiguracja Protobuf w projekcie Android

Konfiguracja Protobuf w projekcie Android odbywa się poprzez wtyczkę Gradle com.google.protobuf. Wtyczka automatycznie uruchamia kompilator protoc podczas kompilacji i generuje klasy Kotlin z plików .proto. Do pracy wymagane jest dodanie wtyczki w build.gradle poziomu projektu i zastosowanie jej w module aplikacji.

Po skonfigurowaniu Gradle, pliki .proto umieszczane są w katalogu src/main/proto. Kompilator protoc przetwarza je przy każdej kompilacji, generując klasy Kotlin, które można użyć w kodzie aplikacji. Ważne jest prawidłowe określenie wersji protobuf i protoc, aby uniknąć konfliktów zależności z innymi bibliotekami projektu.

W przypadku projektów iOS Protobuf jest podłączany przez CocoaPods lub Swift Package Manager. Wtyczka Swift Protobuf automatycznie generuje struktury Swift zgodne z protokołem Codable. W projektach Dart dla Flutter używany jest pakiet protobuf, a kompilacja odbywa się przez dart run protoc_plugin.

Często zadawane pytania

Jaka jest różnica między Protobuf a JSON?

Protobuf — binarny format z obowiązkowym schematem, 3-10 razy bardziej kompaktowy niż JSON. JSON — tekstowy, czytelny dla człowieka, nie wymaga schematu. Protobuf szybciej się serializuje i deserializuje, ale wymaga kompilacji plików .proto. JSON jest łatwiejszy w debugowaniu i nie wymaga wstępnej konfiguracji.

Jak zainstalować kompilator protoc?

Pobierz protoc z wydania GitHub protobuf dla swojej platformy. Dla macOS zainstaluj przez brew install protobuf. Dla Windows pobierz archiwum zip i dodaj protoc.exe do PATH. Dla Android/Kotlin użyj wtyczki Gradle com.google.protobuf, która automatycznie uruchamia kompilację podczas budowania.

Czym jest gRPC i jak jest powiązany z Protobuf?

gRPC — to wysokowydajny framework RPC od Google, używający Protobuf jako języka interfejsu (IDL) i formatu serializacji. gRPC definiuje serwisy i metody RPC w plikach .proto, generuje kod kliencki i serwerowy, obsługuje strumieniowanie i protokoły binarne.

Jakie języki obsługuje Protobuf?

Google oficjalnie obsługuje: C++, Java, Kotlin, Python, Go, Ruby, C#, PHP, JavaScript, Objective-C, Swift i Dart. Społeczność opracowała wsparcie dla Rust, TypeScript, Scala, Lua i innych języków. Do programowania mobilnego dostępne są Kotlin/Java (Android) i Swift/Objective-C (iOS).

Jak zapewnić wsteczną kompatybilność schematów?

Protobuf obsługuje wsteczną kompatybilność poprzez zasady: nie zmieniaj numerów pól, nie usuwaj pól (użyj reserved), dodawaj nowe pola z nowymi numerami. Starzy klienci ignorują nieznane pola, nowi klienci otrzymują wartości domyślne dla brakujących starych pól.

Podsumowanie

  • Protocol Buffers — binarny format serializacji od Google z obowiązkowym schematem danych
  • Rozmiar wiadomości 3-10 razy mniejszy niż JSON dzięki kodowaniu Varint
  • Szybkość serializacji i deserializacji wyższa niż formatów tekstowych
  • Schematy .proto zapewniają ścisłe typowanie i generowanie kodu dla 12+ języków
  • Wsteczna kompatybilność pozwala ewoluować API bez psucia klientów
  • gRPC używa Protobuf jako standardowego formatu do komunikacji mikroserwisowej
  • Idealny dla systemów o wysokim obciążeniu i aplikacji mobilnych z ograniczonym ruchem

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również