JSON Toolkit

JSON แบบไบนารี: เลือกระหว่าง MessagePack, CBOR และ BSON

สรุปสำคัญ: MessagePack, CBOR และ BSON ต่างบีบอัด JSON ให้เป็นไบต์ เปรียบเทียบต้นทุนไบต์ การจัดการ int64 และข้อมูลไบนารี และหาเส้นแบ่งที่ชัดเจนว่าควรเปลี่ยนรูปแบบเมื่อใด

ระดับกลางอ่านประมาณ 10 นาทีเผยแพร่ 2026-10-31อัปเดต 2026-10-31
ภาพหน้าปกเปรียบเทียบรูปแบบ JSON แบบไบนารี MessagePack, CBOR และ BSON

สรุปสั้น: เก็บ JSON แบบข้อความไว้สำหรับการแลกเปลี่ยนภายนอกและสำหรับข้อมูลที่คนต้องตรวจสอบ และเปลี่ยนไปใช้ MessagePack หรือ CBOR บนลิงก์ภายในเฉพาะเมื่อ payload แบบไบนารี จำนวนเต็มที่เกิน 2^53 หรือทศนิยมแบบแม่นยำตรงทำให้ขนาดหลังบีบอัดหรือความสามารถในการแสดงชนิดกลายเป็นปัญหาจริง; BSON เป็นของระบบนิเวศ MongoDB

Text JSON ประหยัดช่องว่าง ส่วนรูปแบบไบนารีประหยัดเครื่องหมายวรรคตอนและรูปข้อความของจำนวน ชื่อฟิลด์ยังปรากฏครั้งเดียวต่อเรกคอร์ด ดังนั้นให้คำนวณการประหยัดจริงก่อนเปลี่ยน

1. JSON แบบไบนารีประหยัดอะไรจริง ๆ

กำหนดความคาดหวังก่อน ไม่มีรูปแบบใดในเหล่านี้เป็น "ไวยากรณ์ JSON อีกแบบ" พวกมันเข้ารหัส โมเดลข้อมูลเดียวกันเป็นไบต์: object, array, string, number, boolean และ null สิ่งที่พวกมันกำจัดนั้นเป็นรูปธรรม:

  • อักขระโครงสร้างอย่างเครื่องหมายคำพูด, colon, เครื่องหมายจุลภาค และวงเล็บปีกกา;
  • รูปข้อความฐานสิบของจำนวน ทำให้ 32 กลายเป็นหนึ่งไบต์;
  • การสแกนซ้ำเพื่อหาขอบเขตของ string แทนที่ด้วยคำนำหน้าความยาวคงที่;
  • การเข้ารหัส Base64 สำหรับ payload ไบนารี ซึ่งเก็บเป็นไบต์ได้โดยตรง

สิ่งที่พวกมันกำจัดไม่ได้ก็เป็นรูปธรรม เช่นกัน: ชื่อฟิลด์ยังปรากฏเป็น string ในทุกเรกคอร์ด map ของ MessagePack, map ของ CBOR และเอกสาร BSON ต่างทำคีย์ซ้ำสำหรับทุกรายการ ดังนั้นเมื่อ JSON ของคุณเป็นหนึ่งหมื่นเรกคอร์ดที่มีรูปร่างเดียวกัน ช่องว่างขนาดหลังบีบอัดระหว่างข้อความกับไบนารีจะเล็กกว่าที่สัญชาตญาณบอกมาก เพราะ gzip เก่งที่สุดในการกำจัดชื่อฟิลด์ที่ซ้ำกัน

2. รูปแบบทั้งสามมาจากไหน

รูปแบบ สเปกและปี ที่มา การใช้งานทั่วไป
MessagePack สเปก msgpack.org ตั้งแต่ปี 2008 การออกแบบอิสระที่เน้นความมินิมัล ค่าแคช, IPC, pipeline ของ log
CBOR RFC 8949 (STD 94) ปี 2020 ได้อิทธิพลจาก MessagePack และมาตรฐานโดย IETF COSE, WebAuthn, CWT, อุปกรณ์จำกัดทรัพยากร
BSON bsonspec.org ระบบนิเวศ MongoDB ออกแบบสำหรับเอกสารฐานข้อมูล การเก็บและ wire protocol ของ MongoDB

