grpc-gateway:grpcをhttpプロトコルに変換して対外的にサービスを提供

5340 ワード

私の会社のプロジェクトはRestfulに基づくマイクロサービスアーキテクチャを採用しています.マイクロサービス間のコミュニケーションがますます頻繁になるにつれて、rpcで内部の通信をして、対外的にはRestfulを使うことを望んでいます.そこでGoogleのgrpcを思い出しました.
grpcを用いる利点は多く,バイナリデータは伝送速度を速めることができ,http 2ベースの多重化はサービス間の接続回数を減らすことができ,関数と同様の呼び出し方式も開発効率を効果的に向上させることができる.
しかし、grpcを使用すると問題に直面します.私たちのマイクロサービスは外部にRestfulインタフェースを提供する必要があります.内部呼び出しでgrpcを使用すると、場合によっては1つの機能の2つのAPIインタフェースを同時に提供する必要があります.これにより、開発効率が低下するだけでなく、デバッグの複雑さも増加します.そこでRestfulとgprcを互いに変換できる変換メカニズムがあるかどうかを考えた.
ネット上で解決策を見ましたhttps://github.com/grpc-ecosystem/grpc-gateway簡単に言えば、変換とエージェント転送を担当するゲートウェイサーバがあります.
次の図を示します.
インストール
まずProtocolBuffers 3.0以降をインストールします.
mkdir tmp
cd tmp
git clone https://github.com/google/protobuf
cd protobuf
./autogen.sh
./configure
make
make check
sudo make install

次にgo getを使用してgrpc-gatewayを取得します.
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
go get -u github.com/golang/protobuf/protoc-gen-go

ここでは、生成されたバイナリファイルをコンパイルするディレクトリを$PATHに、$GOPATH/bin$PATHに入れることが望ましい.

この例は、私の前のブログ「googleのgrpc glangでの使用」の例に基づいています.必要があれば、前のブログを理解してください.
サンプルコード取得アドレス:https://github.com/andyidea/go-example.
コードファイルの構造は次のとおりです.
└── src
    └── grpc-helloworld-gateway
        ├── gateway
        │   └── main.go
        ├── greeter_server
        │   └── main.go
        └── helloworld
            ├── helloworld.pb.go
            ├── helloworld.pb.gw.go
            └── helloworld.proto

まず合意書を見てみましょう.helloworld.protoにはいくつかの変動があり、google公式のapi関連の拡張を導入し、grpcのhttp変換をサポートしています.
具体的な変更は以下の通りです.
syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";

package helloworld;

import "google/api/annotations.proto";

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {
        option (google.api.http) = {
        post: "/v1/example/echo"
        body: "*"
    };
  }
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

以前のprotoファイルと比較して、新しいファイルが増えました.
import "google/api/annotations.proto";

および
option (google.api.http) = {
        post: "/v1/example/echo"
        body: "*"

ここではhttpの拡張構成を追加しました.
次にprotoファイルをコンパイルし、対応するgoファイルを生成します.
cd src/grpc-helloworld-gateway

protoc -I/usr/local/include -I. \
-I$GOPATH/src \
-I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
--go_out=Mgoogle/api/annotations.proto=github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis/google/api,plugins=grpc:. \
helloworld/helloworld.proto 

ここではhelloworld/helloworldが生成されました.pb.goファイル.
helloworld.pb.goはserverサービスに必要です.次にprotocを使用してgatewayに必要なgoファイルを生成する必要があります.
cd src/grpc-helloworld-gateway

protoc -I/usr/local/include -I. \
-I$GOPATH/src  -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
--grpc-gateway_out=logtostderr=true:. \
helloworld/helloworld.proto

ここではhelloworld/helloworldが生成されました.pb.gw.goファイル.このファイルはgatewayが使用するプロトコルファイルで、grpcとhttpのプロトコル変換に使用されます.
プロトコルファイルの処理が完了すると、gatewayコードを書く必要があります.
gatewayコードは次のとおりです.
package main

import (
    "flag"
    "net/http"

    "github.com/golang/glog"
    "github.com/grpc-ecosystem/grpc-gateway/runtime"
    "golang.org/x/net/context"
    "google.golang.org/grpc"

    gw "grpc-helloworld-gateway/helloworld"
)

var (
    echoEndpoint = flag.String("echo_endpoint", "localhost:50051", "endpoint of YourService")
)

func run() error {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    defer cancel()

    mux := runtime.NewServeMux()
    opts := []grpc.DialOption{grpc.WithInsecure()}
    err := gw.RegisterGreeterHandlerFromEndpoint(ctx, mux, *echoEndpoint, opts)
    if err != nil {
        return err
    }

    return http.ListenAndServe(":8080", mux)
}

func main() {
    flag.Parse()
    defer glog.Flush()

    if err := run(); err != nil {
        glog.Fatal(err)
    }
}

まずechoEndpointは接続する必要があるサーバ情報を格納し、これらの情報と新規のサーバ用gwを用いる.goのRegisterGreeterHandlerFromEndpointが登録とバインドされると、低層はechoEndpointが提供するリモートサーバアドレスに接続され、gatewayはクライアントとリモートサーバとして接続され、その後httpで新しいサーバを起動し、gatewayはサーバ側としてhttpのサービスを外部に提供します.
コードはこれで終わります.テストしてみましょう.
まずgreeter_を起動しますserverサービス、gatewayを再起動するとgatwayがgreeter_に接続されますserver後、httpの傍受を対外的に確立する.
その後curlでhttpリクエストを送信します
curl -X POST -k http://localhost:8080/v1/example/echo -d '{"name": " world"}

{"message":"Hello  world"}

プロセスは以下の通りである:curlはpostでgatewayに要求を送信し、gatewayはproxyとして要求をgrpcを通じてgreeterに転送する.server,greeter_serverはgrpcで結果を返し,gatewayは結果を受け取った後,jsonに変換してフロントエンドに戻る.
これによりgrpc−gatewayによりhttp jsonから内部grpcへの変換過程が完了した.