12 ms·
The state of gRPC in the browser
- baron816 8y agoAnother team at my company developed a microservice that uses gRPC that my team depends on and it’s been an absolute nightmare. Protobufs are just too limited in what they can do to make them useful except in very specific, narrow cases.
- lima 8y agoWhat kind of limits are you seeing?
- cphoover 8y agoI'm also curious
- dekhn 8y agoreally? I mean besides the fact that nearly every message across Google is protobuf-encoded (with a fairly rich schema), protobufs are general enough to encode any message within them (you could use it to just pass bytes around), it's hard to see why this would be true. Can you be more specific?
- scarmig 8y agoThat's surprising, since Google uses protobufs very (very!) extensively internally, and it'd have to be a very exotic use case for protobufs not to be useful. Which isn't to say they're the be-all-end-all, but I'd be curious to hear your use case.
- com2kid 8y agoI haven't looked into gRPC at all, but I know for a fact that Protobufs can do whatever is needed in regards to serializing data. Being limited to types that Java supports is a huge limiting factor for some use cases, thankfully there are extensions to the spec to get around these limitations (but then you have to use libraries that all supports the same extensions, and that limits your choices, so yes this can become an issue!) On the flip side, compared to JSON with its anemic type support, Protobufs looks great! Of course at the end of the day, a huge % of apps have to talk to the web browser, so everything gets dumbed down to strings and doubles. :(
- ninkendo 8y ago> compared to JSON with its anemic type support Am I the only one who wants to keep serialization as far from my type system as possible? I want to have my internal data model for my software, and when I want to serialize it, I should be able to do it in any number of different ways (redacting values, using HATEOAS links for REST routes, using a lossless format for storage) depending on the situation. Protobuf couples data modeling and data serialization into a single inseparable concern, and it becomes difficult to do anything else once you start using it.
- com2kid 8y agoIt is a performance trade off. Sure you can use JSON and make everything strings and do something like { type: 'int8', value: '52' } but then parsing out the data ends up being a huge overhead. I once saw an XML variant of this, where someone decided to make the ultimate Distributed Computing System and serialize every single function call, take up over 1/2 of a CPU core for de/serialization for just the one app running on that machine. While I could admire the purity of the design, it was utterly insane as an actual thing to bring into the world. Protobuf is a good mixture of "strict typing so everyone is on the same page", "freedom to do stuff", and "perf isn't horrible." There are other encoding systems out there that offer even more freedom, e.g. cap'n'proto, and better performance, but with other trade offs. On the opposite side of things, my team had been serializing straight C structs out over the wire, but every field addition was a breaking change, and communicating the changes to our structures across teams was a nightmare of meetings and "has your team merged the changes Bob made so we can roll out our new format yet?" We needed 3 teams to roll out changes at the same time! With protobufs, we were able to make changes to our wire format incredibly rapidly, we had a nice source control managed asset that defined our format, there weren't any confusions as to how data was laid out, and clients using older versions of our definitions just missed out on newer features, nothing actually broke. It was an insanely large improvement, and honestly for the managed platforms, the performance wasn't appreciably worse than trying to convince Java to read in uint8s and write out uint8s. My team was working on an embedded platform with RAM measured in kilobytes, and it was worth us eating the overhead just to get rid of the countless meetings we had to hold whenever we made a change to any of our structures.
- baron816 8y agoIt’s the repeated/oneof issue that’s causing me problems right now.
- CobrastanJorji 8y agoYou mean like: repeated oneof actions { ActionTypeOne type_one; ActionTypeTwo type_two; } or like: oneof thingy { repeated string first_option; string second_option; } I can see why you'd want to do either of those things, but it doesn't seem like a huge deal to me to wrap those in another message.
- ssambros 8y agooneof thingy { repeated string first_option; string second_option; } Not the most beautiful solution, but I've seen it in production and it works fine.
- aoeusnth1 8y agoAnd why can't you wrap it in another message?
- cgdub 8y agoCan you go into detail on this? Perhaps you would prefer something like Ion: https://amzn.github.io/ion-docs/guides/why.html https://amzn.github.io/ion-docs/guides/why.html
- deleted 8y ago[deleted]
- DrScientist 8y agoI'm excited this as an option in the toolbox.
- lima 8y agoMy team has been using gRPC + Improbable's grpc-web [0] + Typescript for a green field project and it has been amazing. - Typing all the way to the frontend. - gRPC/protobuf forces you to describe your interfaces and are self-documenting. - gRPC semantics like error codes and deadlines (if you propagate them through your stack, they're particularly useful - for instance, we cancel database transactions across service boundaries if a request times out). - Performance is great (but we're far from seeing bottlenecks with JSON, it's not the reason we choose gRPC). - We use grpc-gateway which auto-generates a REST proxy for our customers. We sometimes use it for interactive debugging. [1] - Rather than importing database models for our management tools and one-off scripts, using the API is so frictionless that we even use it inside our backend code and for CLI utilities. The Google API design guide is helpful: https://cloud.google.com/apis/design https://cloud.google.com/apis/design One piece of advice: Treat your gRPC calls like you would treat a GraphQL resolver - if you squint your eyes, they're very similar concepts. Rather than specifying a GraphQL query, you specify a Field Mask. https://developers.google.com/protocol-buffers/docs/reference/csharp/class/google/protobuf/well-known-types/field-mask https://developers.google.com/protocol-buffers/docs/referenc... Happy to answer questions on our experience. [0]: https://github.com/improbable-eng/grpc-web https://github.com/improbable-eng/grpc-web [1]: https://github.com/grpc-ecosystem/grpc-gateway https://github.com/grpc-ecosystem/grpc-gateway
- eberkund 8y agoIs it still necessary to use a REST proxy when using protobuf from the browser?
- lima 8y agoNo - it's just there for customers who want a REST API. We don't use it outside of tests and development.
- jonahss 8y agoWere you able to find a good javascript or typescript gRPC client? The official google one seemed to have spotty documentation for the js module itself. It did not look like it supported promises or Nodejs streams either.
- deleted 8y ago[deleted]
- rhacker 8y agoWe built out our gRPC services starting about 8 months ago. I pounded my fists on the gRPC-web issue board a bunch of times. Things started moving. In the end, it was too little and the effort is too divided. Also the route for which they wanted to implement streaming was, personally, poorly designed. We have since switched to GraphQL and haven't looked back.
- sonnyblarney 8y agoWe are looking at this as well. Can I ask a question? Seems GraphQL and gRPC are to some extent complementary: one is graph/data oriented, the other more functional/service oriented. I know GQL has it's own ideas about transport, but would it make any sense at all to actually put GQP over gRPC? And by that I mean to have some gRPC services pass GQL requests as parameters? Or have I misunderstood entirely?
- Stoids 8y agoGQL and gRPC are absolutely complementary. Having resolvers fan out to gRPC-backed microservices has been great at our company. We initially used protos for all of our service contracts (including server <-> web UI communication). While this was nice for all the reasons other people have stated, protos kinda ended up sucking to work with on the front-end. Protos are a serialization contract and should remain such. Too much proto-specific logic ended up bleeding into our web codebase (dealing with oneofs, enums, etc). GQL's IDL on the other hand ended up being a perfect middle-ground. It gave us a nice layer to deal with that serialization specific stuff, while letting the front-end work with better data models (interfaces, unions, string enums, etc.). GQL's IDL and TypeScript are a great match, since GQL types are ultimately just discriminated unions, which TS handles like a charm.
- heavenlyhash 8y agoCan you comment more about your comparative experiences with "logic bleed"? I find this fascinating, because it seems that a lot of the bleed should be the same (isn't 'oneof' roughly equivalent to 'union'?)... but it sounds like something is different in practice, and I'd really like to understand what the root cause of the difference is.
- inputdev 8y agoI've had issues with npm and binaries of gRPC in firebase related to node versions and electron versions. It seems like this could be a good alternative if it was used in firebase since it's implemented in typescript - not sure I completely understand it, though.
- maxpert 8y agoWeb has come a full circle. First we disgust and hate SOAP XML and friends. Then we go to REST and realize of it's too loose! Then we invent stuff like Swagger and JSONAPI in order to put some interfacing in place. And then we bring in cripples that give similar but water downed features of SOAP, GRPC, GraphQL and more friends. Edit: I know I might get downvotes but think for a second we could have just taken some good parts from SOAP to begin with and have all the goodness.
- lima 8y agoYes, it has come full circle - but SOAP XML and friends were rightfully despised. The spec is a mess and there are so many broken implementations all over the place. I have fond memories of debugging the PHP SOAP client in order to build a bug-by-bug compatible Python version :-) gRPC and other modern RPC protocols/SOA frameworks are basically "the good parts from SOAP".
- vbezhenar 8y agoI feel that the difference is that SOAP was a proper spec made by multiple parties, for better or worse. And GRPC is just a published spec from Google with code from Google. Of course it won't be such a mess and it will be good enough. Is it good to rely on Google adopting its tech as an industry standard? That's a philosophical question.
- thisgoodlife 8y agoI personally use this rule to decide whether I should use a Google service/library: it has to have more than 1 billion active users or it's an important part of such services. gRpc more specifically protobuf, imo, is very important to Google. So I won't be worried about its future.
- skybrian 8y agoFrom a philosophical point of view, it seems like a design critique should be focused more on the design and less about where it came from? (Assuming it's open source and there aren't intellectual property issues.) Industry standards tend to take on a life of their own, even if they came from one company. (Consider Docker.)
- continuations 8y agoWhat's the advantage of using this over something like XMLHttpRequest?
- darkhorn 8y agoXMLHttpRequest does not have a remote procedure call (RPC).
- continuations 8y agoI meant what's the advantage of using RPC instead of XMLHttpRequest to communicate with the server.
- skybrian 8y agoWell, XMLHttpRequest alone doesn't cover much so you're really comparing with HTTP requests combined with JSON and whatever you use to document your JSON API. The advantage of protobufs is basically static typing with backward-compatible serialization (you can add new fields), that's compatible with many server-side languages. It's honestly an awkward fit for web apps, though. Basic things are different, like int64's aren't native to JavaScript.
- timdorr 8y agoXHR is really just an HTTP client, despite the name. It doesn't enforce anything regarding inputs and outputs of an HTTP request. gRPC gives you guarantees on those inputs and outputs, along with a bunch of extra features. It's basically a layer on top of XHR.
- pcj-github 8y agogrpc-web indeed does use XMLHttpRequest internally to make the request to the server. Main advantage is type-safety of the overall communication protocol and some efficiency gains. Cannot be stated strongly enough how important compile-time type-safety guarantees between client and server is (particularly in a "microservices" environment where everything is disconnected at runtime); eliminates an entire class of bugs, frees developers to focus on more business-relevant tasks rather than worrying about serialization.
- vbezhenar 8y agoI'm surprised that streaming is not implemented for web client. Streaming seems to be a huge feature for gRPC. Why does it take so long?
- SlowRobotAhead 8y agoSlight off topic, but has anyone executed gRPC on a C platform for embedded? I'm willing for forgo the automatic code generation - but hell if there are any good resources I've been able to find on this.
- Matthias247 8y agoWith embedded platform you mean microcontroller with RTOS? Afaik there are no suitable implementations yet. It will generally be pretty hard to build something like this, since grpc requires HTTP/2, and that is hard to implement with no dynamic allocations and a low amount of memory. E.g. each substream requires a minimum amount of buffering, there is header decompression, etc. For pure protobuf communication on embedded systems nanopb works fine. If one doesn't need concurrent streams, HTTP/1.1 or coap plus nanopb encoded payloads work fairly well.
- SlowRobotAhead 8y agoThe problem I have with nanoPB, is that the RPC comm between the app over BLE and the server over http is entirely up to me. There are no suggestions, standards, or even great examples of what the pb should contain and how it gets processed at each location. It almost becomes RESTful where I have a proto that has a request field, response field, and all the optional fields for both, when the server or app sees one of these I need all custom implementation to decide what to do with these ‘states’. It seems wrong and complex to make it all arbitrarily handled at each of three places. NanoPB is excellent. But it’s the handling of the data (calls, req/res, timeouts, errors, formats, patterns) that I wish there was something for. And yea, you got it right that with no HTTP layer it wouldn’t be gRPC on the device. But my app and server could still use that, if only the device could process the intention of the gRPC format changes / extensions.
- helipaddi 8y agoCould someone explain the difference between gRPC and Apache Thrift? Even tough the Apache Thrift project is not as active as gRPC it works quite well for us.
- anderspitman 8y agoI think they're rather similar in goals. I found this overview informative: https://youtu.be/RoXT_Rkg8LA https://youtu.be/RoXT_Rkg8LA
- throaaway1984 8y agogRPC is protocol agnostic. You can use any wire type with it, like JSON. There's even a codec for thrift messages on gRPC called grift.
- q3k 8y agoThrift is what xooglers at Facebook implemented when they wanted Stubby. grpc is Google's own open source edition of Stubby. They are very similar paradigm-wise.
- jholman 8y agoWait, what? IIRC Stubby is a lockserver, used for two things: coordinated locks, and small coordinated data. You mean protobuff, don't you? Am I misremembering and/or wrong?
- deklerk 8y agoYou're thinking of chubby. :) https://ai.google/research/pubs/pub27897 https://ai.google/research/pubs/pub27897
- Matthias247 8y agoThe main difference: grpc can do bidirectional streaming, and not only request-response RPC.
- anderspitman 8y agoI'm quite surprised they're not using websockets for streaming. Anyone know why? EDIT: Better question: is anyone aware of a system like gRPC but built with bidirectional streaming for the browser from the beginning?
- lima 8y agoImprobable's client does have experimental websocket streaming.
- throaaway1984 8y agoWebsockets have head-of-line blocking, which is one of the main reasons HTTP/2 exists. HTTP/2 (i.e. gRPC) is a bidirectional streaming protocol, and you can use the fetch API in JS to use it. The reason gRPC-web exists is because browsers artificially hide some of the headers, which have been part of the HTTP standard since the beginning. If that was fixed, gRPC would just be plain XHR or fetch requests and gRPC-web would go away.
- jbrandhorst 8y agoI'm the author of this blog post and one of the maintainers of the Improbable grpc-web implementation. I don't explicitly mention it in the post, but no browser has support for fetch request streaming yet, so true bidirectionality would not be possible even if you had control over the headers. This will come eventually, and then grpc-web will have proper bi-di streaming support. It is doubtful whether it will actually have access to raw HTTP/2 frames which would be required for the gRPC HTTP/2 protocol.
- anderspitman 8y agoCorrect me if I'm wrong, but my understanding is that HTTP/2 only half solves the head of line blocking problem. It's true that you don't have message-level blocking like websockets, but it's still TCP so streams can block each other if there's packet loss. QUIC seems like the full solution. Also, is head of line blocking really that big of a problem for RPC? It only seems to really be a big deal if your latency tolerance is really tight.
- 8y ago
- gregwebs 8y agoI am using the HTTP Gateway and generating OpenAPI from that for type-safe access [1]. The main downside is that this introduces an additional build step in your project and a small amount of additional run-time processing. The upside is supporting a JSON API and not requiring gPRC(-Web) for clients. Even for non-browser clients, GRPC tooling can still be heavy-weight to pull into your project. Not all languages have easy to use OpenAPI integration, but any language can always just send some JSON. But with the HTTP Gateway you are actually supporting both, so a browser client can still use GRPC-Web if it is able. [1] https://github.com/gogo/grpc-example https://github.com/gogo/grpc-example
- jbrandhorst 8y agoHi, I'm the author of this blog post _and_ the author of this repository - so happy to hear you're finding it useful! I agree that the grpc-gateway is very useful still, but for greenfield projects I think it would be useful to consider the grpc-web on its own merits. I see the grpc-gateway as a way to integrate gRPC into existing environments.
- keymone 8y ago> An efficient JSON-like message encoding how is this still "the future"?
- platform 8y agoOne other that helps JSON/REST to remain defacto these days, is not just a web browser support. But also nice mobile clients like Retrofit. Retrofit seamlessly converts JSON data by means of json de-serializer, into Java classes. So we get typefull semantic (but, albeit at run time only). I have retrofit integrated with RxJava, and when I looked what it would take to 'plugin' gRPC, I found that I have to change not just my backend, but all the wiring for the mobile frontends. And, at the time it looked like too much work. If Retrofit, would make it transparent JSON vs gRPC -- then it would be great for folks that already invested into Retrofit/JSON.
- hardwaresofton 8y agogRPC is two things to me (please correct me if I'm forgetting something): - A specification language for services and the RPC calls they take (except RPC response primitives include single message and stream) - A binary object definition/packing scheme (aka protobuf) Outside of the HTTP and what HTTP/2 makes possible, I feel vaguely like everyone is rushing to replace pure HTTP/HTTP2 (and HTTP3 in the future) with something that is less extensible and could be implemented inside HTTP for the most part. Obviously you can't do anything about the inefficiencies of headers in HTTP/1 (this is better in HTTP/2 & 3), the lack of built-in stream semantics (again only HTTP/1 though you can make do with some longpolling/SSE/websockets scheme) but outside of the HTTP stuff you can absolutely transmit your content as a stream of tightly packed bytes and let consumers do whatever they need to... Why is gRPC anything more than a content type? It's so weird to see gRPC evolve from (in some sense, I might be wrong) HTTP + HTTP/2, and now people trying to shoe horn it back into the browser. It's really hard to find metrics (maybe I should do a comparison and post results I guess), but like in this SO post[0]. The hype train is presenting gRPC as the next thing, but it shouldn't be, IMO. Most of the improvement is from use of protobuf for more efficient (de)serialization -- and I don't think gRPC is the best tool for declaring API schemas (RPC or otherwise) either. [0]: https://stackoverflow.com/questions/44877606/is-grpchttp-2-faster-than-rest-with-http-2 https://stackoverflow.com/questions/44877606/is-grpchttp-2-f...
- Matthias247 8y agoI think what you describe is the shortcoming of the initial grpc spec. It was for some reason decided to define it on top of features which are barely implemented outside of HTTP/2 and special libraries (especially: Trailers). But it would have been possible to just define things on top of common HTTP semantics. This is what grpc-web now fixes according to my understanding. I think even streaming should have been possible with HTTP/1.1. Bodies can be streamed there just fine, if libraries support it (for browsers the issue was up to now that the APIs don't support access to bodies as streams). The only thing I'm not sure if there is an issue in HTTP/1.1 with request streams still running while the response stream has already finished.
- hardwaresofton 8y ago
- 013a 8y agoThe state of gRPC on the browser is the main reason why my company selected Twirp instead. Being able to natively call a simple HTTP endpoint with a JSON payload is fantastic; its the benefits of protobufs when you can use it, with a graceful fallback for clients that need normal HTTP. Of course you can get this with grpc-gateway, but now you have two things to maintain.
- blixt 8y agoHas anyone considered using this or something else for IPC – that is, communicating between memory boundaries in the same application (e.g., Node/web, Swift or C# to a web container, etc.)? Even just for Electron the built in IPC API doesn’t really cut it long term since you don’t get typing nor proper request/response or topic based streaming support so bugs are more likely to sneak in.
- deleted 8y ago[deleted]