gRPC Conceptsの和訳

この記事は2019/02/19時点のgRPC Concepts?を和訳したものです。

--- 

このドキュメントでは、gRPCのアーキテクチャとRPCライフサイクルの概要とともに、いくつかの重要なgRPCの概念を紹介します。

これは、[What is gRPC？](https://qiita.com/tikidunpon/items/28690424aa09efe81597)を読んだことを前提としています。 言語固有の詳細については、利用可能な場合は、選択した言語のクイックスタート、チュートリアル、およびリファレンスドキュメントを参照してください。

## 概要

### サービス定義  

多くのRPCシステムと同様に、gRPCはサービスを定義し、リモートで呼び出すことができるメソッドとその引数および戻り値の型を指定するという考えに基づいています。 デフォルトでは、gRPCはプロトコルバッファをインタフェース定義言語（IDL）として使用して、サービスインタフェースとペイロードメッセージの構造の両方を記述します。 必要に応じて他の方法を使用することが可能です。

```proto
service HelloService {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  string greeting = 1;
}

message HelloResponse {
  string reply = 1;
}
```

gRPCでは、4種類のサービスメソッドを定義できます。

- 通常の関数呼び出しのように、クライアントがサーバーに1つのリクエストを送信し、1つのレスポンスを返す単項RPC

```proto
rpc SayHello(HelloRequest) returns (HelloResponse){
}
```

- クライアントがサーバーにリクエストを送信し、一連のメッセージを読み取るためのストリームを取得するサーバーストリーミングRPC。 クライアントは、メッセージがなくなるまで、返されたストリームから読み込みます。 gRPCは個々のRPC呼び出し内でのメッセージの順序付けを保証します。

```proto
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse){
}
```

- クライアントストリーミングRPC。ここでクライアントは一連のメッセージを書き込み、再び提供されたストリームを使用してそれらをサーバーに送信します。 クライアントがメッセージの書き込みを終了すると、サーバーがメッセージを読み、そのレスポンスを返すのを待ちます。 また、gRPCは個々のRPC呼び出し内でのメッセージの順序付けを保証します。

```proto
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse) {
}
```

- 双方が読み書きストリームを使用して一連のメッセージを送信する双方向ストリーミングRPC。 2つのストリームは独立して動作するため、クライアントとサーバーは好きな順序で読み書きできます。たとえば、サーバーは、レスポンスを書き込む前にすべてのクライアントメッセージを受信するのを待つことも、メッセージを読み取ってメッセージを書き込むことも、あるいはその他の読み取りと書き込みの組み合わせを行うこともできます。各ストリーム内のメッセージの順序は保持されます。

```proto
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse){
}
```

以下のRPCライフサイクルのセクションで、さまざまな種類のRPCについて詳しく説明します。

### APIサーフェスの利用

`.proto`ファイルのサービス定義から始めて、gRPCはクライアント側とサーバー側のコードを生成するプロトコルバッファコンパイラプラグインを提供します。 gRPCユーザーは通常、クライアント側でこれらのAPIを呼び出し、サーバー側で対応するAPIを実装します。


- サーバー側では、サーバーはサービスによって宣言されたメソッドを実装し、クライアント呼び出しを処理するためにgRPCサーバーを実行します。 gRPCインフラストラクチャは、入ってくるリクエストをデコードし、サービスメソッドを実行し、そしてサービスレスポンスをエンコードします。
- クライアント側では、クライアントにはスタブと呼ばれるローカルオブジェクトがあり（一部の言語では推奨用語はクライアントです）、サービスと同じメソッドを実装しています。 クライアントはローカルオブジェクトのこれらのメソッドを呼び出すだけで、呼び出しのパラメータを適切なプロトコルバッファメッセージタイプにラップできます。gRPCはリクエストをサーバに送信し、サーバのプロトコルバッファのレスポンスを返します。

### 同期 vs 非同期

レスポンスがサーバーから到着するまでブロックする同期RPC呼び出しは、RPCが目指すプロシージャー呼び出しの抽象化に最も近い近似値です。 一方、ネットワークは本質的に非同期であり、多くのシナリオで現在のスレッドをブロックせずにRPCを起動できると便利です。

ほとんどの言語のgRPCプログラミングサーフェスは、同期と非同期の両方の種類があります。 各言語のチュートリアルとリファレンスドキュメントで詳細を確認できます。

## RPCライフサイクル

### 単項RPC

まず、クライアントが単一のリクエストを送信し、単一のレスポンスを返す最も単純なタイプのRPCを見てみましょう。

- クライアントがスタブ/クライアントオブジェクトのメソッドを呼び出すと、この呼び出しに対するクライアントのメタデータ、メソッド名、および該当する場合は指定されたデッドラインでRPCが呼び出されたことがサーバーに通知されます。

- その後、サーバーは独自の初期メタデータ（他のレスポンスの前に送信する必要があります）をすぐに返信するか、クライアントのリクエストメッセージ（最初のアプリケーション固有のもの）を待つことができます。
- サーバーがクライアントのリクエストメッセージを受け取ると、レスポンスを作成してデータを追加するために必要な作業はすべて行われます。レスポンスは（成功した場合）ステータスの詳細（ステータスコードとオプションのステータスメッセージ）およびオプションの後続メタデータと共にクライアントに返されます。
- ステータスが`OK`の場合、クライアントはレスポンスを受け取り、これでクライアント側の呼び出しが完了します。

### サーバーストリーミングRPC  

サーバーストリーミングRPCは、サーバーがクライアントのリクエストメッセージを受け取った後に一連のレスポンスを送り返す点を除けば、単項RPCの例に似ています。すべてのレスポンスを送り返した後、サーバーのステータスの詳細（ステータスコードとオプションのステータスメッセージ）とオプションの後続のメタデータがサーバー側で完了するために送り返されます。クライアントは、サーバーからのすべてのレスポンスを受け取ったら完了します。

### クライアントストリーミングRPC  

クライアントストリーミングRPCも、クライアントが単一のリクエストではなくリクエストのストリームをサーバーに送信することを除けば、この単項RPCの例と似ています。サーバーは通常1つの応答を返しますが、必ずしもその詳細とオプションの後続メタデータと共にすべてのクライアントの要求を受け取った後ではありません。

### 双方向ストリーミングRPC  

双方向ストリーミングRPCでも、呼び出しはクライアントがメソッドを呼び出し、サーバーがクライアントのメタデータ、メソッド名、およびデッドラインを受信することによって開始されます。この場合も、サーバーは最初のメタデータを送り返すか、クライアントがリクエストの送信を開始するのを待つかを選択できます。

クライアントとサーバーは任意の順序で読み書きできるため、次に起こることはアプリケーションによって異なります。ストリームは完全に独立して動作します。したがって、たとえば、サーバーはレスポンスを書き込む前にすべてのクライアントのメッセージを受信するまで待機するか、サーバーとクライアントが「ピンポン」することができます。（サーバーがリクエストを取得してからレスポンスを送信し、次にクライアントが送信するレスポンスに基づいて別のリクエストを送信するなど。）

### デッドライン/タイムアウト

gRPCは、RPCがエラー`DEADLINE_EXCEEDED`で終了するまでに、クライアントがRPCの完了を待つ時間を指定できるようにします。サーバー側では、サーバーは、特定のRPCがタイムアウトしたかどうか、またはRPCを完了するのにどのくらいの時間が残っているかを確認するために照会できます。

デッドラインやタイムアウトの指定方法は言語によって異なります。たとえば、すべての言語にデフォルトのデッドラインがあるわけではなく、一部の言語APIはデッドライン（固定時間）に関して機能し、一部の言語APIはタイムアウトに関して機能します。 （期間）。

### RPCの終了

gRPCでは、クライアントとサーバーの両方が、呼び出しの成功を独立してローカルに判断し、その結論は一致しない可能性があります。これは、例えば、サーバー側では正常に終了したが（「すべてのレスポンスを送信しました！」）、クライアント側では失敗した（「レスポンスはデッドライン後に到着した！」）RPCがあることを意味します。クライアントがすべてのリクエストを送信する前に、サーバーが完了を決定することも可能です。

### RPCのキャンセル  

クライアントまたはサーバーは、いつでもRPCを取り消すことができます。キャンセルするとRPCは直ちに終了し、それ以上の作業は行われません。取り消し（undo）ではありません。キャンセル前に行われた変更はロールバックされません。

### メタデータ  

メタデータは特定のRPC呼び出しに関する情報（認証の詳細など）です。キーと値のペアのリストの形式で表されます。キーは文字列で、値は通常文字列です（ただしバイナリデータでもかまいません）。メタデータは、gRPC自体には不透明です。これにより、クライアントは呼び出しに関連する情報をサーバーに提供できます。 

メタデータへのアクセスは言語に依存します。  

### チャネル  

gRPCチャネルは、指定されたホストとポート上のgRPCサーバへの接続を提供し、クライアントスタブを作成するとき（または一部の言語では単に「クライアント」）に使用されます。クライアントはチャネル引数を指定して、メッセージ圧縮のオン/オフの切り替えなど、gRPCのデフォルトの動作を変更できます。チャネルには、接続およびアイドルを含む状態があります。

gRPCがチャネルのクローズをどのように処理するかは、言語によって異なります。一部の言語では、チャネル状態の照会も許可されています。