23 ms·
Twirp: A new RPC framework for Go
- rguzman 9y agothis looks really sweet. i've never understood why gRPC limits itself to protobufs only when the protobufs have a canonical json representation. i'm glad that twirp is fixing that piece.
- spenczar5 9y agoYes! In theory, gRPC has a way to pick custom serializers... but in practice, they are pretty clumsy to use and don't seem very well supported. There's a lot more benefit when you can guarantee that all servers will support JSON, too.
- cyrusaf 9y agoHTTP 1.1 + json support for twirp opens up a lot of doors too. It's easy for the browser to natively hit a twirp service without the need for large packages such as https://github.com/improbable-eng/grpc-web https://github.com/improbable-eng/grpc-web.
- puzzle 9y agoYou can use gRPC with FlatBuffers, too. https://grpc.io/blog/flatbuffers https://grpc.io/blog/flatbuffers
- gipp 9y agoOn GCP, Cloud Endpoints proxies will transparently translate back and forth between protobufs and the canonical JSON, allowing either representation to be used. So if you're on GCP and don't care about vendor lock-in, that's a solution.
- buckhx 9y agoThere is also the grpc-gateway project for JSON transcoding https://github.com/grpc-ecosystem/grpc-gateway https://github.com/grpc-ecosystem/grpc-gateway
- puzzle 9y agoTo be fair, if you chose gRPC for performance, but then end up using JSON for most of your traffic, perhaps you picked the wrong tool.
- gipp 9y agoI don't think generally people want to have JSON accepted to use in their production workloads. More for development, testing, that kind of thing. Being able to just curl your service makes a huge difference.
- puzzle 9y agoIt always starts that way, then people demand JSON everywhere ("why not?"), then they complain when things get too slow or when the OOMs begin to appear. :-)
- tothemario 9y agoawesome! a lot easier to integrate than gRPC. It will be way more useful after other languages are supported
- ghayes 9y agoI wrote a similar library to this called Hyperbuffs[0] in Elixir. The goal of the project is to document and build your endpoints using protobufs, but to allow the caller to choose either protobuf or JSON encoding for content and accept types. [0] https://github.com/hayesgm/hyperbuffs https://github.com/hayesgm/hyperbuffs
- sliken 9y agoLooks nice. Can anyone comment on how auth works with Twirp? I was trying to get GRPC working to authenticate with unsigned ssl certs (much like using SSH) and was rather disappointed how awkward it was. Basically two completely different methods requiring hiding session ID in two unrelated places just to allow a SSL cert to control authentication. Anyone done similar with Twirp?
- spenczar5 9y agoYep, you can do this pretty easily because Twirp's generated objects plug in nicely to the normal `net/http` tools. The server is a `http.Handler`, and the client constructor takes a `http.Client`. So if you're familiar with how to use SSL certs for authentication with a vanilla Go HTTP client and server, Twirp would work in exactly the same way. When you create a Twirp server, you get a `net/http.Handler`. You can mount it on a `http.Server` with its `TLSConfig` field set to the right policy. The client constructor similarly takes a `*net/http.Client`. You could provide a Client that uses a `http.Transport` with its `TLSClientConfig` field set to something using the right value (like in https://gist.github.com/michaljemala/d6f4e01c4834bf47a9c4 https://gist.github.com/michaljemala/d6f4e01c4834bf47a9c4, say).
- spenczar5 9y agoHey everyone! I'm the OP and primary author of Twirp. I'm happy to answer any questions and hear feedback. You can also reach me directly, if you like, email is in my profile.
- bradrydzewski 9y agoThanks for posting! Does Twirp use a single HTTP request per call, or does it use a persistent connection similar to the net/rpc package? If the latter, does it provide options for heartbeat, reconnect and retry? EDIT: the blog post covers this in the protocol section. Every request is a POST :)
- spenczar5 9y agoIt's one HTTP request per call, but requests usually flow over a persistent connection in HTTP 1.1 - it's certainly not re-opening a connection for every request. TCP reconnection and stuff like that is at a lower level than Twirp. When you make a client of a Twirp service, the constructor accepts a http.Client which it'll use to send the requests. http.Client has a "Transport" field which is responsible for opening connections, that sort of thing. The Go standard library's defaults are pretty good, but you can tune it as you like.
- tschellenbach 9y agoThanks for posting! How did you work around issues with GRPC on AWS/ELB?
- SEJeff 9y agoLooks like the website got a HN hug of death and isn't really loading for me whatsoever.
- dayjah 9y agoUnlikely? It's hosted on medium - I'm pretty sure they can handle the load. However here is the cached version: https://webcache.googleusercontent.com/search?q=cache:6vYOM9EjSsAJ:https://blog.twitch.tv/twirp-a-sweet-new-rpc-framework-for-go-5f2febbf35f+&cd=1&hl=en&ct=clnk&gl=us https://webcache.googleusercontent.com/search?q=cache:6vYOM9...
- warent 9y agoMust just be your network. I would be surprised if HN traffic could bring down Medium
- warent 9y agoReally excited about this. I didn't like how opaque and heavy gRPC is. Also I really wanted support for JSON. Mostly for these reasons, RCP hasn't been implemented in my architecture yet (Just using standard REST) Twirp is everything I wanted in an RPC framework and I'm looking forward to implementing it ASAP. Thanks Twitch team :)
- jadeklerk 9y agoCan I ask why you want JSON with gRPC? The benefits to protobuf are tremendous, with little to no downsides
- johnbellone 9y agoWe ran into problems where we had embedded Ruby and Python interpreters (Chef/SaltStack) that made it a big pain to ship new libraries. It was much easier to use the grpc-gateway (HTTP/JSON) for those clients and the generated grpc bindings (HTTP2/proto) for services.
- kjksf 9y agoOne reason is to be able to call gRPC service from a web browser. Native JSON support makes that much easier.
- johnbellone 9y agoThere has recently been a lot of work for native grpc client in the browser. It’s not fully there yet but is looking real promising! https://github.com/improbable-eng/grpc-web https://github.com/improbable-eng/grpc-web
- weitzj 9y agoAlso grpc web is coming along https://github.com/grpc/grpc-web https://github.com/grpc/grpc-web
- 9y ago
- ben_jones 9y agoThis is a pretty awesome project. The one thing that's missing would be autogenerated javascript/typescript stubs like grpc-web does. Will definitely experiment with this when building small go applications.
- cyrusaf 9y agoHopefully these will be implemented soon by the community. Open source rules :)
- lobster_johnson 9y agoThis looks promising! We use the go-grpc SDK in conjunction with gogoprotobuf, and it's been a rocky road. While the article identifies some operational issues (e.g. the reliance on HTTP/2), there are several considerable deficiencies with gRPC today, at least when using it with Go: 1. The JSON mapping (jsonpb.go) is clumsy at best, and by this I mean that it produces JSON that often doesn't look anything like how you'd hand-design your structures. "oneof" structs, for example, generate an additional level of indirection that you typically wouldn't have. Proto3's decision to forego Proto2's optional values (in Proto3 everything is optional) cause Go's zero value semantics to leak into gRPC [1]. (We had to fork jsonpb.go to fix some of these issues, but as far as I can tell, upstream is still very awkward.) 2. The Go code generator usually produces highly unidiomatic Go. "oneof" is yet again an offender here. The gogoprotobuf [2] project tries to fix some of go-grpc's deficiencies, but it's still not sufficient. Ideally you should be able to use the Proto structs directly, but our biggest gRPC project we basically gave up here, and decided to limit Proto usage to the server layer, with a translation layer in between that translates all the Proto structs to/from native structs. That keeps things clean, but it's pretty exhausting work, which lots of type switches (which are hampered by Go's lack of switch exhaustiveness checking; we use BurntSushi's go-sumtype [3] a lot, but I don't think it can work for Proto structs, as it requires that a struct also implements an interface). 3. Proto3 has very limited support for expressing "free-form" data. By this I mean if you need to express a Protobuf field that contains a structured set of data such as {"foo": {"bar": 42}}. For this, you have the extension google.protobuf.Value [4], which supports some basic primitives, but not all (no timestamps, for example) and cannot be used to serialize actual gRPC messages; you can't serialize {"foo": MyProtoMessage{...}}. Free-form structured data is important for systems that accept foreign data where the schema isn't known; for example, a system that indexes analytics data. From what I can tell, though, Twirp doesn't "disrupt" gRPC as much as I'd like, since it appears to rely on the existing JSON mapping. [1] https://github.com/gogo/protobuf/issues/218 https://github.com/gogo/protobuf/issues/218 [2] https://github.com/gogo/protobuf https://github.com/gogo/protobuf [3] https://github.com/BurntSushi/go-sumtype https://github.com/BurntSushi/go-sumtype [4] https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Value https://developers.google.com/protocol-buffers/docs/referenc...
- 9y ago
- joshuak 9y agoI think the work the gRPC contributors are doing is great, including all the features. But I can't emphasize enough how important it is for projects like this that take great ideas to a new level by prioritizing simplicity. It's like one project brainstorms great ideas by not being too resistant to new ones (the "yes, and..." rule), while the other refines the ideas with a focus on simplicity to extract the greatest value for the cost. Great work.
- ww520 9y agoIs Thrift supported in Go?
- jadeklerk 9y agoNot fully https://thrift.apache.org/docs/Languages https://thrift.apache.org/docs/Languages
- anonacct37 9y agoAny performance numbers?
- spenczar5 9y agoIt's really hard to write benchmarks of an RPC system that mean much, but the overhead is really just in serialization. We have services that handle tens of thousands of requests per second on Twirp in one process. Serialization/deserialization of a typical protobuf struct takes a microsecond or two, but it generates some garbage, so GC ends up slowing you down if you try to go really crazy and push past 100k req/s in one process with non-trivial message structures.
- anonacct37 9y agoThanks, that's the exact info I was looking for. I've unfortunately been bitten before by choosing json as a serialization format, specifically in go, due to JSON performance dominating processing. No criticism though, JSON is the right choice for many types of APIs.
- spenczar5 9y agoYou can and should use Twirp's protobuf serialization instead for almost all applications. The JSON serialization is really intended for developers and low-throughput cross-language clients. Protobuf serialization isn't free, but it's definitely cheaper than JSON serialization.
- kodablah 9y agoWhat could make this really take off is an in-browser JS client. The simplicity it has added seems to really help there. The gRPC team has had one in hiding for a long time only giving people access who explicitly ask: https://github.com/grpc/grpc/issues/8682 https://github.com/grpc/grpc/issues/8682 (good thing GitHub has a feature that snips hundreds of comments or that link would take a while to load)
- spenczar5 9y agoTotally agree, and it's something I'd love to see. Consider this a call for contributors - I think a simple generated javascript client would be an excellent way to help with the project.
- lykr0n 9y agoWhy use HTTP for transport instead of Messagepack or ZMQ? Seems a bit overkill if you are whipping binary data back and forth between services. Protobuf + ZMQ seems a lot more efficient to me.
- mentat 9y agoA lot of this boils down to wanting to be able to use standard load balancers.
- grogenaut 9y agoAbsolute throughput or efficiency isn't the goal of most RPC mechanisms, twirp specifically. However I don't think it's underperformant either. It's very easy to reason about, and debug, plays with ELBs well, and most important, gets developers thinking at a Service to Service RPC level instead of about low level stuff. Fix and optimize throughput for services which actually have those problems.
- jeremyjh 9y agoMessagepack is a serialization format, not a transport. It is an alternative to protobuf or json. Mostly people use HTTP because there are so many services and components that already support it (load balancers, proxies, sidecars etc), it has well-supported options for authentication, conveys metadata seamlessly through multiple layers, and its overhead isn't an issue for the kind of payloads they are sending. Plus, you know, curl.
- oh-kumudo 9y agoIt is nice but would say with limited value outside of Twitch
- rguzman 9y agoanyone who is going a move from monolith to microservices on top of AWS is a potential user of twirp and it will save tons of time on design and implementation. that's a lot of value and for a lot more people than just Twitch.
- d0100 9y agoI definitely would prefer to use this instead of bizare-REST-like (it's how REST usually devolves into) in a next project , if I can't use graphql.
- rmrfrmrf 9y agoI was surprised to find that GraphQL was probably the easiest sell to my team ever.
- rmrfrmrf 9y agoThere seems to be somewhat of a pattern of Go being linked to outages (CloudFlare and now Twitch). Any regrets investing in Go?
- klodolph 9y agoAre you talking about problems with gRPC mentioned in the article? gRPC is not in any way specific to Go or even related to Go, and I can confirm that there have been some problems with the C++ version of gRPC. The CloudFlare outage was related to leap second handling... while the particulars of the Go library contributed, this is also far, far from the only time that a leap second caused havoc online. Hell, in 2008, Zunes were crippled by a leap day bug. RPC and time handling are notoriously tricky problems to get right.
- zenlikethat 9y agoUm... what? Might as well say that operating systems are linked to outages. Pretty sure Twitter wasn’t running on Go all the times it went down. Go is really ridiculously solid and used in all kinds of production systems, outages happen no matter what language.
- g123g 9y agoI am interested in finding out how Twirp helps with versioning? Is it possible to have services evolve independent of each other?
- chuhnk 9y agoAuthor of go-micro here. Good to finally start seeing some choices focused on RPC. I started go-micro in 2014, before gRPC came on the scene. Even still I think the tooling doesn't emphasize ease of development. That was my goal with go-micro. https://github.com/micro/go-micro https://github.com/micro/go-micro
- lprd 9y agoCan any explain to me what an RPC is?
- stanleydrew 9y agohttps://en.wikipedia.org/wiki/Remote_procedure_call https://en.wikipedia.org/wiki/Remote_procedure_call
- th1nkdifferent 9y agoRemote Procedure Call. https://en.wikipedia.org/wiki/Remote_procedure_call https://en.wikipedia.org/wiki/Remote_procedure_call
- jlebrech 9y agobeautiful, i'm sick of juggling get/post/put/patch/delete and figuring out which one the api developer chose. just do X using Yparams.
- MentallyRetired 9y agoI've been saying for years and years that JSON RPC is the way to go. Glad to see at least someone agrees. http://www.jsonrpc.org/ http://www.jsonrpc.org/
- daveroberts 9y agoI'm trying to understand the problem this solves. Let's say you have an HTTP API which allows users to update their email address: POST /api/user/:username/update_email But you change the application to require API clients to send the user_id instead of the username. POST /api/user/:user_id/update_email Wouldn't you still need to mandate that all clients are updated regardless of whether you use this tool as an abstraction layer to your API?
- warent 9y agoRecommend reading on what an RPC is: https://www.geeksforgeeks.org/operating-system-remote-procedure-call-rpc/ https://www.geeksforgeeks.org/operating-system-remote-proced... And protobufs: https://developers.google.com/protocol-buffers/docs/proto3 https://developers.google.com/protocol-buffers/docs/proto3 Example, one benefit is that you're defining your API by using language neutral protobufs which then generate code consistently (including types!) into many languages. Your entire communication procedure can be easily and succinctly described in a single small, human readable file.
- tdrd 9y agoLots of comments here about lack of JSON support in gRPC - while that's true, it's relatively easily to bolt on using grpc-gateway (https://github.com/grpc-ecosystem/grpc-gateway https://github.com/grpc-ecosystem/grpc-gateway). Here's how we did it in CockroachDB: https://github.com/cockroachdb/cockroach/blob/24ed8df04719a15e74c29d5747224ef6987e7756/pkg/server/server.go#L994-L1008 https://github.com/cockroachdb/cockroach/blob/24ed8df04719a1... The supporting code (protoutil) is https://godoc.org/github.com/cockroachdb/cockroach/pkg/util/protoutil#JSONPb https://godoc.org/github.com/cockroachdb/cockroach/pkg/util/... and https://godoc.org/github.com/cockroachdb/cockroach/pkg/util/protoutil#ProtoPb https://godoc.org/github.com/cockroachdb/cockroach/pkg/util/....
- mikeschinkel 9y agoIt is amazing to me that almost nobody here actually questioned the wisdom of throwing out the time tested benefits of robustness of REST in exchange for that which REST was created to eliminate; the fragility of RPC. And all because using RPC is easier in the moment (vs. over time.) This reminds of of the old saw "Those who ignore history are doomed to repeat it." If you are unaware of the benefits, here are a just few links that can explain it: - https://www.quora.com/What-are-the-advantages-of-REST-over-a-more-RPC-style https://www.quora.com/What-are-the-advantages-of-REST-over-a... - https://www.quora.com/What-is-the-difference-between-REST-and-RPC https://www.quora.com/What-is-the-difference-between-REST-an... - http://duncan-cragg.org/blog/post/getting-data-rest-dialogues/ http://duncan-cragg.org/blog/post/getting-data-rest-dialogue... - https://apihandyman.io/do-you-really-know-why-you-prefer-rest-over-rpc/ https://apihandyman.io/do-you-really-know-why-you-prefer-res... - https://www.quora.com/What-are-the-pros-and-cons-of-REST-versus-RPC https://www.quora.com/What-are-the-pros-and-cons-of-REST-ver...
- Walkman 9y agoI did. It's pretty obvious they don't understand REST at all so they reinvented the wheel.