CBOR เป็นมาตรฐานมากที่สุด: มี media type application/cbor ที่ลงทะเบียนกับ IANA, กฎการเข้ารหัสแบบ deterministic และ CDDL สำหรับคำอธิบาย MessagePack เบาที่สุด ด้วยสเปกที่พอดีหนึ่งหน้า BSON หนักที่สุด: มันฝัง ObjectId, Decimal128, วันที่ และ subtype ไบนารีเข้าในระบบชนิดของมัน ซึ่งเป็นเหตุให้มันเป็นที่นิยมจริง ๆ เฉพาะในระบบนิเวศ MongoDB

3. ข้อมูลเดียวกัน สี่การเข้ารหัส

ยกตัวอย่าง {"name":"joe"} ต้นทุนไบต์เปรียบเทียบได้ง่าย:

การเข้ารหัส ไบต์ ลำดับไบต์
ข้อความ JSON 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 ไบต์ + ไบต์ชนิด + name\0 + ความยาวค่า 4 ไบต์ + joe\0 + ตัวปิดท้าย

แยกเก้าไบต์ของ MessagePack ดู:

  • 81: nibble สูง 1000 หมายถึง map, nibble ต่ำ 0001 หมายถึงหนึ่งคู่คีย์-ค่า;
  • a3: สามบิตสูง 101 หมายถึง string ความยาวคงที่ 3;
  • 6e 61 6d 65: ASCII ของ name;
  • a3: string อีกตัวความยาว 3;
  • 6a 6f 65: joe

a1 ของ CBOR คือ major type 5 (map) ความยาว 1 และ 64 คือ major type 3 (text string) ความยาว 4 ความหมายจึงเกือบเป็น isomorphic กับ MessagePack BSON ใหญ่กว่า: ทุกเอกสารพาความยาวรวม 4 ไบต์ ทุกฟิลด์ทำไบต์ชนิดและชื่อซ้ำ และทุก string ทำความยาวพร้อม \0 ต่อท้ายซ้ำ ในเอกสารเล็ก BSON อาจใหญ่กว่าข้อความ JSON ได้ง่าย ๆ

คุณตรวจคำนำหน้าได้โดยตรงด้วยการแสดงไบต์เหล่านั้นเป็นฐานสิบหก:

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 ขนาดและความเร็ว parse: ไม่ต้องสนตัวเลขการตลาด

คำอ้างว่าไบนารี "เร็ว 10 เท่า" ควรแยกเป็นสองคำถาม

ขนาด. เมื่อไม่บีบอัด ไบนารีเล็กกว่าเพราะเครื่องหมายวรรคตอนและช่องว่างหายไป แต่ pipeline จริงแทบจะบีบอัดเสมอ: หลัง gzip หรือ brotli ชื่อฟิลด์ที่ซ้ำกันถูกบีบอัดจนหาย และข้อได้เปรียบของไบนารีก็หดลงอย่างมาก ให้ทำตามวิธีใน การทำ JSON ให้เล็กสุดเทียบกับ gzip: วัดไบต์หลังบีบอัดก่อน แล้วจึงตัดสินว่าการเปลี่ยนรูปแบบคุ้มหรือไม่

ความเร็ว parse. ไบนารีข้าม lexing (การสแกนเครื่องหมายคำพูด, เครื่องหมายจุลภาค และอักขระของจำนวน) จึงควรเร็วกว่าในทางทฤษฎี อย่างไรก็ตามใน JavaScript ต้นทุนหลักคือการจัดสรร object และหน่วยความจำ ซึ่ง decoder ใดก็เลี่ยงไม่ได้ รูปร่างข้อมูล จำนวนฟิลด์ และคุณภาพ implementation ล้วนมีผล ข้อสรุปที่เชื่อถือได้จึงมาจากการ benchmark payload ของคุณเอง ไม่ใช่การอ้างตัวคูณของผู้ขาย หาก payload เดียวใหญ่เกินกว่าจะอ่านเข้าหน่วยความจำทีเดียว ให้แบ่งด้วยวิธีใน การ parse และ streaming JSON ขนาดใหญ่ ก่อนวัดกำไรจากการเข้ารหัส

4. ฟิลด์ int64 และไบนารี: เหตุผลจริงของการเปลี่ยน

ขนาดมักไม่ใช่เหตุผลที่เปลี่ยนรูปแบบ ความสามารถในการแสดงชนิด ต่างหากที่เป็นเหตุผล

4.1 จำนวนเต็มที่เกิน 2^53

จำนวน JSON ตกไปอยู่ใน double ใน JavaScript ดังนั้น 9007199254740993 กลายเป็น 9007199254740992 รูปแบบไบนารีทั้งสามจัดการเรื่องนี้ต่างกัน:

