📜 ⬆️ ⬇️

Twirp vs. gRPC. Is it worth it?

If you are using a micro-service architecture, then you most likely know that the overhead of communication between services often becomes a significant problem and if you encountered this problem, you most likely started using one of the RPC frameworks over Protobuf , for example, Google’s gRPC or Go-Kit from Peter Bourgon or something else. Retelling what it is and how to use it makes no sense, everything is well described before me. I myself actively use gRPC in my projects, but here Twich decided to release my protobuf Twirp implementation. If you are wondering why they needed it or how it differs, go under the cat.

First of all, let's look at the reasons for making Twich release its own version of ProtoBuf:


As you can see, simplicity is the main reason why Twich decided to write its own implementation of Protobuf.

Now let's see how to use this library.
')
If you already have a Go development environment, then you need to install the following packages.

go get github.com/twitchtv/twirp/protoc-gen-twirp go get github.com/golang/protobuf/protoc-gen-go 

For example, we write a simple service that increments the value passed as a parameter.

 syntax = "proto3"; service Service { rpc Increment(Request) returns (Response); } message Request { int32 valueToIncrement = 1; // must be > 0 } message Response { int32 IncrementedValue = 1; // must be > 0 } 

Generate code for our client by executing the following command

 protoc --proto_path=$GOPATH/src:. --twirp_out=. --go_out=. ./paperclips.proto 

As a result, two files will be created.


Next, add the implementation of our service

 package main import ( "fmt" "log" "net/http" "context" pb "TwirpSample/Server/Twirp" ) // Server implements the Increment service type Server struct { value int32 } // NewServer creates an instance of our server func NewServer() *Server { return &Server{ value: 1, } } // Increment returns the incremented value of request.ValueToIncrement func (s *Server) Increment(ctx context.Context, request *pb.Request) (*pb.Response, error) { return &pb.Response{ IncrementedValue: request.ValueToIncrement + 1, }, nil } func main() { fmt.Printf("Starting Increment Service on :6666") server := NewServer() twirpHandler := pb.NewServiceServer(server, nil) log.Fatal(http.ListenAndServe(":6666", twirpHandler)) } 

Now, if you start the client with the command go run main.go, the service can be accessed as via HTTP:

 curl --request "POST" \ --location "http://localhost:6666/Service/Increment" \ --header "Content-Type:application/json" \ --data '{ValueToIncrement: 0}' \ --verbose Output: {"IncrementedValue":1} 

Or in binary format

 package main import ( "fmt" rpc "TwirpSample/Server/Twirp" "net/http" "context" ) func main() { fmt.Println("Twirp Client Example.") client := rpc.NewServiceProtobufClient("http://localhost:6666", &http.Client{}) v, err := client.Increment(context.Background(), &rpc.Request{ValueToIncrement: 11}) if err != nil { fmt.Println(err.Error()) } fmt.Printf("Value: %d", v.IncrementedValue) } Output: Twirp Client Example. Value: 11 

In general, the framework itself is almost identical in approach with gRPC, but it is simple to implement and with simultaneous support for HTTP 1.1. In my opinion, its applicability, if you need an RPC service, with which you plan to simultaneously interact with the UI via HTTP and between services via Protobuf.

References:

Source: https://habr.com/ru/post/354706/


All Articles