- PostgreSQL extension proxy PgDog ने SQL parsing performance बढ़ाने के लिए Protobuf serialization की जगह Rust direct binding अपनाई
- मौजूदा Protobuf-आधारित संरचना को C–Rust direct conversion (bindgen + Claude द्वारा जनरेटेड wrapper) से बदलकर parsing 5.45 गुना, deparsing 9.64 गुना तेज किया गया
- performance bottleneck pg_query_parse_protobuf फ़ंक्शन में मिला, और caching की कोशिशों के बाद भी मूलभूत सुधार के लिए संरचना बदली गई
- Claude LLM का उपयोग करके 6,000 lines का Rust–C conversion code अपने-आप जनरेट किया गया, और इसे
parse,deparse,fingerprint,scanजैसी मुख्य functions पर लागू किया गया - इस optimization से PgDog की CPU usage और latency घटी, और PostgreSQL horizontal scaling proxy के रूप में इसकी efficiency काफ़ी बढ़ी
PgDog और Protobuf की सीमाएँ
- PgDog PostgreSQL को scale करने के लिए बना एक proxy है, जो अंदरूनी तौर पर SQL queries parse करने के लिए libpg_query का उपयोग करता है
- यह Rust में लिखा गया है, और पहले Protobuf serialization/deserialization के ज़रिए C library से communicate करता था
- Protobuf तेज़ है, लेकिन direct binding तरीका उससे भी तेज़ है
- PgDog टीम ने
pg_query.rsको fork करके Protobuf हटाया और C–Rust direct binding लागू की - नतीजतन query parsing 5.45 गुना और deparsing 9.64 गुना तेज़ हो गई
- PgDog टीम ने
benchmark परिणाम
- benchmark को PgDog के fork repository में दोबारा चलाया जा सकता है
pg_query::parse(Protobuf): 613 QPSpg_query::parse_raw(direct C–Rust): 3357 QPSpg_query::deparse(Protobuf): 759 QPSpg_query::deparse_raw(direct Rust–C): 7319 QPS
performance bottleneck analysis और caching प्रयास
- samply profiler से CPU time का analysis करने पर pg_query_parse_protobuf फ़ंक्शन bottleneck निकला
- caching के ज़रिए कुछ सुधार की कोशिश की गई
- LRU algorithm-आधारित hashmap cache का उपयोग कर query text को key और AST को stored value के रूप में रखा गया
- prepared statements के उपयोग पर reuse संभव था
- लेकिन कुछ ORM हज़ारों unique queries बनाते थे, और पुराने PostgreSQL drivers prepared statements को support नहीं करते थे, इसलिए cache efficiency कम रही
LLM की मदद से Protobuf हटाना
- PgDog टीम ने Claude LLM का उपयोग करके Protobuf हटाने वाले Rust bindings जनरेट किए
- स्पष्ट और verify किए जा सकने वाले task scope में AI ने प्रभावी ढंग से काम किया
- Claude ने
libpg_queryके Protobuf spec के आधार पर C structs को Rust structs से map किया- 2 दिनों की iterative मेहनत के बाद 6,000 lines का recursive Rust code पूरा हुआ
- इसे
parse,deparse,fingerprint,scanfunctions पर लागू किया गया, और pgbench के आधार पर 25% performance improvement की पुष्टि हुई
implementation की संरचनात्मक जानकारी
- Rust और C के बीच conversion में unsafe functions का उपयोग करके structs को सीधे map किया गया
- C structs को Postgres API तक भेजकर AST बनाया गया, फिर उसे Rust में recursively convert किया गया
- हर AST node को convert_node फ़ंक्शन से process किया जाता है, जो SQL grammar के सैकड़ों tokens को map करता है
- SELECT, INSERT जैसे हर node type के लिए अलग conversion functions मौजूद हैं
- conversion result में मौजूदा Protobuf struct (
protobuf::ParseResult) का दोबारा उपयोग किया गया, जिससे tests में byte-level comparison validation संभव हुआ - recursive algorithm में memory allocation कम होती है और CPU cache efficiency अधिक रहती है, इसलिए यह iterative implementation से तेज़ है
- iterative implementation अनावश्यक memory allocation और hashmap lookups की वजह से उल्टा धीमी रही
निष्कर्ष
- Postgres parser का overhead घटाकर PgDog ने latency, memory और CPU usage तीनों कम किए
- इस optimization से PgDog और तेज़ तथा कम लागत पर चलने वाला PostgreSQL scaling proxy बन गया
- PgDog PostgreSQL के horizontal scaling (next iteration) को साथ मिलकर बनाने वाले engineers की भर्ती कर रहा है
3 टिप्पणियां
हो सकता है कि मैं मूल लेख को गलत समझ रहा हूँ, लेकिन खासकर Rust से जुड़े लेखों में अक्सर ऐसा लगता है कि मुद्दे की असली बात से हटकर इसे ऐसे लिखा जाता है मानो यह सिर्फ़ "Rust होने की वजह से" तेज़ हो गया हो.
इस लेख का मुख्य बिंदु तो यह है कि अनावश्यक serialization overhead कम करने से performance बेहतर हुई है.
अब दोबारा देखता हूँ तो यह भी शायद Rust की उतनी प्रशंसा करने वाला लेख नहीं लगता, लेकिन क्या दूसरे लेखों की वजह से मेरे मन में इसके प्रति नकारात्मक धारणा बन गई है?
मुझे भी लगा कि इस मूल शीर्षक में, वास्तविक सामग्री से अलग, Rust पर जरूरत से ज़्यादा ज़ोर है, जिससे यह प्रदर्शन सुधार पर केंद्रित दिखता है, इसलिए मैंने इसे थोड़ा संशोधित किया।
लगता है Rust से जुड़े लेखों में ऐसा रुझान अक्सर दिखता है, इसलिए उन्हें थोड़ा फ़िल्टर करके पढ़ने की ज़रूरत होती है।
Hacker News की राय
शीर्षक ऐसा लगता है मानो Rust ने 5 गुना performance improvement दिया हो, लेकिन विडंबना यह है कि असल में चीज़ें पहले धीमी हुई थीं
समस्या यह थी कि Rust में लिखे गए software को C में लिखी libpg_query का इस्तेमाल करना था, लेकिन उसे सीधे जोड़ नहीं पा रहे थे, इसलिए Protobuf-आधारित Rust–C binding का उपयोग किया गया
यह तरीका धीमा था, इसलिए आखिरकार LLM की मदद से non-portable लेकिन कहीं अधिक optimized binding फिर से लिखी गई
अगर शुरुआत से ही C में लिखा गया होता, तो conversion process की ज़रूरत ही नहीं पड़ती। यानी, शीर्षक “Rust इस्तेमाल करने से हुए performance loss को कम किया” अधिक सटीक होता
conversion layer portability और security देती है, लेकिन आखिरकार copy·conversion·serialization बार-बार होती है और यही app को धीमा बनाने के कारणों में से एक है
Rust से C library को call करना बहुत आसान है, और safe wrapper भी पहले से बहुत मौजूद हैं
बीच में Protobuf रखने वाली संरचना लगभग कभी नहीं देखी, और bottleneck वही था
शीर्षक सिर्फ click खींचने के लिए “Rust में फिर से लिखा” वाले meme के करीब लगता है
मूल library में serialization/deserialization बार-बार होने वाला गलत design था, और असली बात उसे हटाना है
शीर्षक “Protobuf को सामान्य API से बदलकर 5 गुना तेज़ किया” अधिक सही है
Rust में C binding सबसे आसान चीज़ों में है, और अगर API बहुत बड़ा न हो तो यह simple होता है
memory के अंदर data exchange के लिए Protobuf अनुपयुक्त tool लगता है
आगे LLM की वजह से अलग-अलग भाषाओं में porting विस्फोटक रूप से बढ़ती दिख सकती है
शीर्षक कुछ हद तक भ्रामक है
असल में बात यह है कि “Protobuf serialization step हटाया तो चीज़ें तेज़ हो गईं”
यह client और server को स्वतंत्र रूप से update होने पर भी काम करने देता है, और कई भाषाओं के बीच communication आसान बनाता है
बड़े systems में ऐसी flexibility बहुत महत्वपूर्ण होती है
वजह Rust नहीं, बल्कि Protobuf को generalized storage format की तरह इस्तेमाल करना हो सकता है
आखिरकार, किसी खास उद्देश्य के लिए चीज़ों को सरल बनाना ही मुख्य बात थी
शीर्षक में Rust डालना clickbait जैसा चुनाव लगता है
pg_query के मूल लेखक ने पृष्ठभूमि समझाई
शुरुआत में pganalyze में Postgres query को parse करके table references ढूँढने, query को rewrite करने और format करने के लिए इसका उपयोग हुआ
पहले JSON इस्तेमाल किया गया, लेकिन बाद में Protobuf में बदला गया ताकि कई भाषाओं (Ruby, Go, Rust, Python आदि) में type-safe binding आसानी से दी जा सके
Rust जैसी भाषाओं के लिए FFI बेहतर है, लेकिन दूसरी भाषाओं में maintenance burden ज़्यादा होता है
वे Lev की कोशिश का समर्थन करते हैं, और आगे libpg_query तक सीधे FFI access देने वाले functions जोड़ने की योजना है
हालांकि जहाँ performance महत्वपूर्ण न हो, वहाँ Protobuf अब भी अधिक सुविधाजनक विकल्प है
“5 गुना तेज़” सुनकर Cap’n Proto के “अनंत गुना तेज़” वाले मज़ाक की याद आती है
शीर्षक बढ़ा-चढ़ाकर कहा गया है, लेकिन असली काम प्रभावशाली है
Protobuf को पूरी तरह हटाया नहीं गया, बल्कि उसके इस्तेमाल के तरीके को optimize किया गया
“X में बदलते ही 5 गुना तेज़ हो गया” जैसी पंक्ति का मतलब अक्सर यह होता है कि “पहले implementation बुरी तरह गड़बड़ थी, उसे ठीक किया गया”
मुख्य सीख यह है
Rust FFI में भी overhead होता है, इसलिए असली उपलब्धि भाषा नहीं बल्कि data flow का redesign और optimization effort है
FlatBuffers तेज़ है, लेकिन Protobuf इस्तेमाल करने का कारण यह है कि उसे बड़ी कंपनियाँ maintain करती हैं
आखिरकार, “Google ने बनाया है इसलिए सुरक्षित है” वाली धारणा का कोई आधार नहीं है
अगर सिर्फ memory sharing और version fields वाला zero-copy structure चाहिए, तो Protobuf का खास कारण नहीं दिखता
Protobuf performance मज़ाक के स्तर की लगती है
serialization लगभग free होने वाले zero-copy formats इस्तेमाल करने चाहिए
उदाहरण के लिए, मेरे बनाए Lite³ की speed FlatBuffers से 242 गुना तेज़ है
Protobuf इस्तेमाल करने के पीछे ecosystem, schema, भाषा-विशिष्ट tooling जैसी कई व्यावहारिक वजहें होती हैं
असल समस्या Rust या Protobuf नहीं, बल्कि PostgreSQL abstraction layer की inefficient serialization implementation थी
pgdog ने उस layer को हटाकर data को सीधे C API में pass किया
गैर-ज़रूरी features हटाने से स्वाभाविक रूप से चीज़ें तेज़ हो जाती हैं
लेकिन कुछ लोगों के लिए अब भी serialization की ज़रूरत रहेगी
ऐसे लोगों के लिए “Rust में बदलो” वाला शीर्षक गलत संदेश देता है
आखिरकार, ज़्यादातर मामलों में JSON काफ़ी है, और अगर सच में अधिक speed चाहिए तो serialization को ही टालना चाहिए
यह अनुचित तुलना है
IPC communication में serialization protocol इस्तेमाल करने पर overhead होना स्वाभाविक है
“20% तेज़ हो तो improvement, 10 गुना तेज़ हो तो मतलब शुरू से गलत बनाया गया था” — यह कहावत यहाँ बिल्कुल फिट बैठती है