รูปแบบ จำนวนเต็ม 64 บิต 64 บิตแบบไม่คิดเครื่องหมาย ความแม่นยำตามอำเภอใจ
MessagePack ✓ int64 (0xd3) ถอดเป็น BigInt ได้ ✓ uint64 (0xcf) ✗ (ต้องใช้ extension type)
CBOR ✓ รูป 64 บิตของ major type 0/1 ✓ พื้นที่เข้ารหัสเดียวกัน ✓ bignum tag 2/3
BSON ✓ int64 (0x12) ✗ รองรับเฉพาะแบบมีเครื่องหมาย ✗ (Decimal128 เป็น fixed-point ไม่ใช่จำนวนเต็มตามอำเภอใจ)

CBOR เป็นตัวเดียวที่มีการแสดงแทนมาตรฐานสำหรับจำนวนเต็มความแม่นยำตามอำเภอใจ: ค่าที่เกิน 64 บิตถูกห่อด้วย tag 2 (ไม่ติดลบ) หรือ tag 3 (ติดลบ) รอบ byte string MessagePack และ BSON ถอยไปใช้ string หรือข้อตกลง extension ที่ทำเอง

4.2 Payload ไบนารี

JSON มีวิธีแสดงไบนารีเพียงวิธีเดียว: Base64 ซึ่งพอง payload ขึ้นประมาณหนึ่งในสามและต้องถอดรหัสคัดลอกเพิ่ม MessagePack มีชนิด bin (0xc4–0xc6), CBOR มี byte string (major type 2) และ BSON มี subtype ไบนารี เมื่อคุณขนส่งรูปภาพ, hash, vector หรือบล็อกที่บีบอัดแล้ว ความแตกต่างนี้สำคัญกว่าการประหยัดไบต์เครื่องหมายวรรคตอนไม่กี่ไบต์มาก

5. เปรียบเทียบเคียงข้างกัน

มิติ MessagePack CBOR BSON
สเปก สเปกของชุมชน IETF RFC 8949 ระบบนิเวศ MongoDB
Media type application/msgpack (ไม่ใช่มาตรฐาน IANA) application/cbor (ลงทะเบียน IANA) ไม่มี media type ทั่วไป
ระบบชนิด หกชนิดของ JSON บวก bin และ ext หกชนิดของ JSON บวก bin, tag และ simple value กว้างกว่า: ObjectId, Decimal128, วันที่, regex, timestamp
กลไกส่วนขยาย Extension type (เช่น timestamp -1) Tag (วันที่, bignum, CBOR ที่ฝังอยู่) รหัสชนิดตายตัว ส่วนขยายตามข้อตกลงของระบบนิเวศ
การเข้ารหัสแบบ deterministic ไม่มีข้อกำหนดมาตรฐาน กฎชัดเจน ใช้กับลายเซ็นได้ ไม่มี
Self-describing ใช่ แต่ไม่มี schema ระดับฟิลด์ ใช่ และอธิบายได้ด้วย CDDL ใช่ โดยชื่อฟิลด์ซ้ำในทุกเอกสาร
Overhead เอกสารเล็ก ต่ำ ต่ำ สูง (คำนำหน้าความยาว, ชื่อฟิลด์, ตัวปิดท้าย)
ระบบนิเวศ แคช, log, RPC บางส่วน COSE, WebAuthn, IoT MongoDB เท่านั้น

6. การรองรับใน Browser และ Node

Node 24 ไม่มี codec เหล่านี้ในตัว คุณจึงต้องติดตั้งไลบรารี ตัวเลือกที่พบบ่อย:

Runtime MessagePack CBOR BSON
Node.js @msgpack/msgpack, msgpackr cbor-x, borc bson
Browser @msgpack/msgpack cbor-x build สำหรับ browser, cbor-web bson

ทั้งสองตระกูลทำงานบน Uint8Array และไม่ต้องใช้ Buffer ให้ระวังความต่างของเวอร์ชัน:

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 };
}

ไลบรารีส่วนใหญ่ถอดจำนวนเต็มขนาดใหญ่เป็น number โดยค่าเริ่มต้นและสูญเสียความแม่นยำเมื่อเกินช่วงปลอดภัย หากค่าที่แม่นยำตรงสำคัญ ให้เปิดออปชัน BigInt อย่างชัดเจน (useBigInt64 ใน @msgpack/msgpack, สวิตช์ที่เทียบเท่าใน cbor-x) ไม่อย่างนั้นคุณเพียงย้ายปัญหาเดิมของ JSON ไปยังรูปแบบใหม่

