ХабрПостыНовостиМегапосты?

Twirp против gRPC. Стоит ли?

Если вы используете микро-сервисную архитектуру, то скорее всего знаете, что накладные расходы на коммуникацию между сервисами часто становятся значительной проблемой и если Вы сталкивались с этой проблемой, то скорее всего начали использовать один из RPC фреймворков поверх Protobuf, например, gRPC от Google или Go-Kit от Peter Bourgon или что-то другое. Пересказывать что это и как этим пользоваться нет смысла, все достаточно хорошо описано до меня. Я сам активно использую gRPC в своих проектах, но тут Twich решил выпустить свою реализацию protobuf Twirp. Если Вам интересно, зачем им это было нужно или чем она отличается проходите под кат.

Прежде всего давайте посмотрим на причины заставившие Twich релизить свою собственную версию ProtoBuf:


Как видите, простота это основновная причина, по которой Twich решили написать свою реализацию Protobuf.

Теперь давайте посмотрим, как же использовать эту библиотеку.

Если у вас уже настроена среда разработки на Go, то Вам нужно установить следующие пакеты

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

Для пример напишем простой сервис, который инкрементит значение переданное в качестве параметра.

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
}

Сгенерируем код для нашего клиента выполнив следующую команду

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

В результате буду созданы два файла


Дальше добавим реализацию нашего сервиса

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))
}

Теперь, если вы запустите клиента командой go run main.goм к сервису можно будет обратиться как по HTTP:

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


Output:
{"IncrementedValue":1}

Или в бинарном формате

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

В целом сам фреймворк практически идентичен по подходам с gRPC, но прост в реализации и с одновременной поддержкой HTTP 1.1. На мой взгляд его применимость, если вам необходим RPC сервис, с который вы планируем одновременно взаимодействовать с UI посредством HTTP и между сервисами посредством Protobuf.

Ссылки:

@
30.04.2018 23:10 UTC
Первоисточник