Übersicht

Protocol Buffers sind ein sprach- und plattformneutraler, erweiterbarer Mechanismus zur Serialisierung strukturierter Daten.

Es ist wie JSON, nur kleiner und schneller, und es generiert native Sprachbindungen. Sie definieren einmal, wie Ihre Daten strukturiert sein sollen, und können dann speziellen generierten Quellcode verwenden, um Ihre strukturierten Daten einfach in und aus einer Vielzahl von Datenströmen und mit einer Vielzahl von Sprachen zu schreiben und zu lesen.

Protocol Buffers sind eine Kombination aus der Definitionsprache (erstellt in .proto-Dateien), dem Code, den der Proto-Compiler generiert, um mit Daten zu interagieren, sprachspezifischen Laufzeitbibliotheken, dem Serialisierungsformat für Daten, die in eine Datei geschrieben (oder über eine Netzwerkverbindung gesendet) werden, und den serialisierten Daten.

Welche Probleme lösen Protocol Buffers?

Protocol Buffers bieten ein Serialisierungsformat für Pakete mit typisierten, strukturierten Daten, die bis zu einige Megabyte groß sind. Das Format eignet sich sowohl für flüchtigen Netzwerkverkehr als auch für die langfristige Datenspeicherung. Protocol Buffers können mit neuen Informationen erweitert werden, ohne bestehende Daten ungültig zu machen oder eine Codeaktualisierung zu erfordern.

Protocol Buffers sind das am häufigsten verwendete Datenformat bei Google. Sie werden häufig für die Kommunikation zwischen Servern sowie für die Archivierung von Daten auf Festplatten verwendet. Protokollpuffer-Nachrichten und Dienste werden durch von Ingenieuren erstellte .proto-Dateien beschrieben. Das Folgende zeigt ein Beispiel für eine message.

edition = "2023";

message Person {
  string name = 1;
  int32 id = 2;
  string email = 3;
}

Der Proto-Compiler wird zur Build-Zeit auf .proto-Dateien aufgerufen, um Code in verschiedenen Programmiersprachen (behandelt in Sprachenübergreifende Kompatibilität später in diesem Thema) zu generieren, um die entsprechenden Protokollpuffer zu manipulieren. Jede generierte Klasse enthält einfache Accessoren für jedes Feld und Methoden zum Serialisieren und Parsen der gesamten Struktur zu und von Rohbytes. Das Folgende zeigt Ihnen ein Beispiel, das diese generierten Methoden verwendet.

Person john = Person.newBuilder()
    .setId(1234)
    .setName("John Doe")
    .setEmail("jdoe@example.com")
    .build();
output = new FileOutputStream(args[0]);
john.writeTo(output);

Da Protocol Buffers in einer Vielzahl von Diensten bei Google intensiv genutzt werden und die Daten darin einige Zeit bestehen bleiben können, ist die Aufrechterhaltung der Abwärtskompatibilität entscheidend. Protocol Buffers ermöglichen die nahtlose Unterstützung von Änderungen, einschließlich des Hinzufügens neuer Felder und des Löschens bestehender Felder, für jeden Protokollpuffer, ohne bestehende Dienste zu beeinträchtigen. Weitere Informationen zu diesem Thema finden Sie unter Proto-Definitionen aktualisieren, ohne Code aktualisieren zu müssen, später in diesem Thema.

Welche Vorteile bietet die Verwendung von Protocol Buffers?

Protocol Buffers sind ideal für jede Situation, in der Sie strukturierte, aufzeichnungenartige, typisierte Daten auf sprach-, plattform- und erweiterbare Weise serialisieren müssen. Sie werden am häufigsten für die Definition von Kommunikationsprotokollen (zusammen mit gRPC) und für die Datenspeicherung verwendet.

Einige der Vorteile der Verwendung von Protocol Buffers sind:

  • Kompakte Datenspeicherung
  • Schnelles Parsen
  • Verfügbarkeit in vielen Programmiersprachen
  • Optimierte Funktionalität durch automatisch generierte Klassen

Sprachenübergreifende Kompatibilität

Dieselben Nachrichten können von Code gelesen werden, der in jeder unterstützten Programmiersprache geschrieben ist. Sie können ein Java-Programm auf einer Plattform haben, das Daten aus einem Softwaresystem erfasst, sie basierend auf einer .proto-Definition serialisiert und dann bestimmte Werte aus diesen serialisierten Daten in einer separaten Python-Anwendung auf einer anderen Plattform extrahiert.

Die folgenden Sprachen werden direkt vom Protocol Buffers-Compiler, protoc, unterstützt:

Die folgenden Sprachen werden von Google unterstützt, aber der Quellcode der Projekte befindet sich in GitHub-Repositorys. Der protoc-Compiler verwendet Plugins für diese Sprachen.