7. ความสามารถในการ debug และความเข้ากันได้ของ protocol

7.1 ความสามารถในการ debug: ต้นทุนแฝงที่ใหญ่ที่สุด

ข้อดีใหญ่ที่สุดของ text JSON ไม่ใช่ขนาด แต่คือ คุณเปิดมันได้ทุกเมื่อ หลังจากเปลี่ยนเป็นไบนารี:

  • grep, awk และ jq ใช้ไม่ได้ทั้งหมด และ pipeline ของ log ต้องมีขั้นตอนถอดรหัสเพิ่ม;
  • การ debug production ต้องมี decoder ที่ถูกเวอร์ชัน ไม่อย่างนั้นชื่อฟิลด์ที่เห็นจะผิด;
  • ทราฟฟิกที่ดักจับได้แสดงใน developer tools ของ browser เป็นก้อนไบต์ที่อ่านไม่ออก;
  • diff ในการรีวิวโค้ดแสดงสตริงฐานสิบหกยาว

CBOR มี diagnostic notation ที่แสดงไบต์กลับเป็นข้อความอ่านง่ายใกล้เคียง JSON เช่น map เป็น {1: 2}; MessagePack ก็มี decoder command line อยู่บ้าง แต่ทั้งหมดต้องติดตั้งเพิ่มและอยู่นอกเส้นทางการทำงานมาตรฐาน

ข้อสรุป: เมื่อใดที่คนต้องตรวจข้อมูลบ่อย ๆ ต้นทุนแฝงของรูปแบบไบนารีจะเกินแบนด์วิดท์ที่มันประหยัด

7.2 ความเข้ากันได้ของ protocol และส่วนขยาย

  • CBOR มีกลไก tag ที่สมบูรณ์ที่สุด: tag 0 สำหรับสตริงวันที่-เวลา, tag 1 สำหรับ Unix timestamp, tag 2 และ 3 สำหรับ bignum และ tag 24 สำหรับ CBOR ที่ฝังอยู่ เมื่อรวมกับการเข้ารหัสแบบ deterministic มันถูกใช้โดย protocol ที่ต้องมีลายเซ็นและความสอดคล้องข้าม implementation เช่น COSE, WebAuthn และ CWT
  • MessagePack ปล่อย extension type ให้ผู้ implement ในทางปฏิบัติตัวที่พบบ่อยมีเพียง timestamp (extension type -1) ข้ามทีม ทุก extension type ต้องเขียนลงในเอกสาร protocol ไม่อย่างนั้นอีกฝั่งถอดรหัสไม่ได้
  • BSON มีรหัสชนิดตายตัว และ ObjectId, Decimal128, MinKey และ MaxKey เป็นความหมายเฉพาะของ MongoDB การใช้ BSON เป็นรูปแบบแลกเปลี่ยนทั่วไปนำชนิดที่ไม่ได้ใช้และคำนำหน้าความยาวที่ไม่ได้ใช้มาด้วยเป็นกอง

หาก protocol ต้องการ "ข้อมูลเดียวกันต้องสร้างไบต์เดียวกัน" มีเพียง CBOR ที่ให้คำตอบมาตรฐาน; MessagePack และ BSON ต่างต้องมีข้อตกลงเพิ่มเรื่องลำดับฟิลด์และรายละเอียดการเข้ารหัส

8. เมื่อใดควรเปลี่ยน

สัญญาณที่สนับสนุนการเปลี่ยน:

  • Payload ใหญ่ ทั้งสองฝั่งเปลี่ยนได้ และขนาดหลังบีบอัดยังต่างกันอย่างมีความหมาย;
  • คุณขนส่งเนื้อหาไบนารี และการพองจาก Base64 กับต้นทุนการถอดรหัสวัดได้;
  • คุณต้องใช้จำนวนเต็ม 64 บิตหรือทศนิยมแบบแม่นยำตรงที่ double ของ JSON แทนไม่ได้;
  • ลิงก์เป็น server-to-server และเครื่องมือวินิจฉัยสามารถทำให้เป็นมาตรฐานได้

