title: 【転載】gRPC 快速入門
date: 2021-08-09 16:36:33
comment: false
toc: true
category:
- Golang
- gRPC
tags: - 転載
- Go
- gRPC
- クイック
- 入門
本文転載自:gRPC 快速入門 | 李文周のブログ
RPC は近年比較的注目されている概念で、マイクロサービスアーキテクチャの台頭に伴い、RPC の応用がますます広がっています。本記事では RPC と gRPC の関連概念を紹介し、詳細なコード例を通じて gRPC の基本的な使用法を説明します。
gRPC#
RPC とは#
分散コンピューティングにおいて、リモートプロシージャコール(英語:Remote Procedure Call、略称 RPC)はコンピュータ通信プロトコルです。このプロトコルは、あるコンピュータ上で実行されているプログラムが、別のアドレス空間(通常はオープンネットワーク上のコンピュータ)のサブルーチンを呼び出すことを許可します。プログラマーは、ローカルプログラムを呼び出すのと同じように、追加のプログラミングを行うことなく(詳細に気を配る必要はありません)、この相互作用を行うことができます。RPC はサーバー - クライアント(Client/Server)モデルであり、古典的な実装は「リクエストを送信し、応答を受け取る」ことで情報を交換するシステムです。
gRPC とは#
gRPC
は、任意の環境で実行できる現代的なオープンソースの高性能 RPC フレームワークで、最初は Google によって開発されました。HTTP/2 をトランスポートプロトコルとして使用します。
gRPC では、クライアントはローカルメソッドを呼び出すように、他のマシン上のサーバーアプリケーションのメソッドを直接呼び出すことができ、分散アプリケーションやサービスをより簡単に作成するのに役立ちます。多くの RPC システムと同様に、gRPC はサービスを定義し、パラメータと戻り値の型を持つリモート呼び出し可能なメソッドを指定することに基づいています。サーバープログラムでこのインターフェースを実装し、gRPC サービスを実行してクライアントの呼び出しを処理します。クライアントには、サーバーと同じメソッドを提供するスタブがあります。
なぜ gRPC を使うのか#
gRPC を使用することで、1 つの .proto
ファイルでサービスを定義し、それをサポートする任意の言語でクライアントとサーバーを実装できます。逆に、それらはさまざまなシナリオで使用でき、Google のサーバーからあなた自身のタブレットまで、gRPC は異なる言語や環境間の通信の複雑さを解決します。protocol buffers
を使用することで、効率的なシリアル化、シンプルな IDL、インターフェースの更新の容易さなど、他の利点も得られます。要するに、gRPC を使用することで、私たちは言語を超えた分散コードをより簡単に書くことができます。
gRPC のインストール#
gRPC のインストール#
go get -u google.golang.org/grpc
Protocol Buffers v3 のインストール#
gRPC サービスコードを生成するためのプロトコルコンパイラをインストールします。最も簡単な方法は、以下のリンクからあなたのプラットフォームに適した事前コンパイルされたバイナリファイル(protoc-<version>-<platform>.zip
)をダウンロードすることです:https://github.com/google/protobuf/releases
ダウンロードが完了したら、以下の手順を実行します:
- ダウンロードしたファイルを解凍します
protoc
バイナリファイルのパスを環境変数に追加します
次に、以下のコマンドを実行して protoc の Go プラグインをインストールします:
go get -u github.com/golang/protobuf/protoc-gen-go
コンパイラプラグイン protoc-gen-go
は $GOBIN
にインストールされ、デフォルトでは $GOPATH/bin
です。これがあなたの $PATH
に含まれている必要があります。そうしないと、プロトコルコンパイラ protoc
がそれを見つけることができません。
インストールの指定#
gRPC 開発は三つのステップに分かれます#
象を冷蔵庫に入れるのは何ステップですか?
- 冷蔵庫の扉を開けます。
- 象を入れます。
- 冷蔵庫の扉を閉めます。
gRPC 開発も同様に三つのステップに分かれます:
.proto
ファイルを作成し、指定された言語のソースコードを生成します。- サーバーコードを作成します
- クライアントコードを作成します
gRPC 入門例#
proto コードの作成#
gRPC は Protocol Buffers に基づいています。
Protocol Buffers
は、言語に依存せず、プラットフォームに依存しない拡張可能なメカニズムで、構造化データをシリアル化するために使用されます。Protocol Buffers
を使用すると、構造化データを一度定義し、特別に生成されたソースコードを使用して、さまざまなデータストリームでさまざまな言語で構造化データを簡単に読み書きできます。
Protocol Buffers
に関するチュートリアルは、オンラインで検索できます。本記事では、読者が Protocol Buffers
に精通していることを前提としています。
syntax = "proto3"; // バージョン宣言、Protocol Buffers v3を使用
package pb; // パッケージ名
// 挨拶サービスを定義
service Greeter {
// SayHello メソッド
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// 名前を含むリクエストメッセージ
message HelloRequest {
string name = 1;
}
// 挨拶文を含むレスポンスメッセージ
message HelloReply {
string message = 1;
}
以下のコマンドを実行して、Go 言語のソースコードを生成します:
protoc -I helloworld/ helloworld/pb/helloworld.proto --go_out=plugins=grpc:helloworld
gRPC_demo/helloworld/pb
ディレクトリに helloworld.pb.go
ファイルが生成されます。
サーバー側の Go コードの作成#
package main
import (
"fmt"
"net"
pb "gRPC_demo/helloworld/pb"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
)
type server struct{}
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}
func main() {
// ローカルの8972ポートをリッスン
lis, err := net.Listen("tcp", ":8972")
if err != nil {
fmt.Printf("failed to listen: %v", err)
return
}
s := grpc.NewServer() // gRPCサーバーを作成
pb.RegisterGreeterServer(s, &server{}) // gRPCサーバーにサービスを登録
reflection.Register(s) // 指定されたgRPCサーバーにサーバーリフレクションサービスを登録
// Serveメソッドはlisで受信接続を受け入れ、各接続のためにServerTransportとserverのgoroutineを作成します。
// このgoroutineはgRPCリクエストを読み取り、登録されたハンドラーを呼び出して応答します。
err = s.Serve(lis)
if err != nil {
fmt.Printf("failed to serve: %v", err)
return
}
}
上記のコードを gRPC_demo/helloworld/server/server.go
ファイルに保存し、コンパイルして実行します:
cd helloworld/server
go build
./server
クライアント側の Go コードの作成#
package main
import (
"context"
"fmt"
pb "gRPC_demo/helloworld/pb"
"google.golang.org/grpc"
)
func main() {
// サーバーに接続
conn, err := grpc.Dial(":8972", grpc.WithInsecure())
if err != nil {
fmt.Printf("faild to connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
// サーバーのSayHelloを呼び出す
r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: "q1mi"})
if err != nil {
fmt.Printf("could not greet: %v", err)
}
fmt.Printf("Greeting: %s !\n", r.Message)
}
上記のコードを gRPC_demo/helloworld/client/client.go
ファイルに保存し、コンパイルして実行します:
cd helloworld/client/
go build
./client
出力は以下のようになります(注意:サーバー側を先に起動してからクライアント側を起動してください):
$ ./client
Greeting: Hello q1mi!
この時点で、私たちのディレクトリ構造は以下のようになります:
./gRPC_demo
├── go.mod
├── go.sum
└── helloworld
├── client
│ ├── client
│ └── client.go
│ ├── client.py
├── pb
│ ├── helloworld.pb.go
│ └── helloworld.proto
└── server
├── server
└── server.go
gRPC の言語間呼び出し#
次に、gRPC を使用して言語間の RPC 呼び出しを実現する方法を示します。
Python 言語を使用してクライアントを作成し、上記で Go 言語で作成したサーバーに RPC リクエストを送信します。
Python コードの生成#
gRPC_demo
ディレクトリで以下のコマンドを実行します:
python -m grpc_tools.protoc -I helloworld/pb/ --python_out=helloworld/client/ --grpc_python_out=helloworld/client/ helloworld/pb/helloworld.proto
上記のコマンドは、gRPC_demo/helloworld/client/
ディレクトリに以下の 2 つの Python ファイルを生成します:
helloworld_pb2.py
helloworld_pb2_grpc.py
Python 版クライアントの作成#
gRPC_demo/helloworld/client/
ディレクトリに client.py
ファイルを作成し、その内容は以下の通りです:
# coding=utf-8
import logging
import grpc
import helloworld_pb2
import helloworld_pb2_grpc
def run():
# 注意(gRPC Python Team): .close()メソッドはchannelで使用可能です。
# そして、with文がコードの要件に合わない場合に使用するべきです。
with grpc.insecure_channel('localhost:8972') as channel:
stub = helloworld_pb2_grpc.GreeterStub(channel)
response = stub.SayHello(helloworld_pb2.HelloRequest(name='q1mi'))
print("Greeter client received: {}!".format(response.message))
if __name__ == '__main__':
logging.basicConfig()
run()
上記のコードを保存して実行すると、出力結果は以下のようになります:
gRPC_demo $ python helloworld/client/client.py
Greeter client received: Hello q1mi!
これで、Python コードで作成したクライアントが Go 言語版のサーバーを呼び出すことができました。
右側のリンクをクリックして完全なコードを確認してください:gRPC_demo 完全コード
gRPC にはさらに多くの高度な使用法があります。未完待続…