JSON Biner: Memilih Antara MessagePack, CBOR, dan BSON
Intinya: MessagePack, CBOR dan BSON semuanya mengompres JSON menjadi byte. Bandingkan biaya byte, penanganan int64 dan biner, serta dapatkan batas jelas kapan beralih itu layak.

Intinya: pertahankan JSON teks untuk pertukaran eksternal dan untuk data yang perlu diperiksa orang, dan beralih ke MessagePack atau CBOR pada tautan internal hanya ketika payload biner, bilangan bulat di atas 2^53, atau desimal eksak membuat ukuran terkompresi atau daya ekspresi tipe menjadi masalah nyata; BSON milik ekosistem MongoDB.
JSON teks menghemat spasi; format biner menghemat tanda baca dan bentuk tekstual angka. Nama field masih muncul sekali per record, jadi hitung dulu penghematan nyatanya sebelum beralih.
1. Apa yang sebenarnya dihemat JSON biner
Tetapkan ekspektasi terlebih dahulu. Tidak satu pun dari format ini adalah "sintaks JSON lain". Mereka mengodekan model data yang sama dalam byte: objek, array, string, angka, boolean, dan null. Yang mereka hilangkan konkret:
- Karakter struktural seperti tanda kutip, titik dua, koma, dan kurung kurawal;
- Bentuk teks desimal angka, sehingga
32menjadi satu byte; - Pemindaian ulang untuk batas string, digantikan oleh awalan panjang tetap;
- Encoding Base64 untuk payload biner, yang dapat disimpan langsung sebagai byte.
Yang tidak dapat mereka hilangkan juga sama konkretnya: nama field masih muncul sebagai string di setiap record. Map MessagePack, map CBOR, dan dokumen BSON semuanya mengulang kunci untuk setiap entri. Jadi ketika JSON Anda adalah sepuluh ribu record dengan bentuk sama, selisih ukuran terkompresi antara teks dan biner jauh lebih kecil daripada dugaan intuisi, karena gzip paling baik dalam menghilangkan nama field yang berulang.
2. Dari mana ketiga format ini berasal
| Format | Spesifikasi dan tahun | Asal | Penggunaan tipikal |
|---|---|---|---|
| MessagePack | Spesifikasi msgpack.org, sejak 2008 | Desain independen yang berfokus pada minimalisme | Nilai cache, IPC, pipeline log |
| CBOR | RFC 8949 (STD 94), 2020 | Dipengaruhi MessagePack, distandarkan oleh IETF | COSE, WebAuthn, CWT, perangkat terbatas |
| BSON | bsonspec.org, ekosistem MongoDB | Dirancang untuk dokumen basis data | Penyimpanan dan wire protocol MongoDB |
CBOR adalah yang paling terstandardisasi: media type application/cbor terdaftar IANA, aturan encoding deterministik, dan CDDL untuk deskripsi. MessagePack adalah yang teringan, dengan spesifikasi yang muat dalam satu halaman. BSON adalah yang terberat: ia memasukkan ObjectId, Decimal128, tanggal, dan subtipe biner ke dalam sistem tipenya, itulah sebabnya ia hanya benar-benar populer di dalam ekosistem MongoDB.
3. Data yang sama, empat encoding
Ambil {"name":"joe"} sebagai contoh. Biaya byte mudah dibandingkan:
| Encoding | Byte | Urutan byte |
|---|---|---|
| JSON teks | 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 | Panjang total 4 byte + byte tipe + name\0 + panjang nilai 4 byte + joe\0 + terminator |
Pisahkan sembilan byte MessagePack:
81: nibble atas1000berarti map, nibble bawah0001berarti satu pasangan kunci-nilai;a3: tiga bit atas101berarti string dengan panjang tetap 3;6e 61 6d 65: ASCII untukname;a3: string lain dengan panjang 3;6a 6f 65:joe.
a1 pada CBOR adalah major type 5 (map) dengan panjang 1, dan 64 adalah major type 3 (text string) dengan panjang 4, sehingga semantiknya hampir isomorfik dengan MessagePack. BSON lebih besar: setiap dokumen membawa panjang total 4 byte, setiap field mengulang byte tipe dan namanya, dan setiap string mengulang panjang plus \0 di akhir. Pada dokumen kecil, BSON dapat dengan mudah lebih besar daripada JSON teks.
Anda dapat memeriksa prefix secara langsung dengan merender byte tersebut sebagai hex:
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 Ukuran dan kecepatan parse: abaikan angka pemasaran
Klaim bahwa biner "10x lebih cepat" harus dipecah menjadi dua pertanyaan.
Ukuran. Tanpa kompresi, biner lebih kecil karena tanda baca dan spasi hilang. Tetapi pipeline nyata hampir selalu mengompresi: setelah gzip atau brotli, nama field yang berulang terkompresi habis, dan keunggulan biner menyusut drastis. Ikuti metode di Minifikasi JSON versus gzip: ukur byte terkompresi terlebih dahulu, lalu putuskan apakah perubahan format layak.
Kecepatan parse. Biner melewati leksing (memindai tanda kutip, koma, dan karakter angka), sehingga secara teori seharusnya lebih cepat. Namun di JavaScript, biaya dominan adalah mengalokasikan objek dan memori, yang tidak dapat dihindari dekoder mana pun. Bentuk data, jumlah field, dan kualitas implementasi semuanya berpengaruh, sehingga satu-satunya kesimpulan yang andal berasal dari benchmark payload Anda sendiri alih-alih mengutip pengali dari vendor. Jika satu payload terlalu besar untuk dibaca ke memori sekaligus, potong dengan pendekatan yang dijelaskan di parsing dan streaming JSON besar sebelum mengukur keuntungan encoding.
4. int64 dan field biner: alasan nyata untuk beralih
Ukuran sering bukan alasan untuk mengganti format. Daya ekspresi tipe adalah alasannya.
4.1 Bilangan bulat di atas 2^53
Angka JSON mendarat di double dalam JavaScript, sehingga 9007199254740993 menjadi 9007199254740992. Ketiga format biner menanganinya secara berbeda:
| Format | Bilangan bulat 64-bit | 64-bit tak bertanda | Presisi arbitrer |
|---|---|---|---|
| MessagePack | ✓ int64 (0xd3), dapat didekode ke BigInt |
✓ uint64 (0xcf) |
✗ (memerlukan tipe ekstensi) |
| CBOR | ✓ bentuk 64-bit major type 0/1 | ✓ Ruang encoding sama | ✓ tag bignum 2/3 |
| BSON | ✓ int64 (0x12) |
✗ Hanya bertanda | ✗ (Decimal128 adalah fixed-point, bukan bilangan bulat arbitrer) |
CBOR adalah satu-satunya yang memiliki representasi standar untuk bilangan bulat presisi arbitrer: nilai di atas 64 bit dibungkus dalam tag 2 (non-negatif) atau tag 3 (negatif) di sekitar byte string. MessagePack dan BSON beralih ke string atau konvensi ekstensi buatan sendiri.
4.2 Payload biner
JSON hanya memiliki satu cara untuk mengekspresikan biner: Base64, yang mengembungkan payload sekitar sepertiga dan membutuhkan salinan dekode tambahan. MessagePack memiliki tipe bin (0xc4–0xc6), CBOR memiliki byte string (major type 2), dan BSON memiliki subtipe biner. Ketika Anda mengangkut gambar, hash, vektor, atau blok terkompresi, perbedaan ini jauh lebih penting daripada menghemat beberapa byte tanda baca.
5. Perbandingan berdampingan
| Dimensi | MessagePack | CBOR | BSON |
|---|---|---|---|
| Spesifikasi | Spesifikasi komunitas | IETF RFC 8949 | Ekosistem MongoDB |
| Media type | application/msgpack (bukan standar IANA) |
application/cbor (terdaftar IANA) |
Tidak ada media type umum |
| Sistem tipe | Enam tipe JSON plus bin dan ext | Enam tipe JSON plus bin, tag, dan simple value | Lebih luas: ObjectId, Decimal128, tanggal, regex, timestamp |
| Mekanisme ekstensi | Tipe ekstensi (misalnya timestamp -1) | Tag (tanggal, bignum, CBOR tersemat) | Kode tipe tetap, ekstensi berdasarkan konvensi ekosistem |
| Encoding deterministik | Tidak ada persyaratan standar | Aturan eksplisit, dapat dipakai untuk tanda tangan | Tidak ada |
| Self-describing | Ya, tetapi tanpa schema tingkat field | Ya, dan dapat dideskripsikan dengan CDDL | Ya, dengan nama field diulang per dokumen |
| Overhead dokumen kecil | Rendah | Rendah | Tinggi (awalan panjang, nama field, terminator) |
| Ekosistem | Cache, log, sebagian RPC | COSE, WebAuthn, IoT | Hanya MongoDB |
6. Dukungan peramban dan Node
Node 24 tidak membawa codec ini, jadi Anda perlu memasang pustaka. Pilihan umum:
| Runtime | MessagePack | CBOR | BSON |
|---|---|---|---|
| Node.js | @msgpack/msgpack, msgpackr |
cbor-x, borc |
bson |
| Peramban | @msgpack/msgpack |
Build peramban cbor-x, cbor-web |
bson |
Kedua keluarga bekerja pada Uint8Array dan tidak memerlukan Buffer. Perhatikan perbedaan versi:
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 };
}
Sebagian besar pustaka mendekode bilangan bulat besar ke number secara bawaan dan kehilangan presisi di luar rentang aman. Jika nilai eksak penting, aktifkan opsi BigInt secara eksplisit (useBigInt64 di @msgpack/msgpack, sakelar setara di cbor-x), jika tidak Anda hanya memindahkan masalah lama JSON ke format baru.
7. Kemampuan debug dan kompatibilitas protokol
7.1 Kemampuan debug: biaya tersembunyi terbesar
Keunggulan terbesar JSON teks bukanlah ukuran; melainkan bahwa Anda dapat membukanya kapan saja. Setelah beralih ke biner:
grep,awk, danjqsemuanya berhenti bekerja, dan pipeline log memerlukan langkah dekode tambahan;- Debugging produksi memerlukan dekoder yang tepat pada versi yang tepat, atau nama field yang Anda lihat akan salah;
- Trafik yang tertangkap muncul di dev tools peramban sebagai gumpalan byte yang tidak terbaca;
- Diff tinjauan kode menampilkan rangkaian heksadesimal.
CBOR memiliki notasi diagnostik, yang merender byte kembali menjadi teks terbaca yang dekat dengan JSON, misalnya map sebagai {1: 2}; MessagePack juga memiliki beberapa dekoder command-line. Tetapi semuanya memerlukan pemasangan tambahan dan berada di luar jalur operasi standar.
Kesimpulannya: setiap kali orang perlu memeriksa data secara sering, biaya tersembunyi format biner melebihi bandwidth yang dihematnya.
7.2 Kompatibilitas protokol dan ekstensi
- CBOR memiliki mekanisme tag paling lengkap: tag 0 untuk string date-time, tag 1 untuk timestamp Unix, tag 2 dan 3 untuk bignum, dan tag 24 untuk CBOR tersemat. Dikombinasikan dengan encoding deterministik, ia digunakan oleh protokol yang membutuhkan tanda tangan dan konsistensi lintas implementasi, seperti COSE, WebAuthn, dan CWT.
- MessagePack menyerahkan tipe ekstensi kepada implementator. Dalam praktiknya satu-satunya yang umum adalah timestamp (tipe ekstensi -1). Antar tim, setiap tipe ekstensi harus ditulis ke dalam dokumen protokol atau pihak lain tidak dapat mendekodenya.
- BSON memiliki kode tipe tetap, dan
ObjectId,Decimal128,MinKey, sertaMaxKeyadalah semantik khusus MongoDB. Memperlakukan BSON sebagai format pertukaran umum membawa banyak tipe tak terpakai dan awalan panjang tak terpakai.
Jika protokol mengharuskan "data yang sama harus menghasilkan byte yang sama", hanya CBOR yang menyediakan jawaban standar; MessagePack dan BSON keduanya membutuhkan kesepakatan tambahan tentang urutan field dan detail encoding.
8. Kapan layak beralih
Sinyal yang membenarkan peralihan:
- Payload besar, kedua ujung dapat berubah, dan ukuran terkompresi masih berbeda secara berarti;
- Anda mengangkut konten biner dan penggembungan Base64 serta biaya dekode terukur;
- Anda membutuhkan bilangan bulat 64-bit atau desimal eksak yang tidak dapat direpresentasikan double JSON;
- Tautan adalah server-ke-server dan perkakas diagnostik dapat distandarkan.
Sinyal yang menentangnya:
- gzip atau brotli sudah terpasang dan keuntungannya hanya persentase satu digit;
- API bersifat publik dan pihak ketiga hanya memiliki klien HTTP serbaguna;
- Data adalah log atau konfigurasi yang dibaca orang dengan tangan;
- Tim tidak memiliki anggaran untuk memelihara dekoder dan kompatibilitas versi.
Jalur tengah juga berfungsi: pertahankan JSON secara eksternal dan gunakan MessagePack untuk cache internal. Nilai cache hanya dibaca oleh layanan Anda sendiri, sehingga ukuran dan biaya parse sama-sama membaik, dan mengosongkan cache menyelesaikan masalah apa pun tanpa menyentuh kontrak.
9. Checklist
- [ ] Bandingkan jumlah byte terkompresi dari data nyata, bukan jumlah tanpa kompresi;
- [ ] Tetapkan kebijakan bilangan bulat besar: opsi BigInt, transport string, atau bignum CBOR;
- [ ] Kirim field biner sebagai bin atau byte string alih-alih membungkusnya dengan Base64;
- [ ] Tulis tipe ekstensi dan tag ke dalam dokumen protokol dan patok versi dekoder;
- [ ] Pertahankan jalur debug JSON teks yang dapat diaktifkan saat insiden produksi;
- [ ] Jalankan benchmark dan catat angka yang dapat direproduksi alih-alih klaim verbal.
Apa perbedaan antara MessagePack dan CBOR?
Encoding mereka sangat mirip: map, array, dan string semuanya menggunakan awalan tipe-plus-panjang yang ringkas. Perbedaan utamanya adalah standardisasi. CBOR adalah RFC IETF dengan media type IANA, mekanisme tag, dan aturan encoding deterministik; MessagePack adalah spesifikasi komunitas yang tipe ekstensinya bergantung pada kesepakatan pribadi. Pilih CBOR ketika Anda membutuhkan tanda tangan, konsistensi lintas implementasi, atau protokol perangkat terbatas.
Bisakah BSON menggantikan JSON sebagai format umum?
Tidak disarankan. BSON dirancang untuk dokumen basis data: setiap dokumen membawa panjang total 4 byte, setiap field mengulang tipe dan namanya, dan dokumen kecil akhirnya lebih besar daripada JSON teks. Ia juga menyertakan tipe khusus MongoDB seperti ObjectId dan MinKey. Di luar MongoDB, sebagian besar sistem tipenya tidak terpakai sementara penalti ukuran tetap ada.
Seberapa kecil format biner membuat payload saya?
Tergantung bentuk datanya. Ketika nama field sangat berulang, JSON teks terkompresi dan format biner berakhir dekat; ketika namanya pendek dan data penuh karakter struktural serta angka, keunggulan biner lebih jelas. Ukur sampel nyata baik tanpa kompresi maupun setelah gzip, lalu putuskan, alih-alih memperkirakan dengan pengali generik.
Apakah saya masih bisa melakukan debug data biner dengan jq?
Tidak. jq hanya memproses JSON teks dan akan langsung gagal pada byte MessagePack atau CBOR. Anda harus mendekode dengan pustaka yang sesuai menjadi JSON terlebih dahulu lalu meneruskannya ke jq; CBOR juga dapat melalui alat notasi diagnostik agar menjadi teks terbaca. Mempertahankan jalur debug teks lebih murah daripada memasang perkakas sesuai kebutuhan.