62
53

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Go 5Advent Calendar 2020

Day 25

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

Last updated at Posted at 2020-12-25

##はじめに
(当時)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公式

62
53
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
62
53

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?