Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
52
Help us understand the problem. What is going on with this article?
@Sora_TrilingualEngineer

今流行りのgRPCについて簡単にまとめてみた(Goのサンプルコード付き)

はじめに

(当時)Go歴1ヶ月の私が急遽gRPCを用いてバックエンドのAPIを開発してる業務に参画することになり、必要にかられて急いで学んだので、その時の学びを共有します✎

gRPCって最近よく聞くけど、「なにそれ?」って方も多いと思うので(私もそのうちの1人でした)、自分の学びを纏めるためにもgRPCのエントリー記事を書こうと決意し、Go 5 Advent Calendar 2020に登録しました!

gRPCとは

  • gRPCって良いらしい
  • 最近gRPC流行ってるらしい

等聞いたことは多いと思いますが、簡単に説明すると

  • RPC (Remote Procedure Call) を実現するためにGoogleが開発したプロトコルの1つ
  • Protocol Buffers を使ってデータをシリアライズし、高速な通信を実現できる
  • IDL(インターフェース定義言語)を使ってあらかじめAPI仕様を .proto ファイルとして定義し、.protoファイルからサーバー側&クライアント側に必要なソースコードのひな形を生成できる
  • 言語に依存せず、一つの.protoファイルで12言語の実装を生成できる(Go, Java, Python, C, Ruby等など。主要なプログラミング言語はだいたい網羅されてる!)
  • 認証、Load balancing, log, モニタリングのプラグインが比較的簡単
  • HTTP/2を基に作られており、簡単にHTTP/2の恩恵を受けられる
  • SSL通信がデフォルトで適応されており、安全性が高い
  • スケーラビリティが高い (数百万のリクエストを並列でさばける)
  • (以下の)4つのAPIタイプを作成でき、様々な種類/用途のAPIを開発できる
  1. Unary (一般的なやつ:1 req(request) 1 res(response))
  2. Server Streaming (client:1 req, server:複数res)
  3. Client Streaming (client: 複数req, server: 1 res)
  4. Bi Directional Streaming (client:複数req, server:複数res) Screen Shot 0002-12-25 at 19.29.54.png

■複数言語で通信時のイメージ
grpc_polyglot.png
gRPC公式より抜粋

gRPCが流行っているわけ

gRPCのメリットは特にマイクロサービスの中で強く発揮されます。
gRPCが流行った原因の一つはマイクロサービスとの相性が良いからです👀!

さっき言った特徴の

  • モダン、通信が早くて低遅延、データ送信が効率的
  • 異なる言語間での通信を簡単にできる

の辺りが理由でマイクロサービスのAPIはgRPCを使って実装されることが多いです。
GoogleやNetflixのような世界的企業でもgRPCは使われており、規模が大きく、サービスを連携させている大企業にメリットが多い技術です。

開発の流れ

1. .protoファイルの定義・作成

greet.proto
syntax = "proto3";

package greet;
option go_package="greetpb";

// GreetRequest を受け取って GreetResponse を返すメソッドの定義
service Greet {
  rpc Greet (GreetRequest) returns (GreetResponse) {}
}

message Greeting {
    string first_name = 1;
    string last_name = 2;
}

// GreetRequest のリクエスト定義
message GreetRequest {
    Greeting greeting = 1;
}

// GreetResponse のリスポンス定義
message GreetResponse {
    string result = 1;
}

2. .proto をコンパイルし、サーバー&クライアントのコード生成

greet.pb.go
type Greeting struct {
    FirstName            string   `protobuf:"bytes,1,opt,name=first_name,json=firstName,proto3" json:"first_name,omitempty"`
    LastName             string   `protobuf:"bytes,2,opt,name=last_name,json=lastName,proto3" json:"last_name,omitempty"`
    XXX_NoUnkeyedLiteral struct{} `json:"-"`
    XXX_unrecognized     []byte   `json:"-"`
    XXX_sizecache        int32    `json:"-"`
}

func (m *Greeting) GetFirstName() string {
    if m != nil {
        return m.FirstName
    }
    return ""
}

func (m *Greeting) GetLastName() string {
    if m != nil {
        return m.LastName
    }
    return ""
}

// 長いので以下略 //

3. 2.を使用し、クライアント&サーバサイドの実装。

■クライアントサイド

client.go
package main

import (
// 略
)