สัญญาณที่คัดค้าน:

  • gzip หรือ brotli มีอยู่แล้วและกำไรเป็นเพียงเลขหลักเดียวเป็นเปอร์เซ็นต์;
  • API เป็นสาธารณะและบุคคลที่สามมีเพียง HTTP client ทั่วไป;
  • ข้อมูลเป็น log หรือ configuration ที่คนอ่านด้วยมือ;
  • ทีมไม่มีงบสำหรับดูแล decoder และความเข้ากันได้ของเวอร์ชัน

ทางสายกลางก็ใช้ได้: เก็บ JSON ไว้ภายนอกและใช้ MessagePack สำหรับแคชภายใน ค่าแคชมีเพียง service ของคุณเองอ่าน ขนาดและต้นทุน parse จึงดีขึ้นทั้งคู่ และการล้างแคชแก้ปัญหาได้โดยไม่แตะสัญญา

9. รายการตรวจสอบ

  • [ ] เปรียบเทียบจำนวนไบต์หลังบีบอัดจากข้อมูลจริง ไม่ใช่จำนวนก่อนบีบอัด;
  • [ ] กำหนดนโยบายจำนวนเต็มขนาดใหญ่: ออปชัน BigInt, ขนส่งเป็น string หรือ bignum ของ CBOR;
  • [ ] ส่งฟิลด์ไบนารีเป็น bin หรือ byte string แทนการห่อด้วย Base64;
  • [ ] เขียน extension type และ tag ลงในเอกสาร protocol และปักหมุดเวอร์ชัน decoder;
  • [ ] เก็บเส้นทาง debug แบบ text-JSON ที่เปิดได้ระหว่างเหตุการณ์ production;
  • [ ] รัน benchmark และบันทึกตัวเลขที่ทำซ้ำได้แทนคำอ้างด้วยวาจา

MessagePack กับ CBOR ต่างกันอย่างไร?

การเข้ารหัสของทั้งสองคล้ายกันมาก: map, array และ string ต่างใช้คำนำหน้าแบบชนิดบวกความยาวที่กระชับ ความแตกต่างหลักคือความเป็นมาตรฐาน CBOR เป็น IETF RFC ที่มี media type ของ IANA มีกลไก tag และกฎการเข้ารหัสแบบ deterministic; MessagePack เป็นสเปกของชุมชนซึ่ง extension type พึ่งข้อตกลงส่วนตัว ให้เลือก CBOR เมื่อต้องมีลายเซ็น ความสอดคล้องข้าม implementation หรือ protocol สำหรับอุปกรณ์จำกัดทรัพยากร

BSON ใช้แทน JSON เป็นรูปแบบทั่วไปได้หรือไม่?

ไม่แนะนำ BSON ถูกออกแบบสำหรับเอกสารฐานข้อมูล: ทุกเอกสารพาความยาวรวม 4 ไบต์ ทุกฟิลด์ทำชนิดและชื่อซ้ำ และเอกสารเล็กจบลงด้วยขนาดใหญ่กว่าข้อความ JSON อีกทั้งมีชนิดเฉพาะ MongoDB อย่าง ObjectId และ MinKey นอก MongoDB ระบบชนิดส่วนใหญ่ของมันไม่ได้ใช้ แต่บทลงโทษด้านขนาดยังอยู่

รูปแบบไบนารีทำให้ payload เล็กลงเท่าไร?

ขึ้นกับรูปร่างข้อมูล เมื่อชื่อฟิลด์ซ้ำหนัก ๆ ข้อความ JSON หลังบีบอัดกับรูปแบบไบนารีจะใกล้กัน; เมื่อชื่อสั้นและข้อมูลเต็มไปด้วยอักขระโครงสร้างและจำนวน ข้อได้เปรียบของไบนารีจะชัดกว่า ให้วัดตัวอย่างจริงทั้งก่อนและหลัง gzip แล้วตัดสิน แทนการประมาณด้วยตัวคูณทั่วไป

ยัง debug ข้อมูลไบนารีด้วย jq ได้หรือไม่?

ไม่ได้ jq ประมวลผลเพียง text JSON และจะล้มเหลวทันทีกับไบต์ MessagePack หรือ CBOR คุณต้องถอดรหัสด้วยไลบรารีที่ตรงกันเป็น JSON ก่อนแล้วจึงส่งให้ jq; CBOR ยังผ่านเครื่องมือ diagnostic notation เพื่อเป็นข้อความที่อ่านได้ การเก็บเส้นทาง debug แบบข้อความไว้มีต้นทุนต่ำกว่าการติดตั้งเครื่องมือตามต้องการ