Zusätzliche Sprachen werden nicht direkt von Google, sondern von anderen GitHub-Projekten unterstützt. Diese Sprachen werden in Add-ons von Drittanbietern für Protocol Buffers behandelt.

Projektübergreifende Unterstützung

Sie können Protocol Buffers projektübergreifend verwenden, indem Sie message-Typen in .proto-Dateien definieren, die außerhalb der Codebasis eines bestimmten Projekts liegen. Wenn Sie message-Typen oder Enums definieren, von denen Sie erwarten, dass sie außerhalb Ihres direkten Teams weit verbreitet sein werden, können Sie sie in ihre eigene Datei ohne Abhängigkeiten legen.

Ein paar Beispiele für Proto-Definitionen, die bei Google weit verbreitet sind, sind timestamp.proto und status.proto.

Proto-Definitionen aktualisieren, ohne Code aktualisieren zu müssen

Es ist Standard, dass Softwareprodukte abwärtskompatibel sind, aber es ist weniger üblich, dass sie vorwärtskompatibel sind. Solange Sie einige einfache Praktiken beim Aktualisieren von .proto-Definitionen befolgen, liest alter Code neue Nachrichten ohne Probleme und ignoriert neu hinzugefügte Felder. Für alten Code haben gelöschte Felder ihren Standardwert und gelöschte wiederholte Felder sind leer. Informationen dazu, was "wiederholte" Felder sind, finden Sie unter Protokollpuffer-Definitions-Syntax später in diesem Thema.

Neuer Code liest alte Nachrichten ebenfalls transparent. Neue Felder sind in alten Nachrichten nicht vorhanden; in diesen Fällen bieten Protocol Buffers einen angemessenen Standardwert.

Wann sind Protocol Buffers nicht geeignet?

Protocol Buffers passen nicht zu allen Daten. Insbesondere:

  • Protocol Buffers gehen davon aus, dass ganze Nachrichten in den Speicher geladen werden können und nicht größer als ein Objektgraph sind. Für Daten, die einige Megabyte überschreiten, sollten Sie eine andere Lösung in Betracht ziehen. Wenn Sie mit größeren Daten arbeiten, haben Sie aufgrund von serialisierten Kopien möglicherweise mehrere Kopien der Daten, was zu überraschenden Spitzen des Speicherverbrauchs führen kann.
  • Wenn Protocol Buffers serialisiert werden, kann dieselbe Dateneinheit viele verschiedene binäre Serialisierungen aufweisen. Sie können zwei Nachrichten nicht auf Gleichheit vergleichen, ohne sie vollständig zu parsen.
  • Nachrichten sind nicht komprimiert. Obwohl Nachrichten wie jede andere Datei gezippt oder gzippt werden können, erzielen spezialisierte Kompressionsalgorithmen wie die von JPEG und PNG verwendeten bei Daten des entsprechenden Typs wesentlich kleinere Dateien.
  • Protokollpuffer-Nachrichten sind weder in Bezug auf Größe noch Geschwindigkeit maximal effizient für viele wissenschaftliche und technische Anwendungen, die große, mehrdimensionale Arrays von Gleitkommazahlen umfassen. Für diese Anwendungen haben FITS und ähnliche Formate weniger Overhead.
  • Protocol Buffers sind in nicht-objektorientierten Sprachen, die in der wissenschaftlichen Datenverarbeitung beliebt sind, wie Fortran und IDL, nicht gut unterstützt.
  • Protokollpuffer-Nachrichten beschreiben ihre Daten nicht von sich aus, aber sie verfügen über ein vollständig reflektierbares Schema, mit dem Sie die Selbstdarstellung implementieren können. Das heißt, Sie können eine Nachricht ohne Zugriff auf die entsprechende .proto-Datei nicht vollständig interpretieren.
  • Protocol Buffers sind kein formeller Standard irgendeiner Organisation. Dies macht sie für die Verwendung in Umgebungen mit rechtlichen oder anderen Anforderungen ungeeignet, die auf Standards aufbauen.

Wer verwendet Protocol Buffers?

Viele Projekte verwenden Protocol Buffers, darunter die folgenden:

Wie funktionieren Protocol Buffers?

Das folgende Diagramm zeigt, wie Sie Protocol Buffers verwenden, um mit Ihren Daten zu arbeiten.

Compilation workflow showing the creation of a proto file, generated code, and compiled classes
Abbildung 1. Protocol Buffers Workflow

Der von Protocol Buffers generierte Code bietet Hilfsmethoden zum Abrufen von Daten aus Dateien und Streams, zum Extrahieren einzelner Werte aus den Daten, zum Prüfen, ob Daten vorhanden sind, zum Zurückserialisieren von Daten in eine Datei oder einen Stream und andere nützliche Funktionen.

Die folgenden Codebeispiele zeigen Ihnen ein Beispiel für diesen Ablauf in Java. Wie bereits gezeigt, ist dies eine .proto-Definition.

