
Прежде всего давайте посмотрим на причины заставившие Twich релизить свою собственную версию ProtoBuf:
- Отсутствие поддержки HTTP 1.1. gRPS опирается на HTTP-трейлеры и полно-дуплексные потоки (full-duplex streams). Twirp поддерживает и HTTP 1.1 и HTTP/2, что очень важно потому что большое количество load-balancer-ов (как хардварных, так и софтверных) поддерживают только HTTP 1.1 — включая AWS Elastic Load Balancer. Но в отличии от gRPC Twirp не поддерживает стримингового RPC, что в случае когда Ваш API построен по принципу Request-Response и не требуется.
- Cложность реализации библиотеки grpc-go. Библиотека включает полную реализации HTTP/2, независимую от стандартных библиотек, что делает сложным ее пониманию и анализ возникающих ошибок.
- Cовместимость версий gRPC. В силу того, что gRPC довольно сложен, генерируемый Go код довольно простой и все запросы перенаправляются в grpc-go. Такая связанность приводит к тому, что клиент вынужден использовать ту же самую версию, что и сервер. И если у Вас большое количество клиентов и сервис взаимодействую друг с другом, то версия между ними должна быть идентичная. Понятно, что это приводит к сложностям в деплойменте и развертыванию микросервисов.
- Также Twitch указывают, что grpc-go требует определенную версию protobuf — github.com/golang/protobuf. Но для меня эта проблема кажется надуманной, так как protobuf имеет только один релиз версии v1.0.0, который используется всеми версиями grpc-go.
- gRPC поддерживает только бинарную форму сообщений и сниффинг сообщений очень сложным для анализа. Twirp поддерживает как бинарную форму сообщения в формате protobuf, так и в небинарные в формате JSON. Это вам дает преимущество, скажем если вы хотите взаимодействовать с сервисом через обычный HTTP Request посредством JSON
Как видите, простота это основновная причина, по которой 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
В результате буду созданы два файла
- Increment.pb.go — содержит кодо-генерацию для сообщений
- Increment.twirp.go — содержит интерфейсы и функции сервиса
Дальше добавим реализацию нашего сервиса
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.
Ссылки:
Комментариев нет:
Отправить комментарий