まず、TwichがProtoBufの独自バージョンをリリースした理由を見てみましょう。
- HTTP 1.1のサポートの欠如。 gRPSは、HTTPトレーラーと全二重ストリームに依存しています。 TwirpはHTTP 1.1とHTTP / 2の両方をサポートします。これは、AWS Elastic Load Balancerを含む多数のロードバランサー(ハードウェアとソフトウェアの両方)がHTTP 1.1のみをサポートするため、非常に重要です。 ただし、gRPCとは異なり、TwirpはストリーミングRPCをサポートしません。これは、APIが要求/応答に基づいて構築されており、必須ではない場合です。
- grpc-goライブラリの実装の複雑さ。 このライブラリには、標準ライブラリとは独立したHTTP / 2の完全な実装が含まれているため、発生するエラーの理解と分析が困難になります。
- GRPCバージョンの互換性。 gRPCはかなり複雑であるため、Goで生成されたコードは非常にシンプルで、すべてのリクエストはgrpc-goにリダイレクトされます。 この接続により、クライアントはサーバーと同じバージョンを使用せざるを得なくなります。 また、多数の顧客がいて、サービスが相互にやり取りする場合、顧客間のバージョンは同一である必要があります。 これにより、マイクロサービスの展開と展開が困難になることは明らかです。
- Twitchはまた、grpc-goには特定のバージョンのprotobuf-github.com/golang/protobufが必要であることを示しています。 しかし、私にとっては、protobufにはバージョンv1.0.0のリリースが1つしかなく、これはgrpc-goのすべてのバージョンで使用されているため、この問題は大げさなようです。
- gRPCはバイナリメッセージ形式のみをサポートし、メッセージスニッフィングの分析は非常に困難です。 Twirpは、protobuf形式のバイナリメッセージ形式とJSON形式の非バイナリメッセージ形式の両方をサポートしています。 これにより、JSONを使用した通常のHTTPリクエストを介してサービスとやり取りしたい場合など、利点が得られます。
ご覧のとおり、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
その結果、2つのファイルが作成されます。
- 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をサポートしています。 私の意見では、その適用性は、HTTPを介してUIと、Protobufを介してサービス間で同時に対話することを計画しているRPCサービスが必要な場合です。
参照: