- वेब API के standard के रूप में स्थापित JSON पढ़ने में आसान और flexible है, लेकिन performance और stability के मामले में इसकी सीमाएँ हैं
- Protobuf(Protocol Buffers) सख्त type definition और automatic code generation के ज़रिए data structure को स्पष्ट रूप से सुनिश्चित करता है
- Binary serialization का उपयोग करके यह JSON की तुलना में लगभग 3 गुना या उससे अधिक data size कम करता है और transfer speed बेहतर बनाता है
- server और client एक ही .proto schema साझा करते हैं, इसलिए type mismatch या manual validation की ज़रूरत नहीं रहती
- debugging कठिन हो सकती है, लेकिन performance, maintainability, development efficiency के लिहाज़ से Protobuf आधुनिक API के लिए अधिक उपयुक्त है
JSON की सार्वभौमिकता और सीमाएँ
- JSON एक इंसान द्वारा आसानी से पढ़ा जा सकने वाला text format है, जिसमें सिर्फ
console.log()से भी data देखा जा सकता है - वेब के साथ बेहतरीन integration की वजह से इसे JavaScript और backend framework ecosystem में व्यापक रूप से अपनाया गया है
- यह field जोड़ने, हटाने और type बदलने की flexibility देता है, लेकिन इसी कारण structure mismatch या error की संभावना भी रहती है
- Tool ecosystem समृद्ध है, इसलिए सिर्फ text editor या
curlसे भी इसे आसानी से संभाला जा सकता है - लेकिन इन फ़ायदों के बावजूद, performance और type safety के मामले में इससे बेहतर विकल्प मौजूद हैं
Protobuf का अवलोकन
- Google द्वारा 2001 में विकसित और 2008 में सार्वजनिक किया गया binary serialization format
- internal system और microservice के बीच communication में व्यापक रूप से उपयोग होता है
- अक्सर यह गलतफ़हमी होती है कि इसे gRPC के साथ ही इस्तेमाल करना चाहिए, लेकिन Protobuf को स्वतंत्र रूप से HTTP API में भी इस्तेमाल किया जा सकता है
- शुरुआत में binary format के सीधे न दिखने की वजह से इसकी पहुँच कम थी, लेकिन efficiency और stability के मामले में यह बहुत मज़बूत है
शक्तिशाली type system और code generation
- Protobuf
.protofile के माध्यम से data structure को स्पष्ट रूप से परिभाषित करता है- हर field का सख्त type, numeric identifier, और स्थिर नाम होता है
- उदाहरण:
message User { int32 id = 1; string name = 2; string email = 3; bool isActive = 4; } protoccommand के ज़रिए Dart, TypeScript, Kotlin, Swift, C#, Go, Rust जैसी कई भाषाओं के लिए automatic code generation का समर्थन- generated code के साथ serialization(
writeToBuffer) और deserialization(fromBuffer) किया जाता है, और manual validation या parsing की ज़रूरत नहीं पड़ती - नतीजतन समय की बचत और maintainability में सुधार दोनों साथ मिलते हैं
Binary serialization की दक्षता
- Protobuf text की जगह binary data में serialize होता है, इसलिए यह बेहद compact और तेज़ है
- एक ही data (
Userobject) के size की तुलना:- JSON: 86 bytes (whitespace हटाने पर 68 bytes)
- Protobuf: 30 bytes
- इसकी efficiency के कारण:
- numbers के लिए varint encoding का उपयोग
- text key की जगह numeric tag का उपयोग
- whitespace और अनावश्यक syntax को हटाना
- optional field optimization
- नतीजतन bandwidth की बचत, response speed में सुधार, mobile data की बचत, और user experience बेहतर होता है
Dart आधारित Protobuf API उदाहरण
shelfpackage का उपयोग करके एक सरल HTTP server बनाया जाता है, जोUserobject को Protobuf में लौटाता है- server code के मुख्य बिंदु:
User()object बनाकरwriteToBuffer()से serialize करना- response header में
'content-type': 'application/protobuf'सेट करना
- client,
httppackage औरuser.pb.dartका उपयोग करके Protobuf data को सीधे decode कर सकता है - server और client एक ही
.protoschema साझा करते हैं, इसलिए data structure mismatch नहीं होता - यही तरीका Go, Rust, Kotlin, Swift, C#, TypeScript आदि में भी समान रूप से लागू किया जा सकता है
JSON के बचे हुए फ़ायदे
- Protobuf में schema के बिना अर्थ समझना कठिन होता है
- field name की जगह सिर्फ numeric identifier दिखते हैं, इसलिए इसे इंसान के लिए पढ़ना मुश्किल होता है
- उदाहरण तुलना:
- JSON:
{ "id": 42, "name": "Alice" } - Protobuf:
1: 42, 2: "Alice"
- JSON:
- इसलिए Protobuf के लिए:
- dedicated decoding tool की ज़रूरत होती है
- schema management और version management अनिवार्य हैं
- फिर भी, performance और efficiency के फ़ायदे इससे कहीं अधिक बड़े हैं
निष्कर्ष
- Protobuf एक परिपक्व और high-performance serialization technology है, जिसे public API में भी पूरी तरह इस्तेमाल किया जा सकता है
- gRPC के बिना भी यह सामान्य HTTP API में स्वतंत्र रूप से काम करता है
- यह performance, robustness, error reduction, और development efficiency सभी को बेहतर बनाता है
- अगली पीढ़ी की परियोजनाओं में Protobuf अपनाने का पर्याप्त मूल्य है
10 टिप्पणियां
TypeSpec
https://typespec.io/
https://msgpack.org/ यह कैसा है?
MessagePack भी अच्छा है।
मुझे लगता है कि जिस फ़ॉर्मैट के लिए debugging का कोई आधिकारिक decoder भी नहीं है, उसे mature बताना अपने आप में विरोधाभासी है।
हर टूल की तरह यह भी कोई सर्वगुणसंपन्न समाधान नहीं है, लेकिन मुझे लगता है कि Protobuf भी काफ़ी अच्छा टूल है.
खासकर जब एंबेडेड environment में कई भाषाओं के clients को high-volume, high-frequency (प्रति सेकंड 20 बार) डेटा भेजना पड़ता था, तब मैंने nanopb के साथ इसे काफ़ी साफ़-सुथरे तरीके से इस्तेमाल किया था.
इतना सख्ती से करेंगे तो फिर क्या XML में नहीं आ जाएगा? haha
अगर schema को भी dtd से define कर दिया जाए और parser side पर caching कर ली जाए, तो schema को सिर्फ़ एक बार भेजने जैसा असर भी होगा।
=> क्या schema को वैसे भी कम-से-कम एक बार भेजना ज़रूरी नहीं होता? JSON में भी schema गायब नहीं होता, बल्कि वह data में implicit रूप से शामिल होता है, इसलिए ऐसा नहीं है कि schema भेजा ही नहीं जा रहा। बल्कि हर item के साथ schema बार-बार duplicate होकर भेजा जाता है, इसलिए वह और भी अक्षम है। "schema-based होते हुए भी message के अंदर schema शामिल करने वाला format" काफ़ी अच्छा लग रहा है।
Hacker News राय
JSON में अक्सर अस्पष्ट या गैर-गारंटीड डेटा भेजा जाता है। फ़ील्ड छूट जाना, type errors, key में typo, undocumented structure जैसी कई समस्याएँ होती हैं। लेकिन एक लेख में दावा किया गया था कि Protobuf
.protoफ़ाइल के ज़रिए message structure को स्पष्ट रूप से define करके ऐसी चीज़ों को असंभव बना देता है। हालांकि यह Protobuf की philosophy को गलत समझना है।proto3में required fields का समर्थन ही नहीं है। आधिकारिक दस्तावेज़ (Protobuf Best Practices) में भी साफ़ लिखा है कि “required fields हानिकारक थे, इसलिए हटा दिए गए।” अंततः Protobuf client को भी JSON API की तरह defensive ढंग से लिखना पड़ता हैjson:"-"से private fields को रोकना ज़रूरी है। मेरा प्रोजेक्ट Gooey में देखा जा सकता हैcompressed JSON काफ़ी उपयोगी है, और initial communication cost कम होती है। फ़ील्ड छूट जाएँ या type बदल जाए तो दिक्कत होती है, लेकिन पूरी तरह typed structure design करना और version sync के लिए process बनाना ज़्यादातर लोग ठीक से नहीं कर पाते। आख़िर में कम human cost वाला तरीका जीतता है। इसलिए JSON तब तक ग़ायब नहीं होगा जब तक उससे कम human communication cost वाला कोई विकल्प नहीं आ जाता
console.log()से तुरंत debug किया जा सकने वाला विकल्प नहीं आता, JSON को replace करना मुश्किल हैProtobuf परफ़ेक्ट नहीं है। server और client अलग-अलग समय पर deploy हों और spec version अलग हो जाए, तो safety टूट जाती है। ID reuse पर रोक, unknown-field copying जैसी चीज़ों से इसे कुछ हद तक कम किया जा सकता है, लेकिन distributed systems मूल रूप से complex होते हैं। फिर भी
protobuf3नेprotobuf2की बहुत-सी समस्याएँ हल कीं। पहले यह पता नहीं चलता था कि default value explicitly set की गई थी या field missing थी, लेकिन अबmessagetype से यह हल हो जाता हैलेख में इसे “अत्यंत कुशल” कहा गया, लेकिन gzip का कोई ज़िक्र नहीं है। ज़्यादातर text data पहले से ही auto-compress होकर भेजा जाता है। इसलिए Protobuf की तुलना gzip किए गए JSON से होनी चाहिए
बेहतर protocol की वकालत करना अच्छी बात है, लेकिन यह कहना मुश्किल है कि Protobuf efficiency और usability दोनों में JSON की जगह ले सकता है। Protobuf अपनी strict schema की वजह से उन क्षेत्रों में कमज़ोर पड़ता है जहाँ JSON अच्छा काम करता है। बल्कि CBOR JSON के विकल्प के रूप में ज़्यादा उपयुक्त लगता है। CBOR, JSON की तरह flexible है, लेकिन encoding अधिक compact है
1984 का ASN.1 पहले से वह काम अधिक flexibility के साथ करता है जो Protobuf करता है। DER encoding का इस्तेमाल करें तो यह इतना भी बुरा नहीं है। ASN.1 DER उदाहरण देखा जा सकता है। Protobuf जो हासिल करता है, उसके मुकाबले बहुत ज़्यादा जटिल है
मैंने पूरे production system को Protobuf से बनाया था, लेकिन उसका management अपने आप में पीड़ादायक था। तकनीकी रूप से यह अच्छा दिखता है, लेकिन व्यवहार में JSON कहीं ज़्यादा सरल है
Protobuf बेहतरीन है, लेकिन इसमें zero-copy support न होना खलता है। Cap’n Proto जैसे formats serialization/deserialization bottleneck हटा देते हैं
मैंने एक NodeJS project में
.protoसे पूरा API define किया था, और Content-Type के आधार पर proto या JSON में response देने वाला server बनाया था। यह Swagger से कहीं ज़्यादा structured है। बस अफ़सोस यह है कि Google ने ऐसी सुविधा official library में नहीं दी। gRPC, HTTP/2 dependency की वजह से असुविधाजनक है। वैसे मेरे हिसाब से Text proto सबसे बेहतरीन static configuration language हैमेरा सपना एक ऐसे binary format का है जो schema-based भी हो और message के भीतर schema भी शामिल करे। तब उसे vim plugin से सीधे पढ़ा जा सकेगा। जब लाखों objects हों, तो 2GB message में 1KB schema जोड़ना कोई बड़ा बोझ नहीं है
"डिबगिंग मुश्किल है"
छूट गया