message Person {
  string name = 1;
  int32 id = 2;
  string email = 3;
}

Das Kompilieren dieser .proto-Datei erstellt eine Builder-Klasse, die Sie zum Erstellen neuer Instanzen verwenden können, wie im folgenden Java-Code:

Person john = Person.newBuilder()
    .setId(1234)
    .setName("John Doe")
    .setEmail("jdoe@example.com")
    .build();
output = new FileOutputStream(args[0]);
john.writeTo(output);

Sie können dann Daten mit den von Protocol Buffers in anderen Sprachen erstellten Methoden deserialisieren, z. B. in C++.

Person john;
fstream input(argv[1], ios::in | ios::binary);
john.ParseFromIstream(&input);
int id = john.id();
std::string name = john.name();
std::string email = john.email();

Protokollpuffer-Definitions-Syntax

Beim Definieren von .proto-Dateien können Sie die Kardinalität (einzeln oder wiederholt) angeben. In proto2 und proto3 können Sie auch angeben, ob das Feld optional ist. In proto3 ändert das Setzen eines Feldes auf optional es von impliziter Präsenz zu expliziter Präsenz.

Nachdem Sie die Kardinalität eines Feldes festgelegt haben, geben Sie den Datentyp an. Protocol Buffers unterstützen die üblichen primitiven Datentypen wie Ganzzahlen, Booleans und Gleitkommazahlen. Die vollständige Liste finden Sie unter Skalare Werttypen.

Ein Feld kann auch von einem

  • Ein message-Typ, sodass Sie Teile der Definition verschachteln können, z. B. für wiederholte Datensätze.
  • Ein enum-Typ, sodass Sie eine Auswahl von Werten angeben können.
  • Ein oneof-Typ, den Sie verwenden können, wenn eine Nachricht viele optionale Felder hat und höchstens ein Feld gleichzeitig gesetzt ist.
  • Ein map-Typ, um Schlüssel-Wert-Paare zu Ihrer Definition hinzuzufügen.

Nachrichten können **Erweiterungen** zulassen, um Felder außerhalb der Nachricht selbst zu definieren. Beispielsweise ermöglicht das interne Nachrichtenschema der protobuf-Bibliothek Erweiterungen für benutzerdefinierte, verwendungsspezifische Optionen.

Weitere Informationen zu den verfügbaren Optionen finden Sie im Sprachleitfaden für proto2, proto3 oder Edition 2023.

Nachdem Sie Kardinalität und Datentyp festgelegt haben, wählen Sie einen Namen für das Feld. Beim Festlegen von Feldnamen sind einige Dinge zu beachten:

  • Es kann manchmal schwierig oder sogar unmöglich sein, Feldnamen zu ändern, nachdem sie in der Produktion verwendet wurden.
  • Feldnamen dürfen keine Bindestriche enthalten. Weitere Informationen zur Feldnamensyntax finden Sie unter Nachrichten- und Feldnamen.
  • Verwenden Sie pluralisierte Namen für wiederholte Felder.

Nachdem Sie einem Feld einen Namen zugewiesen haben, weisen Sie eine Feldnummer zu. Feldnummern dürfen nicht wiederverwendet oder umfunktioniert werden. Wenn Sie ein Feld löschen, sollten Sie seine Feldnummer reservieren, um zu verhindern, dass jemand die Nummer versehentlich wiederverwendet.

Zusätzliche Datentyp-Unterstützung

Protocol Buffers unterstützt viele skalare Werttypen, einschließlich Ganzzahlen, die sowohl variable Längenkodierung als auch feste Größen verwenden. Sie können auch Ihre eigenen zusammengesetzten Datentypen erstellen, indem Sie Nachrichten definieren, die selbst Datentypen sind, die Sie einem Feld zuweisen können. Zusätzlich zu den einfachen und zusammengesetzten Werttypen werden mehrere gängige Typen veröffentlicht.

Historie

Um über die Geschichte des Protocol Buffers-Projekts zu lesen, siehe Geschichte von Protocol Buffers.

Open-Source-Philosophie von Protocol Buffers

Protocol Buffers wurden 2008 als Open Source veröffentlicht, um Entwicklern außerhalb von Google die gleichen Vorteile zu bieten, die wir intern daraus ziehen. Wir unterstützen die Open-Source-Community durch regelmäßige Updates der Sprache, während wir diese Änderungen zur Unterstützung unserer internen Anforderungen vornehmen. Obwohl wir ausgewählte Pull-Anfragen von externen Entwicklern akzeptieren, können wir Feature-Anfragen und Fehlerbehebungen, die nicht den spezifischen Anforderungen von Google entsprechen, nicht immer priorisieren.

Entwickler-Community

Um über bevorstehende Änderungen an Protocol Buffers informiert zu werden und sich mit protobuf-Entwicklern und -Benutzern zu vernetzen, treten Sie der Google Group bei.

Zusätzliche Ressourcen