フラミナル

考え方や調べたことを書き殴ります。IT技術系記事多め

【新規ツール探し】シンプルに Go で gRPC が使える Connect「コードがとても見やすい!」

  • 記事作成日:2022/12/01

情報

名前 URL
Github https://github.com/bufbuild/connect-go
公式サイト https://connect.build/docs/introduction
デモサイト https://connect.build/
開発母体 Buf
version 1.3.0
言語 Go
価格 無料
ライセンス Apache-2.0 license

何ができるもの?

Go で gRPC / gRPC-web / connect(独自プロトコル) が簡単に使えるライブラリ

使い方

Getting started | Connect

❯ mkdir connect-go-example
❯ cd connect-go-example
❯ go mod init example
❯ go install github.com/bufbuild/buf/cmd/buf@latest
❯ go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
❯ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
❯ go install github.com/bufbuild/connect-go/cmd/protoc-gen-connect-go@latest
❯ mkdir -p greet/v1
❯ touch greet/v1/greet.proto
❯ cat << EOF > greet/v1/greet.proto
heredoc> syntax = "proto3";

package greet.v1;

option go_package = "example/gen/greet/v1;greetv1";

message GreetRequest {
  string name = 1;
}

message GreetResponse {
  string greeting = 1;
}

service GreetService {
  rpc Greet(GreetRequest) returns (GreetResponse) {}
}
heredoc> EOF 

❯ cat << EOF > buf.gen.yaml
version: v1
plugins:
  - name: go
    out: gen
    opt: paths=source_relative
  - name: connect-go
    out: gen
    opt: paths=source_relative
EOF

❯ buf lint
❯ buf generate

.
├── buf.gen.yaml
├── gen
│  └── greet
│     └── v1
│        ├── greet.pb.go
│        └── greetv1connect
│           └── greet.connect.go
├── go.mod
└── greet
   └── v1
      └── greet.proto
  • greet.pb.go : protoc-gen-go による proto 定義を Go コードにしたもの
  • greet.connect.go : protoc-gen-connect-go による proto 定義を HTTP Handler にしたもの

サーバ実装コードの追加

❯ cat << EOF > cmd/server/main.go
heredoc> >....                                                        
    "log"
    "net/http"

    "github.com/bufbuild/connect-go"
    "golang.org/x/net/http2"
    "golang.org/x/net/http2/h2c"

    greetv1 "example/gen/greet/v1" // generated by protoc-gen-go
    "example/gen/greet/v1/greetv1connect" // generated by protoc-gen-connect-go
)

type GreetServer struct{}

func (s *GreetServer) Greet(
    ctx context.Context,
    req *connect.Request[greetv1.GreetRequest],
) (*connect.Response[greetv1.GreetResponse], error) {
    log.Println("Request headers: ", req.Header())
    res := connect.NewResponse(&greetv1.GreetResponse{
        Greeting: fmt.Sprintf("Hello, %s!", req.Msg.Name),
    })
    res.Header().Set("Greet-Version", "v1")
    return res, nil
}

func main() {
    greeter := &GreetServer{}
    mux := http.NewServeMux()
    path, handler := greetv1connect.NewGreetServiceHandler(greeter)
    mux.Handle(path, handler)
    http.ListenAndServe(
        "localhost:8080",
        // Use h2c so we can serve HTTP/2 without TLS.
        h2c.NewHandler(mux, &http2.Server{}),
    )
}
heredoc> EOF  

確認

❯ curl --header "Content-Type: application/json" --data '{"name": "Jane"}' http://localhost:8081/greet.v1.GreetService/Greet
{"greeting":"Hello, Jane!"} 

利用シーン

  • Go で grpc をつかいたけど、grpc-go は見通し悪いなあという時。
  • シンプルにやりたい時

登場背景

by DeepL

gRPC は、その発表以来 7 年間に渡り、Protobuf RPC に待望のコンセンサスをもたらしてきました。競合する、相互に互換性のない趣味のプロジェクトのスープから出発して、gRPC チームは、共通のプロトコルの周りにコミュニティを結集し、多くの開発者に RPC スタイルの API を紹介し、Google 以外の Protobuf の人気を牽引してきました。彼らのたゆまぬ努力のおかげで、私たちは Protobuf で API を指定し、gRPC で実装し、ほとんどの言語が互換性のあるクライアント ライブラリを持っていると確信できるようになりました。

概念的には、gRPC プロトコルは HTTPに Protobuf でエンコードされたボディとメタデータを追加したものです。この単純な前提にもかかわらず、このプロトコルと今日の gRPC ライブラリは、非常に複雑化した最大公約数的な設計理念を共有しています。gRPC は、生産システムをシンプルで安定したものにするのではなく、開発、配備、デバッグ、保守を過度に複雑にしています。

例として、GoogleのgRPCのGoでの実装を考えてみましょう。

コメントを除くと、grpc-goは13万行の手書きのコードです。何十ものサブパッケージがあり、100近い設定オプションがあり、特注の名前解決とロードバランシングメカニズムがあります。また、膨大な量のコードがあるため、微妙なバグや リソースリークも避けられません。Go標準ライブラリのnet/httpを使用するのではなく、grpc-goはHTTP/2の独自の実装を使用します。これは Go の HTTP エコシステムの残りの部分と互換性がないので、他の HTTP トラフィックと一緒に gRPC リクエストをきれいに提供することができず、ほとんどのサードパーティ パッケージを使用することができません。

gRPCプロトコルはHTTP/2やTrailerをエンドツーエンドでサポートする必要があり、Webブラウザのような一般的なHTTPクライアントをサポートするには、精巧な翻訳プロキシが必要です。不明瞭な HTTP 機能を使用することに加え、gRPC プロトコルはデバッグが困難です。JSON サポートを有効にしても、単純なリクエストとレスポンスの RPC は、気になる JSON とバイナリー・フレームデータを混在させます。curl | jqや Chrome のネットワーク インスペクタを忘れてください - 利用可能なツールはすべて未熟で gRPC 固有のものです。

ポリシーとして、grpc-goはセマンティックバージョニングに従いません。リリースノートには、"動作の変更 "のための特別なセクションさえ含まれています。過去 1 年間に少なくとも 4 回のリリースで後方互換性が破られ、(etcd を含む)著名な gRPC ユーザは、しばしば一度に数ヶ月間アップデートすることができない状況にあります。

grpc-goのオープンソースコミュニティとGoogleの内部ユーザのニーズのバランスをとることは難しく、ありがたい仕事です。そして、おそらくその幅広い機能とオプションは、Google社内で採用されるために必要なものでしょう。しかし、それ以外のユーザーにとっては、grpc-goの複雑さと不安定さは、我々のコアビジネスから目をそらす不快なものでしかないのです。

気にすること

  • 利用者数と開発者数にだいぶ開きがあるので connect を使う場合はそれなりの覚悟が必要。
  • ただコード量も少なく見通しも良いので、そんなに困ることは少なそう。(HTTP/2の実装がないのがいい)
  • まだ対応している言語が少ない