9 ms·
Replacing Protobuf with Rust
- nottorp 8mo agoAre they sure it's because Rust? Perhaps if they rewrite Protobuf in Rust it will be as slow as the current implementation. They changed the persistence system completely. Looks like from a generic solution to something specific to what they're carrying across the wire. They could have done it in Lua and it would have been 3x faster.
- consp 8mo agoIf they made the headline something on the line of "replacing protobuf with a native, optimized implementation" would not get the same attention as putting rust in the title to attract the everything-in-rust-is-better crowd.
- desiderantes 8mo agoThat never happens. Instead, it always attracts the opposite group, the Rust complainers, where they go and complain about how "the everything-in-rust-is-better crowd created yet another fake headline to pretend that Rust is the panacea". Which results in a lot of engagement. Old ragebait trick.
- izacus 8mo ago"never" huh?
- DangitBobby 8mo agoPretty much. The tide of rust evangelism has been turned in favor of complainers for a while now. Nothing compared to JS and React hate, but still.
- satvikpendem 8mo agoYep. The Rust Evangelism Strike Force concept has long been dead for at least the past few years. In many aspects, Rust has become the "boring" technology, like Ruby and Rails.
- hu3 8mo agoAt the very least it gets more upvotes.
- timeon 8mo agoWell it is keyword for RSS feeds.
- misja111 8mo agoCorrect, this has very little to do with Rust. But it wouldn't have made the front page without it.
- mkoubaa 8mo agoBingo
- locknitpicker 8mo agoYes you are absolutely right. The article even outright admits that Rust had nothing to do with it. From the article: > Protobuf is fast, but not using Protobuf is faster. The blog post reads like an unserious attempt to repeat a Rust meme.
- alias_neo 8mo agoI was equally confused by the headline. I wonder if it's just poorly worded and they meant to say something like "Replacing Protobuf with some native calls [in Rust]".
- deleted 8mo ago[deleted]
- embedding-shape 8mo agoIt's devbait, not many of us can resist bikeshedding about the title which obviously doesn't accurately reflect the article contents. And the article contents are self-aware enough to admit this to itself too, yet the title remains.
- win311fwg 8mo agoThe title would suggest that it was already written in Rust; that it was the rewrite in Go that brought five times faster.
- IshKebab 8mo agoI vaguely recall that there's a Rust macro to automatically convert recursive functions to iterative. But I would just increase the stack size limit if it ever becomes a problem. As far as I know the only reason it is so small is because of address space exhaustion which only affects 32-bit systems.
- embedding-shape 8mo ago> I vaguely recall that there's a Rust macro to automatically convert recursive functions to iterative. Isn't that just TCO or similar? Usually a part of the compiler/core of the language itself, AFAIK.
- koverstreet 8mo agoI haven't been following become/TCO in Rust - but what I've usually seen is TCO getting flipped off because it interferes with backtraces and debugging. So I think there's value in providing it as an explicit opt-in; that way when you're reading the code, you know to account for it when you're looking at backtraces. Additionally, if you're relying on TCO it might be a major bug if the compiler isn't able to apply it - and optimizations that aren't applied are normally invisible. This might mean you could get an error if you're expecting TCO and you or the compiler screwed something up.
- tialaramex 8mo agoIn a language like Rust where local variables are explicitly destroyed when scope ends a naive TCO is very annoying and `become` also helps fix that. Suppose I have a recursive function f(n: u8) where f(0) is 0 and otherwise f(n) is n * bar(n) + f(n-1) I might well write that with a local temporary to calculate bar(n) and then we do the sum, but this would inhibit TCO because that temporary should exist after we did the recursive calculation, even though it doesn't matter in practice. A compiler could try to cleverly figure out whether it matters and destroy that local temporary earlier then apply TCO, but now your TCO is fragile because a seemingly minor code change might fool that "clever" logic, by ensuring it isn't correct to make this change and breaking your optimisation. The `become` keyword is a claim by the programmer that we can drop all these locals and do TCO. So because the programmer claimed this should work they're giving the compiler permission to attempt the early drop and if it doesn't work and can't be TCO then complain that the program is wrong.
- yodacola 8mo agoFlatBuffers are already faster than that. But that's not why we choose Protobuf. It's because a megacorp maintains it.
- nindalf 8mo agoYou're saying we choose Protobufs [1] because Google maintains it but not FlatBuffers [2]? [1] - https://github.com/protocolbuffers/protobuf https://github.com/protocolbuffers/protobuf: Google's data interchange format [2] - https://github.com/google/flatbuffers https://github.com/google/flatbuffers: Also maintained by Google
- rafaelmn 8mo agoI get the OP is off base with his remark - but at the same time maintained by Google means shit in practice. AFAIK they have a bunch of production infra on protobuff/gRPC - not so sure about flatbufferrs which came out of the game dev side - that's the difference maker to me - which project is actually rooted in.
- dewey 8mo ago> but at the same time maintained by Google means shit in practice. If you worked on Go projects that import Google protobuf / grpc / Kubernetes client libraries you are often reminded of that fact.
- whoevercares 8mo agoFlatbuffers are fine - I think it is used in many places that needs zero-copy. Also outside google, it powers the Arrow format which is the foundation of modern analytics
- dmoy 8mo ago> AFAIK they have a bunch of production infra on protobuff/gRPC Stubby, not gRPC. Stubby is used for almost everything internally. gRPC is a similar-ish looking thing that is open sourced, but not used nearly as much as stubby internally. Stubby predates gRPC by like 15 years or something. > not so sure about flatbufferrs which came out of the game dev side I wouldn't know. I'll be honest, I always forget that Google made flatbuffers. I guess if you're doing a lot of IPC?
- rozenmd 8mo ago"5 times faster" reminds me of Cap'n Proto's claim: in benchmarks, Cap’n Proto is INFINITY TIMES faster than Protocol Buffers: https://capnproto.org/ https://capnproto.org/
- 7777332215 8mo agoIn my experience capn proto is much less ergonomic.
- IshKebab 8mo agoI agree. It might be faster if you don't actually deserialise the data into native structs but then your codebase will be filled with fairly horrific CapnProto C++ code.
- gf000 8mo agoI mean, cap'n'proto is written by the same person who created protobuf, so they are legit (and that somewhat jokish claim is simply that it requires no parsing).
- Sesse__ 8mo ago> I mean, cap'n'proto is written by the same person who created protobuf Notably, Protobuf 2, a rewrite of Protobuf 1. Protobuf 1 was created by Sanjay Ghemawat, I believe.
- 7e 8mo agoGoogle loves to reinvent shit because they didn't understand it. And to get promo. In this case, ASN.1. And protobufs are so inefficient that they drive up latency and datacenter costs, so they were a step backwards. Good job, Sanjay.
- notyourwork 8mo agoReally dismissive and ignorant take from a bystander. Back it up with your delivery that does better instead of shouting with a pitchfork for no reason.
- t-writescode 8mo agoJust for fun, how often do regular-sized companies that deal in regular-sized traffic need Protobuf to accomplish their goals in the first place, compared to JSON or even XML with basic string marshalling?
- tcfhgj 8mo agoWell, protobuf allows to generate easy to use code for parsing defined data and service stubs for many languages and is one of the faster and less bandwidth wasting options
- bluGill 8mo agoIn most languages protobuf is eaiser because it generates the boilerplate. And protobuf is cross language so even if you are working in javascript where json is native protobuf is still faster because the other side can be whatever and you are not spending their time parsing.
- t-writescode 8mo agoIn most languages I’ve worked in, there is no boiler plate for json either, and barely any for XML. You make a data class of some sort and it “just works”. Not having that functionality is a weakness of a language or its support tools at this point, to me.
- jonathanstrange 8mo agoProtobuf is fantastic because it separates the definition from the language. When you make changes, you recompile your definitions to native code and you can be sure it will stay compatible with other languages and implementations.
- speed_spread 8mo agoYou mean like WSDL, OpenAPI and every other schema definition format? Well I agree. Contract-first is great. You provide your clients with the specs and let them generate their own bindings. And as a client they're great too because I can also easily generate a mock server implementation that I can use in tests.
- steeve 8mo agotldr: they replaced using protobuf as the type system across language boundaries for FFI with true FFI
- Xunjin 8mo agoI loved, every clickbait title should come with a tldr just like this one.
- xxs 8mo agoif you see an order of magnitude difference and a language involved in the title, it's something I refuse to read (unless it's an obvious choice - interpret vs compilied/jit one)
- ahartmetz 8mo agoTitle is as nonsensical as "We replaced Windows with ARM CPUs"
- Terretta 8mo agoWe replaced the periodic table with elements for five times the reaction.
- lowdownbutter 8mo agoDon't read clickbaity headlines and scan hacker news five times faster.
- chuckadams 8mo agoBecome a 5X Hacker News reader with this One Weird Trick.
- deleted 8mo ago[deleted]
- cranx 8mo agoI find the title a bit misleading. I think it should be titled It’s Faster to Copy Memory Directly than Send a Protobuf. Which then seems rather obvious that removing a serialization and deserialization step reduces runtime.
- miroljub 8mo agoYep. Just doing memcpy or mmap would be even faster. But the same Rust advocates bragging about Rust speed frown upon such unsecure practices in C/C++.
- MrDarcy 8mo agoTIL serializing a protobuf is only 5 times slower than copying memory, which is way faster than I thought it’d be. Impressive given all the other nice things protobuf offers to development teams.
- nicman23 8mo agothat actually crazy fast
- dietr1ch 8mo agoI guess that number is as good or as bad as you want with the right nesting. Protobuf is likely really close to optimally fast for what it is designed to be, and the flaws and performance losses left are most likely all in the design space, which is why alternatives are a dime a dozen.
- cmrdporcupine 8mo agoI wouldn't hold onto that number as any kind of fixed usable constant since the reality will depend entirely on things like cache locality and concurrency, and the memory bandwidth of the machine you're running on. Go around doing this kind of pointless thing because "it's only 5x slower" is a bad assumption to make.
- jeffbee 8mo agoSerializing a protobuf can be significantly faster than memcpy, depending. If you have a giant vector of small numbers represented with wide types (4-8 bytes in the machine) then the cost of copying them as variable-length symbols can be less.
- deleted 8mo ago[deleted]
- sylware 8mo agoI don't understand, I used protobuf for map data, but it is a hardcore simple format, this is the whole purpose of it. I wrote assembly, memory mapping oriented protobuf software... in assembly, then what? I am allowed to say I am going 1000 times faster than rust now???
- spwa4 8mo agoYou should be terrified of the instability you're introducing to achieve this. Memory sharing between processes is very difficult to keep stable, it is half the reason kernels exist.
- levkk 8mo agoI was terrified until it worked. The Postgres "ABI" is relatively stable - the parser only really changes between major versions and we bake the whole code into the same executable - largely thanks to the work done by team behind pg_query! The output is machine-verifiable, which makes this uniquely possible in today's vibe-coded world!
- linuxftw 8mo agoMany people are exclaiming that the title is baity, but I disagree. It seems like a perfectly fine title in the context of this blog, which is about a specific product. It's unlikely they wrote the blog with a HN submission in mind. They're not a news publication, either.
- deleted 8mo ago[deleted]
- GuB-42 8mo agoWhat I find particularly ironic is that the title make it feel like Rust gives a 5x performance improvement when it actually slows thing down. The problem they have software written in Rust, and they need to use the libpg_query library, that is written in C. Because they can't use the C library directly, they had to use a Rust-to-C binding library, that uses Protobuf for portability reasons. Problem is that it is slow. So what they did is that they wrote their own non-portable but much more optimized Rust-to-C bindings, with the help of a LLM. But had they written their software in C, they wouldn't have needed to do any conversion at all. It means they could have titled the article "How we lowered the performance penalty of using Rust". I don't know much about Rust or libpg_query, but they probably could have gone even faster by getting rid of the conversion entirely. It would most likely have involved major adaptations and some unsafe Rust though. Writing a converter has many advantages: portability, convenience, security, etc... but it has a cost, and ultimately, I think it is a big reason why computers are so fast and apps are so slow. Our machines keep copying, converting, serializing and deserializing things. Note: I have nothing against what they did, quite the opposite, I always appreciate those who care about performance, and what they did is reasonable and effective, good job!
- logicchains 8mo ago> they had to use a Rust-to-C binding library, that uses Protobuf for portability reasons. That sounds like a performance nightmare, putting Protobuf of all things between the language and Postgres, I'm surprised such a library ever got popular.
- formerly_proven 8mo ago> I'm surprised such a library ever got popular. Because it is not popular. pg_query (TFA) has ~1 million downloads, the postgres crate has 11 million downloads and the related tokio-postgres crate has over 33 million downloads. The two postgres crates currently see around 50x as much traffic as the (special-purpose) crate from the article. edit: There is also pq-sys with over 12 million downloads, used by diesel, and sqlx-postgres with over 16 million downloads, used by sqlx.
- unnouinceput 8mo agoQuote: "We forked pg_query.rs and replaced Protobuf with direct C-to-Rust (and back to C) bindings, ...." So it's C actually, not Rust. But Hey! we used Rust somewhere, so let's post it on HN and farm internet points.
- suriya-ganesh 8mo agoThis is an unfair comparison. using a transport serialization and deserialization protocol for IPC. It is obvious why there was an overhead because it was architectural decision to manage the communication. I guess the old adage of if something goes 20% faster something was improved if it is 10x faster, it was just built wrong is true here.
- maherbeg 8mo agoGotta say, I love using PGDog. It has some fantastic built in features, and I'm looking forward to testing out the improved query parser. Lev and the team are heroes. At the scale we were using PGDog, enabling the previous form of the query parser was extremely expensive (we would have had to 16x our pgdog fleet size).
- levkk 8mo agoThat's the experimental feature I was talking about! :) Thank you so much for the kind words!
- chuckhend 8mo agoGreat work Lev!
- levkk 8mo agoThank you!
- eliasdejong 8mo agoPerformance of Protobuf is a joke. Why not use a zero copy format so that serialization is free? For example, my format Lite³ which outperforms Google Flatbuffers by 242x: https://github.com/fastserial/lite3 https://github.com/fastserial/lite3
- tucnak 8mo agoMmmm, I don't know maybe because your library DIDN'T EXIST before November 2025? Or perhaps for any other million reasons why people use Protobuf, and don't use Cap'n'proto and other 0-serialise libraries, like requiring a schema, established tooling for language of their choice, etc?
- 0x457 8mo agoNow and then I find a wild place people shove protobuf in. It's like zero consideration were given sometimes beyond "multiple languages from the same IDL" like it's some magical zero-overhead abstraction over bytes on a wire.
- nemothekid 8mo agoCan someone explain how protobuf ended up in the middle here? I'm just totally confused; the C ABI exists in almost every language, why did they need protobuf here?
- ordu 8mo agoI don't know, but I have a guess. Someone didn't want to deal with unsafety of dealing with memory allocated in C code. Serialize/deserialize makes it easy, no need for unsafe, no need to learn all the quirks of the C-library allocating the memory. I had experience with writing safe bindings to structures created in C library, and it is a real pain. You spend a lot of times reverse engineering C code to get an idea of the intent of those who had wrote the code. You need to know which pointers can address the same memory. You need to know which pointers can be NULL or just plain invalid. You need to know which pointers you get from C code or pass to it along with ownership, and which are just borrowed. It maybe (and often is) unclear from the documentation, so you are going to read a lot of C code, trying to guess what the authors were thinking when writing it. Generating hypotheses about the library behavior (like 'library never does THIS with the pointer') and trying to prove them by finding all the code dealing with the pointer. It can be easy in easy situations, or it can be really tricky and time consuming. So it can make sense to just insert serialization/deserialization to avoid dealing with C code.
- lfittl 8mo agoSince there seems to be some confusion in the comments about why pg_query chose Protobufs in the first place, let me add some context as the original author of pg_query (but not involved with PgDog, though Lev has shared this work by email beforehand). The initial motivation for developing pg_query was for pganalyze, where we use it to parse queries extracted from Postgres, to find the referenced tables, and these days also rewrite and format queries. That use case runs in the background, and as such is much less performance critical. pg_query actually initially used a JSON format for the parse output (AST), but we changed that to Protobuf a few major releases ago, because Protobuf makes it easy to have typed bindings in the different languages we support (Ruby, Go, Rust, Python, etc). Alternatives (e.g. using FFI directly) make sense for Rust, but would require a lot of maintained glue code for other languages. All that said, I'm supportive of Lev's effort here, and we'll add some additional functions (see [0]) in the libpg_query library to make using it directly (i.e. via FFI) easier. But I don't see Protobuf going away, because in non-performance critical cases, it is more ergonomic across the different bindings. [0]: https://github.com/pganalyze/libpg_query/pull/321 https://github.com/pganalyze/libpg_query/pull/321
- jpalepu33 8mo agoThe title is misleading but the actual work is impressive - they optimized their Protobuf usage, not replaced it entirely. This is a common pattern: "We switched to X and got 5x faster" often really means "We fixed our terrible implementation and happened to rewrite it in X." Key lessons from this: 1. Serialization/deserialization is often a hidden bottleneck, especially in microservices where you're doing it constantly 2. The default implementation of any library is rarely optimal for your specific use case 3. Benchmarking before optimization is critical - they identified the actual bottleneck instead of guessing For anyone dealing with Protobuf performance issues, before rewriting: - Use arena allocation to reduce memory allocations - Pool your message objects - Consider if you actually need all the fields you're serializing - Profile the actual hot path Rust FFI has overhead too. The real win here was probably rethinking their data flow and doing the optimization work, not just the language choice.
- rgovostes 8mo agoWhat the hell happened to Protobuf anyway? Go look at their repo; it’s positively byzantine. There are two or three different Python backends.
- ajross 8mo agoSeems like this has nothing to do with Rust or protobufs. The underlying PostgreSQL abstraction engine they'd picked had a wasteful serialization implementation (that happens to have been using protobuf). So pgdog dropped it and open-coded a serialization-free transfer using the C API. Well, yeah. If there's a feature you don't need, you'll see value by coding around it. Some features turn out not to be needed by anyone, maybe this is one. But some people need serialization, and that's what protobufs are for[1]. Those people are very (!) poorly served by headlines telling them to use Rust (!!) instead of serialization. [1] Though as always the standard litany applies: you actually want JSON, and not protobus or ASN.1 or anything else. If you like some other technology better, you're wrong and you actually want JSON. If you think you need something faster, you probably don't and JSON would suit your needs better. If you really, 100%, know for sure that you need it faster than JSON, then you're probably isomorphic to the folks in the linked article, shouldn't have been serializing at all, and should get to work open coding your own hooks on the raw backend.
- ruicraveiro 8mo agoI don't understand the title. Replacing a serialization format with a language? Makes no sense.
- up2isomorphism 8mo agoYou replace protobuff with a different protocol which is implemented in rust. You can not replace your food with a soap.