初めてGRPCを試みる


それで、私はここ数ヵ月でかなりの数回GRPCについて尋ねられました.私は簡潔にそれについて読んで、それが必要であるならば、それが移行するのが難しいと思いませんでした、しかし、私はこれまでの経験に関するどんな手も得ませんでした.今すぐ変更.

それで、GRPCは何ですか?


GはGPCを2015年に創ったので、Gはグーグルを表します.rpc partリモートプロシージャコールを表します.RPCはまったく新しいやり方ではなく、別のマシンでマシンからプロシージャを呼び出すだけです.それについて現代的なことは、問題のマシンがどこか(例えばGCPのような)クラウド上にあるという事実だけです.
また、GRPCはHTTP/2を使います.HTTP/1.1に反対するHTTP/2の主な利点の1つは、(デフォルトではRESTで使用されます).
  • テキストの代わりにバイナリです
  • これは完全に多重化されている
  • つの接続を並列に使うことができます
  • オーバーヘッドを減らすためにヘッダー圧縮を使用します
  • これは、サーバーを積極的にブラウザのキャッシュに応答を追加するプッシュを許可します.
  • したがって、より詳しい用語では、http 2はバイナリであるので、それはより速いです.HTTP/1.1のシリアル化と逆シリアル化は遅くなります.
    また、通信のためのJSONオブジェクトの代わりにProtobufと呼ばれるものを使用します.唯一の利点は、JSONはより大きなコミュニティ(今のところ)を持っているということです.OK、多分私はJSONでハードになるかもしれない、それはまた、非常に初心者のために理解し、書くことは非常に簡単です.
    しかし、protobufについて話しましょう.基本的にXMLを考えるが、小さく、より速く、簡単です.あなたは.proto ファイル(例は私のアプリでは、私は2番目の)を取得するだけで1つのコマンドを使用すると、ファイル全体と自分自身のクラスを生成することができます.だから何も心配する必要はない、ライブラリはあなたのためにそれを行います.
    そして、それはイントロのためのそれについてです.アプリにジャンプしましょう.

    アプリ


    アプリはかなりまっすぐ前方にあります.フロントエンド側では、単に正方形と円をできるだけ早く押してください.しかし、何がクールなのか、フロントエンドがヒットする1つのREST MicroServiceを使用して、2つのGRPC MicroServiceを使用しています.それは、あなたのハイスコアを追跡して取り込み、次の出現するオブジェクトのサイズを計算するためです.
    あなたがオブジェクトをヒットすることができますより速く、彼らは次に表示され、より遅い場合は、次のオブジェクトが大きくなります.
    そう言ったように、ゲームはかなり簡単です.そして、フロントエンドがちょうど1つであるように、私が本当にどのように働くかについて、私は行きませんindex.html 最も困難なものが残りのMicroServiceへのいくつかのAjax呼び出しであるファイル.
    しかし、最初のGRPCマイクロサービスに入りましょう.

    GRPCハイスコアマイクロサービス


    したがって、このマイクロサービスは2つのことを行います:ハイスコアを取得し、ハイスコアを設定します.非常にオリジナルではなく、それで行きましょう.私は、このプロジェクトがロケット科学であると決して言いませんでした😁
  • 1 )定義.proto file
  • イントロで言うように、GRPCはProtobufを使用して、それを使用するために、我々は最初に定義します.proto ファイル.我々はハイスコアを得るために何かを送信するために何かを送信する必要はありませんので、むしろそれを読む必要はありません、その部分は何も取りませんし、セットハイスコアはスコアを取るし、それがこれまでに保存されている場合よりも優れているかどうかを確認します.
    syntax = "proto3";
    
    option go_package = "game";
    
    service Game{
        rpc SetHighScore(SetHighScoreRequest) returns (SetHighScoreResponse);
        rpc GetHighScore(GetHighScoreRequest) returns (GetHighScoreResponse);
    }
    
    message SetHighScoreRequest {
        double high_score = 1;
    }
    
    message SetHighScoreResponse {
        bool set = 1;
    }
    
    message GetHighScoreRequest {}
    
    message GetHighScoreResponse {
        double high_score = 1;
    }
    
    ヴィオラ.として簡単に取得します.それについてすぐ話しましょう.
    The syntax パートはちょうど私たちが使っているprotoのバージョンを言います、そして、Probe 3は利用できる最新のものです.option go_package ジャスト・セイ.go ファイルを作成するgame パッケージ.service 実際にはGRPCのパンとバターですがrpc 呼び出しをしようとしているリモートマシン上のプロシージャまたは関数として呼び出します.そして、最初に言ったように、JSONを使用していないので、GRPCを使うために送信するメッセージを表す2つのメッセージ署名を定義します.ここでは、4つのメッセージタイプがあります.SetHighScoreRequest, SetHighScoreResponse, GetHighScoreRequest, GetHighScoreResponse . 私がここで言及しなければならない唯一のものは、このおかしいナンバーです1 あなたは見ている.これは、将来的には、我々が追加するか、より多くのフィールドをドロップする場合、これらの数字は、後方互換性を保存するのに役立ちます.

  • 2 )クラスを自動生成するコマンドを実行します.
  • よく、私はgoを使用しています、それで、私のコマンドはちょうどこれらの2ステップを必要とします:go install google.golang.org/protobuf/cmd/protoc-gen-go
    and protoc -I ./protobuf-import -I ./ ./v1/*.proto --go_out=plugins=grpc:./
    そして、あなたは私のMakefileの中にそれを見ることができます.私はMakefileに深く行きません、それはとても単純です.sh しかし、あなたがそれに興味があって、経験がないならば、私をpingしてください、そして、私はそれを説明します🙂
  • 3 ) GRPCサーバを作成する
  • さて、ステップ2は非常にクールに作成highscore.pb.go ファイル.さあ、使いましょう.
    次の構造を作成internal_usage/server/grpc/grpc.go . それはInteralの使用の中にある理由は、一度実装されているため、我々は本当にそれを心配する必要はありません.それは常に動作し、我々はコードの他の部分で作業を開始することができます.
    しかし、中に何があるかを見ましょうgrpc.go ファイル.
    package grpc
    
    import (
        "context"
        v1highscore "github.com/fvukojevic/grpc_test/m-apis/m-highscore/v1"
        "github.com/pkg/errors"
        "github.com/rs/zerolog/log"
        "google.golang.org/grpc"
        "net"
    )
    
    type Grpc struct {
        address string //address where the gRPC will listen at
        srv     *grpc.Server
    }
    
    func NewServer(address string) *Grpc {
        return &Grpc{
            address: address,
        }
    }
    
    var HighScore = 999999.0
    
    func (g *Grpc) SetHighScore(ctx context.Context, input *v1highscore.SetHighScoreRequest) (*v1highscore.SetHighScoreResponse, error) {
        log.Info().Msg("SetHighscore in m-highscore is called")
    
        HighScore = input.HighScore
        return &v1highscore.SetHighScoreResponse{
            Set: true,
        }, nil
    }
    
    func (g *Grpc) GetHighScore(ctx context.Context, input *v1highscore.GetHighScoreRequest) (*v1highscore.GetHighScoreResponse, error) {
        log.Info().Msg("GetHighscore in m-highscore is called")
    
        return &v1highscore.GetHighScoreResponse{
            HighScore: HighScore,
        }, nil
    }
    
    func (g *Grpc) ListenAndServe() error {
        listener, err := net.Listen("tcp", g.address)
    
        if err != nil {
            return errors.Wrap(err, "Failed to open tcp port")
        }
    
        var serverOpts []grpc.ServerOption
    
        g.srv = grpc.NewServer(serverOpts...)
    
        v1highscore.RegisterGameServer(g.srv, g)
    
        log.Info().Str("Address", g.address).Msg("Starting gRPC server for highscore microservice")
    
        if err := g.srv.Serve(listener); err != nil {
            return errors.Wrap(err, "Failed to start gRPC server")
        }
    
        return nil
    }
    
    ご覧の通り、非常に複雑に見えますが、それは本当に何を表しますか?よく、getthighscoreとsethigshcoreはここにあります.proto あなたが覚えているならば、ファイルしてください.また、我々は我々の保持する構造を作成しましたgRPC サーバ.
    そして最後に、我々はこれを持っているListenAndServe すべてのGRPCが特定のアドレス(ポート)を聞いて、それが使われることができるように出されるので、方法.
  • 4 )主からサーバを呼び出す
  • GOに精通している場合は、すべてのエントリポイントを知っているパッケージのメインとメインです.ファイルを移動します.このメインで.私たちは本当に何をする必要がありますか?よくちょうど私たちのサーバーを初期化し、それを提供します.main.go
    package main
    
    import (
        "flag"
        grpcSetup "github.com/fvukojevic/grpc_test/m-apis/m-highscore/internal_usage/server/grpc"
        "github.com/rs/zerolog/log"
    )
    
    func main() {
        var addressPtr = flag.String("address", ":50051", "address where you can connect to gRPC m-highscore service")
    
        flag.Parse()
    
        s := grpcSetup.NewServer(*addressPtr)
    
        if err := s.ListenAndServe(); err != nil {
            log.Fatal().Err(err).Msg("Failed to start grpc server")
        }
    }
    
    そして、それ!

    GRPCゲームエンジン


    名前が涼しく聞こえるにもかかわらず、それはちょうどhighscoreマイクロサービスと同じです、それで、私はあなたにあなた自身でコードを越えるようにします.再び、それはかなり同じです

    フロントエンドとバックエンドの間の通信のための休止


    よく私は最後に休憩を使用して終了しました.なぜ?よく、それはJavaScriptから直接GRPCを呼ぶことを意味しませんでした.少なくとも私にでなく.それで、私は少数のルートを提供する小さなゲートウェイをつくりました、そして、それが打つあらゆるルートは、内部的にGRPCを呼び出して、それが必要とするものを実行します.
    使用中gin gonic 残りのために、それは非常にクールで高速なパッケージとかなり簡単に設定することです.
    しかし、私のREST MicroServiceは永遠に走るGRPCに気づいていなければなりません.それで、それはclients.go ファイル.
    だから我々のサーバー、ハイスコアやゲームエンジンがあります.しかし、何を呼び出す?よく、それはクライアントです.彼らは基本的にサーバーのポートに接続し、それらと通信します.
    ここでどのように簡単ですclients.go ファイルが見える.
    package domain
    
    import (
        v1gameengine "github.com/fvukojevic/grpc_test/m-apis/m-game-engine/v1"
        v1highscore "github.com/fvukojevic/grpc_test/m-apis/m-highscore/v1"
        "github.com/rs/zerolog/log"
        "google.golang.org/grpc"
    )
    
    func NewGRPCGameServiceClient(serverAddr string) (v1highscore.GameClient, error) {
        conn, err := grpc.Dial(serverAddr, grpc.WithInsecure())
    
        if err != nil {
            log.Fatal().Msgf("Failed to dial: %v", err)
            return nil, err
        }
    
        log.Info().Msgf("Successfully connected to [%s]", serverAddr)
    
        if conn == nil {
            log.Info().Msg("m-highscore connection is nil")
        }
    
        client := v1highscore.NewGameClient(conn)
    
        return client, nil
    }
    
    func NewGRPCGameEngineServiceClient(serverAddr string) (v1gameengine.GameEngineClient, error) {
        conn, err := grpc.Dial(serverAddr, grpc.WithInsecure())
    
        if err != nil {
            log.Fatal().Msgf("Failed to dial: %v", err)
            return nil, err
        }
    
        log.Info().Msgf("Successfully connected to [%s]", serverAddr)
    
        if conn == nil {
            log.Info().Msg("m-game-engine connection is nil")
        }
    
        client := v1gameengine.NewGameEngineClient(conn)
    
        return client, nil
    }
    
    だけで接続する場合は、任意のエラーを取得した場合(あなたの本当にすべきではないかもしれません、uは、ポートや何かを逃した場合を除いて)、それはそれです.
    グランドフィナーレについては、次のコードで残りのルートを公開します.
    package main
    
    import (
        "flag"
        grpcSetup "github.com/fvukojevic/grpc_test/m-apis/m-highscore/internal_usage/server/grpc"
        "github.com/rs/zerolog/log"
    )
    
    func main() {
        var addressPtr = flag.String("address", ":50051", "address where you can connect to gRPC m-highscore service")
    
        flag.Parse()
    
        s := grpcSetup.NewServer(*addressPtr)
    
        if err := s.ListenAndServe(); err != nil {
            log.Fatal().Err(err).Msg("Failed to start grpc server")
        }
    }
    

    最終結果


    最後に、最終的な結果は、このような単純なアプリをクリックし、ユーザーの速度を追跡するだけのように見えるはずです.

    プロジェクト資源


    ギタブhttps://github.com/fvukojevic/grpc_test
    アプリケーションは、マイクロサービスなしでも動作しますが、彼らはまだショーケースにクールです.
    もう一度、私はこれが続くのは難しいかもしれないので、質問がある場合はGRPCについての詳細を知りたい場合は、電子メールおよび/またはLinkedInと私に連絡し、私たちはそれについてチャットすることができますお気軽に!
    私のLinkedInプロファイル
    次回まで!🚀🚀