Binäres JSON: Auswahl zwischen MessagePack, CBOR und BSON
Fazit: MessagePack, CBOR und BSON komprimieren JSON alle zu Bytes. Vergleichen Sie Byte-Kosten, den Umgang mit int64 und Binärdaten und erhalten Sie eine klare Linie, wann ein Wechsel sich lohnt.

Kurz gesagt: Behalten Sie Text-JSON für den externen Austausch und für Daten, die Menschen prüfen müssen, und wechseln Sie auf internen Strecken nur dann zu MessagePack oder CBOR, wenn Binär-Payloads, Ganzzahlen oberhalb von 2^53 oder exakte Dezimalzahlen die komprimierte Größe oder die Typausdruckskraft zu einem echten Problem machen; BSON gehört ins MongoDB-Ökosystem.
Text-JSON spart Whitespace; binäre Formate sparen die Satzzeichen und die Textform von Zahlen. Feldnamen erscheinen trotzdem einmal pro Datensatz, ermitteln Sie die echte Ersparnis also vor dem Wechsel.
1. Was binäres JSON tatsächlich spart
Erwartungen zuerst zurechtrücken. Keines dieser Formate ist „eine andere JSON-Syntax“. Sie kodieren dasselbe Datenmodell in Bytes: Objekte, Arrays, Strings, Zahlen, Booleans und null. Was sie entfernen, ist konkret:
- Strukturzeichen wie Anführungszeichen, Doppelpunkte, Kommas und Klammern;
- Die dezimale Textform von Zahlen,
32wird also zu einem einzigen Byte; - Das erneute Scannen nach Stringgrenzen, ersetzt durch ein Präfix fester Länge;
- Die Base64-Kodierung für Binär-Payloads, die direkt als Bytes gespeichert werden können.
Was sie nicht entfernen können, ist ebenso konkret: Feldnamen erscheinen weiterhin als Strings in jedem Datensatz. Eine MessagePack-Map, eine CBOR-Map und ein BSON-Dokument wiederholen den Schlüssel für jeden Eintrag. Besteht Ihr JSON also aus zehntausend Datensätzen derselben Form, ist der komprimierte Größenunterschied zwischen Text und Binär weit kleiner als die Intuition vermutet, weil gzip am besten wiederholte Feldnamen beseitigt.
2. Woher die drei Formate kommen
| Format | Spezifikation und Jahr | Herkunft | Typische Verwendung |
|---|---|---|---|
| MessagePack | msgpack.org-Spezifikation, seit 2008 | Unabhängiges Design mit Fokus auf Minimalismus | Cache-Werte, IPC, Log-Pipelines |
| CBOR | RFC 8949 (STD 94), 2020 | Von MessagePack beeinflusst, vom IETF standardisiert | COSE, WebAuthn, CWT, eingeschränkte Geräte |
| BSON | bsonspec.org, MongoDB-Ökosystem | Für Datenbankdokumente entworfen | MongoDB-Speicherung und Wire-Protokoll |
CBOR ist am stärksten standardisiert: ein bei der IANA registrierter Medientyp application/cbor, deterministische Kodierungsregeln und CDDL zur Beschreibung. MessagePack ist das leichteste, mit einer Spezifikation, die auf eine Seite passt. BSON ist das schwerste: Es backt ObjectId, Decimal128, Daten und Binärsubtypen in sein Typsystem ein, weshalb es nur im MongoDB-Ökosystem wirklich populär ist.
3. Dieselben Daten, vier Kodierungen
Nehmen Sie {"name":"joe"} als Beispiel. Die Byte-Kosten lassen sich leicht vergleichen:
| Kodierung | Bytes | Bytefolge |
|---|---|---|
| JSON-Text | 14 | 7b 22 6e 61 6d 65 22 3a 22 6a 6f 65 22 7d |
| MessagePack | 9 | 81 a3 6e 61 6d 65 a3 6a 6f 65 |
| CBOR | 10 | a1 64 6e 61 6d 65 63 6a 6f 65 |
| BSON | 19 | 4-Byte-Gesamtlänge + Typbyte + name\0 + 4-Byte-Wertlänge + joe\0 + Terminator |
Zerlegen Sie die neun MessagePack-Bytes:
81: Das hohe Nibble1000bedeutet Map, das niedrige Nibble0001bedeutet ein Schlüssel-Wert-Paar;a3: Die hohen drei Bits101bedeuten einen String fester Länge 3;6e 61 6d 65: ASCII fürname;a3: ein weiterer String der Länge 3;6a 6f 65:joe.
CBORs a1 ist Major Type 5 (Map) mit Länge 1, und 64 ist Major Type 3 (Text-String) mit Länge 4, die Semantik ist also fast isomorph zu MessagePack. BSON ist größer: Jedes Dokument trägt eine 4-Byte-Gesamtlänge, jedes Feld wiederholt ein Typbyte und seinen Namen, und jeder String wiederholt eine Länge plus ein abschließendes \0. Bei kleinen Dokumenten kann BSON leicht größer als JSON-Text sein.
Sie können die Präfixe direkt prüfen, indem Sie diese Bytes als Hex darstellen:
const messagePackBytes = [0x81, 0xa3, 0x6e, 0x61, 0x6d, 0x65, 0xa3, 0x6a, 0x6f, 0x65];
const hexText = messagePackBytes.map((byte) => byte.toString(16)).join(' ');
console.log(hexText); // 81 a3 6e 61 6d 65 a3 6a 6f 65
3.1 Größe und Parse-Geschwindigkeit: Marketingzahlen ignorieren
Behauptungen, Binär sei „10x schneller“, sollte man in zwei Fragen zerlegen.
Größe. Unkomprimiert ist Binär kleiner, weil Satzzeichen und Whitespace fehlen. Reale Pipelines komprimieren aber fast immer: Nach gzip oder brotli sind wiederholte Feldnamen weggeschrumpft, und der Binärvorteil schwindet dramatisch. Folgen Sie der Methode in JSON-Minifizierung versus gzip: Zuerst komprimierte Bytes messen, dann entscheiden, ob ein Formatwechsel sich lohnt.
Parse-Geschwindigkeit. Binär überspringt das Lexing (das Scannen von Anführungszeichen, Kommas und Zahlenzeichen), müsste also theoretisch schneller sein. In JavaScript ist der dominante Kostenfaktor jedoch das Allokieren von Objekten und Speicher, was kein Decoder vermeiden kann. Datenform, Feldanzahl und Implementierungsqualität zählen alle, die einzige verlässliche Schlussfolgerung kommt also aus Benchmarks mit Ihren eigenen Payloads statt aus dem Multiplikator eines Anbieters. Ist ein einzelner Payload zu groß, um ihn auf einmal in den Speicher zu lesen, schneiden Sie ihn mit dem in große JSON-Dateien parsen und streamen beschriebenen Ansatz zu, bevor Sie den Kodierungsgewinn messen.
4. int64 und Binärfelder: der echte Grund zu wechseln
Die Größe ist oft nicht der Grund für einen Formatwechsel. Die Typausdruckskraft ist es.
4.1 Ganzzahlen jenseits von 2^53
JSON-Zahlen landen in JavaScript in einem double, 9007199254740993 wird also zu 9007199254740992. Die drei binären Formate gehen damit unterschiedlich um:
| Format | 64-Bit-Ganzzahlen | Unsigned 64-Bit | Beliebige Präzision |
|---|---|---|---|
| MessagePack | ✓ int64 (0xd3), in BigInt dekodierbar |
✓ uint64 (0xcf) |
✗ (braucht einen Extension-Typ) |
| CBOR | ✓ 64-Bit-Formen von Major Type 0/1 | ✓ Derselbe Kodierungsraum | ✓ Bignum-Tags 2/3 |
| BSON | ✓ int64 (0x12) |
✗ Nur signed | ✗ (Decimal128 ist Festkomma, keine beliebige Ganzzahl) |
CBOR ist das einzige mit einer Standarddarstellung für Ganzzahlen beliebiger Präzision: Werte jenseits von 64 Bit werden in Tag 2 (nicht negativ) oder Tag 3 (negativ) um einen Byte-String gewickelt. MessagePack und BSON fallen auf Strings oder eigenwillige Extension-Konventionen zurück.
4.2 Binär-Payloads
JSON hat genau einen Weg, Binärdaten auszudrücken: Base64, was den Payload um etwa ein Drittel aufbläht und eine zusätzliche Dekodierkopie erfordert. MessagePack hat bin-Typen (0xc4–0xc6), CBOR hat Byte-Strings (Major Type 2), und BSON hat Binärsubtypen. Wenn Sie Bilder, Hashes, Vektoren oder komprimierte Blöcke transportieren, zählt dieser Unterschied weit mehr als ein paar gesparte Satzzeichenbytes.
5. Seitenweiser Vergleich
| Dimension | MessagePack | CBOR | BSON |
|---|---|---|---|
| Spezifikation | Community-Spezifikation | IETF RFC 8949 | MongoDB-Ökosystem |
| Medientyp | application/msgpack (nicht IANA-standard) |
application/cbor (bei der IANA registriert) |
Kein allgemeiner Medientyp |
| Typsystem | Sechs JSON-Typen plus bin und ext | Sechs JSON-Typen plus bin, Tags und einfache Werte | Breiter: ObjectId, Decimal128, Daten, Regex, Timestamps |
| Erweiterungsmechanismus | Extension-Typen (etwa Timestamp -1) | Tags (Daten, Bignums, eingebettetes CBOR) | Feste Typcodes, Erweiterungen per Ökosystem-Konvention |
| Deterministische Kodierung | Keine Standardanforderung | Ausdrückliche Regeln, für Signaturen nutzbar | Keine |
| Selbstbeschreibend | Ja, aber kein Schema auf Feldebene | Ja, mit CDDL beschreibbar | Ja, mit pro Dokument wiederholten Feldnamen |
| Overhead bei kleinen Dokumenten | Niedrig | Niedrig | Hoch (Längenpräfix, Feldnamen, Terminator) |
| Ökosystem | Caches, Logs, etwas RPC | COSE, WebAuthn, IoT | Nur MongoDB |
6. Browser- und Node-Unterstützung
Node 24 bringt keinen dieser Codecs mit, Sie installieren also eine Bibliothek. Übliche Wahl:
| Laufzeit | MessagePack | CBOR | BSON |
|---|---|---|---|
| Node.js | @msgpack/msgpack, msgpackr |
cbor-x, borc |
bson |
| Browser | @msgpack/msgpack |
Browser-Build von cbor-x, cbor-web |
bson |
Beide Familien arbeiten auf Uint8Array und benötigen kein Buffer. Achten Sie auf Versionsunterschiede:
import { encode, decode } from '@msgpack/msgpack';
/**
* Encodes an object to MessagePack bytes and decodes it immediately for verification.
* @param payload Plain object to encode
* @returns The decoded value and the encoded byte length
*/
function roundTrip(payload: Record<string, unknown>): { decoded: unknown; byteLength: number } {
const bytes = encode(payload);
return { decoded: decode(bytes), byteLength: bytes.byteLength };
}
Die meisten Bibliotheken dekodieren große Ganzzahlen standardmäßig zu number und verlieren jenseits des sicheren Bereichs Präzision. Zählen exakte Werte, aktivieren Sie ausdrücklich die BigInt-Option (useBigInt64 in @msgpack/msgpack, einen entsprechenden Schalter in cbor-x), sonst haben Sie JSONs altes Problem nur in ein neues Format verschoben.
7. Debugbarkeit und Protokollkompatibilität
7.1 Debugbarkeit: die größten versteckten Kosten
Der größte Vorteil von Text-JSON ist nicht die Größe; er ist, dass Sie es jederzeit öffnen können. Nach dem Wechsel auf Binär:
grep,awkundjqfunktionieren alle nicht mehr, und Log-Pipelines brauchen einen zusätzlichen Dekodierschritt;- Debugging in der Produktion erfordert den richtigen Decoder in der richtigen Version, sonst sind die Feldnamen, die Sie sehen, falsch;
- Abgefangener Traffic erscheint in Browser-Entwicklerwerkzeugen als unlesbarer Byteblock;
- Code-Review-Diffs zeigen eine Hexadezimalzeichenkette.
CBOR hat eine diagnostische Notation, die Bytes wieder in lesbaren, JSON-nahen Text rendert, etwa eine Map als {1: 2}; MessagePack hat ebenfalls einige Kommandozeilen-Decoder. Aber alle erfordern eine zusätzliche Installation und liegen außerhalb des Standardbetriebswegs.
Die Schlussfolgerung: Wann immer Menschen die Daten häufig prüfen müssen, übersteigen die versteckten Kosten eines binären Formats die Bandbreite, die es spart.
7.2 Protokollkompatibilität und Erweiterungen
- CBOR hat den vollständigsten Tag-Mechanismus: Tag 0 für einen Datum-Zeit-String, Tag 1 für einen Unix-Timestamp, Tags 2 und 3 für Bignums und Tag 24 für eingebettetes CBOR. Zusammen mit deterministischer Kodierung wird es von Protokollen genutzt, die Signaturen und Einheitlichkeit über Implementierungen hinweg brauchen, etwa COSE, WebAuthn und CWT.
- MessagePack überlässt Extension-Typen den Implementierern. In der Praxis ist der einzige verbreitete Timestamp (Extension-Typ -1). Über Teams hinweg muss jeder Extension-Typ ins Protokolldokument geschrieben werden, sonst kann die andere Seite ihn nicht dekodieren.
- BSON hat feste Typcodes, und
ObjectId,Decimal128,MinKeyundMaxKeysind MongoDB-spezifische Semantik. BSON als allgemeines Austauschformat zu behandeln bringt einen Haufen ungenutzter Typen und Längenpräfixe mit.
Verlangt ein Protokoll „dieselben Daten müssen dieselben Bytes erzeugen“, bietet nur CBOR eine Standardantwort; MessagePack und BSON brauchen beide zusätzliche Einigung über Feldreihenfolge und Kodierungsdetails.
8. Wann sich ein Wechsel lohnt
Signale, die einen Wechsel rechtfertigen:
- Payloads sind groß, beide Enden lassen sich ändern, und die komprimierten Größen unterscheiden sich noch deutlich;
- Sie transportieren Binärinhalte, und die Base64-Aufblähung und der Dekodieraufwand sind messbar;
- Sie brauchen 64-Bit-Ganzzahlen oder exakte Dezimalzahlen, die JSON-Doubles nicht darstellen können;
- Die Strecke ist Server-zu-Server, und diagnostische Werkzeuge lassen sich standardisieren.
Signale, die dagegen sprechen:
- gzip oder brotli ist bereits vorhanden, und der Gewinn liegt im einstelligen Prozentbereich;
- Die API ist öffentlich, und Dritte haben nur universelle HTTP-Clients;
- Die Daten sind Logs oder Konfiguration, die Menschen von Hand lesen;
- Das Team hat kein Budget, Decoder und Versionskompatibilität zu pflegen.
Ein Mittelweg funktioniert auch: JSON nach außen behalten und MessagePack für interne Caches verwenden. Cache-Werte werden nur von Ihren eigenen Diensten gelesen, Größe und Parse-Kosten verbessern sich also, und das Leeren des Caches löst jedes Problem, ohne den Vertrag anzutasten.
9. Checkliste
- [ ] Komprimierte Byte-Zahlen aus echten Daten vergleichen, nicht unkomprimierte;
- [ ] Die Richtlinie für große Ganzzahlen entscheiden: BigInt-Option, String-Transport oder CBOR-Bignums;
- [ ] Binärfelder als bin oder Byte-Strings senden, statt sie in Base64 zu wickeln;
- [ ] Extension-Typen und Tags ins Protokolldokument schreiben und Decoder-Versionen festnageln;
- [ ] Einen Text-JSON-Debugpfad behalten, der bei Produktionsvorfällen aktiviert werden kann;
- [ ] Einen Benchmark ausführen und reproduzierbare Zahlen statt verbaler Behauptungen festhalten.
Was ist der Unterschied zwischen MessagePack und CBOR?
Ihre Kodierungen sind sehr ähnlich: Maps, Arrays und Strings verwenden alle ein kompaktes Typ-plus-Längen-Präfix. Der Hauptunterschied ist die Standardisierung. CBOR ist ein IETF-RFC mit IANA-Medientyp, Tag-Mechanismus und deterministischen Kodierungsregeln; MessagePack ist eine Community-Spezifikation, deren Extension-Typen auf privaten Absprachen beruhen. Wählen Sie CBOR, wenn Sie Signaturen, Einheitlichkeit über Implementierungen hinweg oder Protokolle für eingeschränkte Geräte brauchen.
Kann BSON JSON als allgemeines Format ersetzen?
Es ist nicht empfehlenswert. BSON wurde für Datenbankdokumente entworfen: Jedes Dokument trägt eine 4-Byte-Gesamtlänge, jedes Feld wiederholt Typ und Namen, und kleine Dokumente werden größer als JSON-Text. Es enthält außerdem MongoDB-spezifische Typen wie ObjectId und MinKey. Außerhalb von MongoDB bleibt der größte Teil seines Typsystems ungenutzt, während die Größennachteile bestehen bleiben.
Wie viel kleiner macht ein binäres Format meinen Payload?
Das hängt von der Datenform ab. Wiederholen sich Feldnamen stark, liegen komprimiertes Text-JSON und binäre Formate nahe beieinander; sind die Namen kurz und die Daten voller Strukturzeichen und Zahlen, ist der Binärvorteil klarer. Messen Sie echte Beispiele unkomprimiert und nach gzip und entscheiden Sie dann, statt mit einem generischen Multiplikator zu schätzen.
Kann ich binäre Daten noch mit jq debuggen?
Nein. jq verarbeitet nur Text-JSON und scheitert sofort an MessagePack- oder CBOR-Bytes. Sie müssen mit der passenden Bibliothek zuerst zu JSON dekodieren und es dann an jq geben; CBOR kann auch durch ein Werkzeug für diagnostische Notation in lesbaren Text verwandelt werden. Einen Text-Debugpfad zu behalten ist billiger, als Werkzeuge auf Abruf zu installieren.