Hacker News new | ask | show | jobs
by leetharris 720 days ago
> At any rate just use JSON with WebSockets. Its stupid simple and still 7-8x faster than HTTP with far less administrative overhead than either HTTP or gRPC.

gRPC is not supposed to be a standard web communication layer.

There are times where you need a binary format and extremely fast serialization/deserialization. Video games are one example where binary formats are greatly preferred over JSON.

But I do agree that people keep trying to shove gRPC (or similar) into things where they aren't needed.

4 comments

> gRPC is not supposed to be a standard web communication layer.

It kind of is. What do you think WebTransport in HTTP/3 is? It's basically gRPC Next. The only reason gRPC didn't make it as the standard web communication layer is because of one disastrous decision by one Chrome engineer in https://issues.chromium.org/issues/40388906, maybe because he woke up on the wrong side of the bed.

Can you expand on this a little? I could not work out the decision from the Chrome issue you linked to.
I think this blog post provides the context for that chromium discussion:

https://carlmastrangelo.com/blog/why-does-grpc-insist-on-tra...

(Somewhere in the middle of the article)

gRPC is meant for backend microservices among other things, and it's still painful for that for the reasons the article describes, all of which could've been fixed or avoided. Internally Google doesn't even use gRPC, they use something similar that has better internal support according to https://news.ycombinator.com/item?id=17690676

I also don't see what'd stop it from being used generally for websites calling the backend API. Even if you don't care about the efficiency (which is likely), it'd be nice to get API definitions built in instead of having to set up OpenAPI.

> Internally Google doesn't even use gRPC, they use something similar that has better internal support according to https://news.ycombinator.com/item?id=17690676

But that says that they do use gRPC internally on projects that are new enough to have been able to adopt it?

In 2018, there was some kind of push towards gRPC internally, but it was since abandoned and reversed among the few who actually switched. They still don't use it internally, only externally in some places.
So, wrong link?
That's great, but protobufs is slow as shit. I wouldnt use it in games.

If I was using something slow that needed flexibility I'd probably go with Avro since it has more powerful scheme evolution.

If I wanted fast I'd probably use SBE or Flatbuffers (although FB is also slow to serialise)

Depending on the use case, it's often better to just copy structs directly, with maybe some care for endianness (little-endian). But at this point, the two most popular platforms, ARM and x86, agree on endianness and most alignment.

There's almost no reason why RPC should not just be

  send(sk, (void *)&mystruct, sizeof(struct mystructtype), 0)
Do all of your platforms have the same word width? The same -fshort-enums settings? Do you know that none of your data structures include pointers? Do all of your systems use the same compiler? Compiler version?

I agree it will usually work, but this becomes an ABI concern, and it's surprisingly common to have ABI mismatches on one platform with the items I've noted above.

I've seen wire protocols that had junk for the alignment buffering in such structs. And I've seen people have to do a whole lot of work to make the wire protocol work on a newer compiler/platform. Also, the whole point of a network protocol being documented is that it decouples the interface (msgs over a network) from the implementation (parsing and acting on msgs). Your v1 server might be able to just copy the read buffer into a struct, but your v2 server won't. And it is possible and desirable to live in a world where you can change your implementation but leave your interface alone (although some parts of the software ecosystem seem to not know this nice fact and implicitly fight against realizing it).

My issue with gRPC is simple, the Go gRPC server code does a lot of allocations. I have a gRPC service where each container does 50-80K/second of incoming calls and I spend a ton of time in GC and in allocating headers for all the msgs. I have a similar REST service where I use fasthttp with 0 allocs (but all the stupidly high number of connections due to the lack of multiplexing thru the connection).

Go's GC wasn't really made with throughput maximization in mind. It's a language that doesn't scale that well to take advantage of beefy nodes and has weak compiler. I suppose the Google's vision for it is to "crank the replica count up". gRPC servers based on top of ASP.NET Core, Java Vert.X and Rust Thruster will provide you with much higher throughput on multi-core nodes.

https://github.com/LesnyRumcajs/grpc_bench/discussions/441

Ignoring the incompatibilities in word size, endianness, etc, how does a Go or JavaScript or etc program on the receiving end know what `mystruct` is? What if you want to send string, list, map, etc data?
string, list, map, etc? You have to use an encoding scheme.

As for go / javascript? I think most languages have the ability to inspect a raw buffer.

> string, list, map, etc? You have to use an encoding scheme.

Yes, you have to use an encoding scheme like JSON or Protobufs. Dumping memory directly down the pipe as you're suggesting doesn't work.

> As for go / javascript? I think most languages have the ability to inspect a raw buffer.

No language has the ability to read a raw buffer and know what the contents are supposed to mean. There needs to be a protocol for decoding the data, for example JSON or Protobufs.

Won't work if your struct has any pointers in it.
I'd recommend not doing that then. Of course the same is true if you coerce a pointer to an int64 and store it in a protobuf.
It's not the pointers themselves so much as what they're typically used for. How would you do dynamic sizing? Imagine sending just a struct of integer arrays this way, you'd have to either know their sizes ahead of time or just be ok with sending a lot of empty bits up to some max size. And recursive structures would be impossible.

You could get around this with a ton of effort around serdes, but it'd amount to reinventing ASN1 or Protobuf.

A lot of protocols in low latency trading systems just have fixed maximum size strings and will right pad with NUL or ASCII space characters.

Packed structs with fixed size fields, little endian integers and fixed point is heaven to work with.

I can see that in niche situations, particularly if you have a flat structure and uniform hardware. Cap'n Proto is also a way to do zero-parsing, but it has other costs.