func main() {

    fmt.Println("Hello I'm a client")

    tls := false
    opts := grpc.WithInsecure()
    if tls {
        certFile := "ssl/ca.crt" // Certificate Authority Trust certificate
        creds, sslErr := credentials.NewClientTLSFromFile(certFile, "")
        if sslErr != nil {
            log.Fatalf("Error while loading CA trust certificate: %v", sslErr)
            return
        }
        opts = grpc.WithTransportCredentials(creds)
    }

    cc, err := grpc.Dial("localhost:50051", opts)
    if err != nil {
        log.Fatalf("could not connect: %v", err)
    }
    defer cc.Close()

    c := greetpb.NewGreetServiceClient(cc)

    doUnary(c)
}

func doUnary(c greetpb.GreetServiceClient) {
    fmt.Println("Starting to do a Unary RPC...")
    req := &greetpb.GreetRequest{
        Greeting: &greetpb.Greeting{
            FirstName: "Stephane",
            LastName:  "Maarek",
        },
    }
    res, err := c.Greet(context.Background(), req)
    if err != nil {
        log.Fatalf("error while calling Greet RPC: %v", err)
    }
    log.Printf("Response from Greet: %v", res.Result)
}

■サーバサイド

server.go

package main

import (
// 略
)

func main() {
    fmt.Println("Hello world")

    lis, err := net.Listen("tcp", "0.0.0.0:50051")
    if err != nil {
        log.Fatalf("Failed to listen: %v", err)
    }

    opts := []grpc.ServerOption{}
    tls := false
    if tls {
        certFile := "ssl/server.crt"
        keyFile := "ssl/server.pem"
        creds, sslErr := credentials.NewServerTLSFromFile(certFile, keyFile)
        if sslErr != nil {
            log.Fatalf("Failed loading certificates: %v", sslErr)
            return
        }
        opts = append(opts, grpc.Creds(creds))
    }

    s := grpc.NewServer(opts...)
    greetpb.RegisterGreetServiceServer(s, &server{})

    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

type server struct{}

func (*server) Greet(ctx context.Context, req *greetpb.GreetRequest) (*greetpb.GreetResponse, error) {
    fmt.Printf("Greet function was invoked with %v\n", req)
    firstName := req.GetGreeting().GetFirstName()
    result := "Hello " + firstName
    res := &greetpb.GreetResponse{
        Result: result,
    }
    return res, nil
}

メリット

  • API設計/仕様の定義が楽、ルールが定められてて逸脱しにくい
  • HTTP/2の恩恵を受けれる(高速、双方間ストリーミング通信)
  • 言語依存がなく、色んな言語でgRPCを利用できる
  • 認証、Load balancing, log, モニタリング等を比較的簡単に実装でき、API開発に注力できる

デメリット

  • データがシリアライズされるのでデバッグしにくい(らしい)
  • ドキュメントや情報が日本語化されてないものが多い。(英語でググる方が良い気がする)

オススメの勉強方法

  1. 公式ページでProtocol BuffersにAPIの仕様を書くとはどんな感じか理解する。 (最初はよくわからなくて良いと思います。私も公式のページ読んでHands onしても「なにこれ?」って状態でした。実際にgRPCを使った開発をすると後でわかってきます。)
  2. gRPCの公式でgRPCとは何かをざっとインプット (包括的ではないので、こんな感じか。くらいの理解で良いと思います。)
  3. 簡単なものを何か作ってみる。(ここで一気に理解が深まります。)

3.のフェーズで私が勉強した教材はUdemyのgRPC [Golang] Master Class: Build Modern API & Microservices
です。
英語での説明(日本語字幕なし)ですが、説明がわかりやすいので英語ができる方にはオススメです。

日本語の教材だとスターティングgRPCあたりが良いらしいです。(私はこちら実施してないです。)

最後に

正直前もってGo 5 Advent Calendar 2020に登録してなければ、面倒くさくて記事書いてなかったです。。締め切り駆動で前もって登録+予約するのって大事ですね。資格等の勉強もこの方式が個人的には一番いいと思います。

Twitterやってるので、よければフォローしてください!
Go, gRPC, AWS, GCP, Next.js, Nuxt.js あたりを使用して開発(&勉強中)してます!
https://twitter.com/skyTrilingineer

参考にさせていただいた記事/ページ

gRPC [Golang] Master Class: Build Modern API & Microservices
gRPCって何?
HTTP/2における双方向通信とgRPCとこれから
gRPC公式
Protocol Buffers公式

52
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sora_TrilingualEngineer
Web系自社開発(Go/Node.js/AWS/ML/Nuxt.js, Go/gRPC/GCP/Next.js)←Sler3年弱。 業務経験:STB開発、運用、保守 VoDアプリの開発・運用・保守  Node.js, JavaScript, Java, Ruby on Rails, Go

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
52
Help us understand the problem. What is going on with this article?