1. はじめに
この Codelab では、gRPC-Python を使用して、Python で記述されたルート マッピング アプリケーションの基盤となるクライアントとサーバーを作成します。
このチュートリアルを完了すると、gRPC を使用してリモート サーバーに接続し、地図上の特定の座標にあるものの名前または郵便番号を取得するクライアントが作成されます。本格的なアプリケーションでは、このクライアント サーバー設計を使用して、ルート上のスポットを列挙または要約できます。
サービスは Protocol Buffers ファイルで定義されます。このファイルは、クライアントとサーバーが相互に通信できるように、クライアントとサーバーのボイラープレート コードを生成するために使用されます。これにより、この機能を実装する時間と労力を節約できます。
この生成されたコードは、サーバーとクライアント間の通信の複雑さだけでなく、データのシリアル化と逆シリアル化も処理します。
学習内容
- プロトコル バッファを使用してサービス API を定義する方法。
- 自動コード生成を使用して、プロトコル バッファ定義から gRPC ベースのクライアントとサーバーを構築する方法。
- gRPC を使用したクライアント サーバー通信の理解。
この Codelab は、gRPC を初めて使用する Python デベロッパー、gRPC の復習を希望するデベロッパー、分散システムの構築に関心のある方を対象としています。gRPC の経験は必要ありません。
2. 始める前に
必要なもの
- Python 3.9 以降。Python 3.13 をおすすめします。プラットフォーム固有のインストール手順については、Python の設定と使用をご覧ください。または、uv や pyenv などのツールを使用して、システム以外の Python をインストールします。
- Python パッケージをインストールする pip。
- Python 仮想環境を作成する venv。
ensurepip
パッケージと venv
パッケージは Python 標準ライブラリの一部であり、通常はデフォルトで使用できます。
ただし、Debian ベースのディストリビューション(Ubuntu など)では、Python を再配布する際にこれらを除外することがあります。パッケージをインストールするには、次のコマンドを実行します。
sudo apt install python3-pip python3-venv
コードを取得する
学習を効率化するため、この Codelab では、すぐに始められるように、あらかじめ作成されたソースコード スキャフォールドが用意されています。次の手順では、grpc_tools.protoc
Protocol Buffer コンパイラ プラグインを使用した gRPC コード生成など、アプリケーションの完成までの手順について説明します。
grpc-codelabs
この Codelab のスキャフォールディング ソースコードは、codelabs/grpc-python-getting-started/start_here ディレクトリにあります。コードを自分で実装しない場合は、完成したソースコードが completed
ディレクトリにあります。
まず、Codelab の作業ディレクトリを作成し、そのディレクトリに移動します。
mkdir grpc-python-getting-started && cd grpc-python-getting-started
Codelab をダウンロードして解凍します。
curl -sL https://github.com/grpc-ecosystem/grpc-codelabs/archive/refs/heads/v1.tar.gz \
| tar xvz --strip-components=4 \
grpc-codelabs-1/codelabs/grpc-python-getting-started/start_here
または、Codelab ディレクトリのみを含む .zip ファイルをダウンロードして、手動で解凍することもできます。
3. サービスを定義する
まず、プロトコル バッファ インターフェース定義言語を使用して、アプリケーションの gRPC サービス、RPC メソッド、リクエストとレスポンスのメッセージ タイプを定義します。サービスでは以下を提供します。
- サーバーが実装し、クライアントが呼び出す
GetFeature
という RPC メソッド。 - メッセージ タイプ
Point
とFeature
は、GetFeature
メソッドを使用するときにクライアントとサーバー間で交換されるデータ構造です。クライアントは、サーバーへのGetFeature
リクエストで地図の座標をPoint
として提供し、サーバーはそれらの座標にあるものを説明する対応するFeature
で応答します。
この RPC メソッドとそのメッセージ型はすべて、提供されたソースコードの protos/route_guide.proto
ファイルで定義されます。
Protocol Buffers は一般に protobuf と呼ばれます。gRPC の用語の詳細については、gRPC の コア コンセプト、アーキテクチャ、ライフサイクルをご覧ください。
メッセージのタイプ
ソースコードの protos/route_guide.proto
ファイルで、まず Point
メッセージ タイプを定義します。Point
は、地図上の緯度と経度の座標ペアを表します。この Codelab では、座標に整数を使用します。
message Point {
int32 latitude = 1;
int32 longitude = 2;
}
数値 1
と 2
は、message
構造内の各フィールドの一意の ID 番号です。
次に、Feature
メッセージ タイプを定義します。Feature
は、Point
で指定された場所にあるものの名前または郵便番号に string
フィールドを使用します。
message Feature {
// The name or address of the feature.
string name = 1;
// The point where the feature is located.
Point location = 2;
}
サービス メソッド
route_guide.proto
ファイルには、アプリケーションのサービスによって提供される 1 つ以上のメソッドを定義する RouteGuide
という名前の service
構造があります。
RouteGuide
定義内に rpc
メソッド GetFeature
を追加します。前述のとおり、このメソッドは指定された座標セットから場所の名前または住所を検索するため、指定された Point
に対して GetFeature
が Feature
を返すようにします。
service RouteGuide {
// Definition of the service goes here
// Obtains the feature at a given position.
rpc GetFeature(Point) returns (Feature) {}
}
これは単項 RPC メソッドです。クライアントがサーバーにリクエストを送信し、ローカル関数呼び出しと同様にレスポンスが返ってくるのを待つシンプルな RPC です。
4. クライアント コードとサーバーコードを生成する
次に、プロトコル バッファ コンパイラを使用して、.proto
ファイルからクライアントとサーバーの両方のボイラープレート gRPC コードを生成します。
gRPC Python コード生成用に、grpcio-tools を作成しました。次の内容が含まれます。
message
定義から Python コードを生成する通常の protoc コンパイラ。service
定義から Python コード(クライアントとサーバースタブ)を生成する gRPC protobuf プラグイン。
pip を使用して grpcio-tools
Python パッケージをインストールします。プロジェクトの依存関係をシステム パッケージから分離するために、新しい Python 仮想環境(venv)を作成しましょう。
python3 -m venv --upgrade-deps .venv
bash/zsh シェルで仮想環境を有効にするには:
source .venv/bin/activate
Windows と標準以外のシェルについては、https://docs.python.org/3/library/venv.html#how-venvs-work の表をご覧ください。
次に、grpcio-tools をインストールします(これにより、grpcio パッケージもインストールされます)。
pip install grpcio-tools
次のコマンドを使用して、Python ボイラープレート コードを生成します。
python -m grpc_tools.protoc --proto_path=./protos \
--python_out=. --pyi_out=. --grpc_python_out=. \
./protos/route_guide.proto
これにより、route_guide.proto
で定義したインターフェースに対して次のファイルが生成されます。
route_guide_pb2.py
には、message
定義から生成されたクラスを動的に作成するコードが含まれています。route_guide_pb2.pyi
は、message
定義から生成された「スタブファイル」または「型ヒントファイル」です。実装のないシグネチャのみが含まれています。スタブファイルは、IDE でより優れたオートコンプリートとエラー検出を提供するために使用できます。route_guide_pb2_grpc.py
はservice
定義から生成され、gRPC 固有のクラスと関数が含まれています。
gRPC 固有のコードには次のものが含まれます。
RouteGuideStub
。これは、gRPC クライアントが RouteGuide RPC を呼び出すために使用できます。RouteGuideServicer
。これは、RouteGuide
サービスの実装のインターフェースを定義します。RouteGuideServicer
を gRPC サーバーに登録するために使用されるadd_RouteGuideServicer_to_server
関数。
5. サービスを作成する
まず、RouteGuide
サーバーの作成方法を見てみましょう。RouteGuide
サーバーの作成と実行は、次の 2 つの作業項目に分かれます。
- サービス定義から生成されたサービサー インターフェースを、サービスの実際の「作業」を行う関数で実装します。
- 特定のポートで gRPC サーバーを実行して、クライアントからのリクエストをリッスンし、レスポンスを送信する。
初期の RouteGuide
サーバーは start_here/route_guide_server.py
にあります。
RouteGuide を実装する
route_guide_server.py
には、生成されたクラス route_guide_pb2_grpc.RouteGuideServicer
をサブクラス化する RouteGuideServicer
クラスがあります。
# RouteGuideServicer provides an implementation
# of the methods of the RouteGuide service.
class RouteGuideServicer(route_guide_pb2_grpc.RouteGuideServicer):
RouteGuideServicer
は、すべての RouteGuide
サービス メソッドを実装します。
簡単な RPC 実装について詳しく見ていきましょう。メソッド GetFeature
は、クライアントから Point
を取得し、データベースから対応する特徴情報を Feature
で返します。
def GetFeature(self, request, context):
feature = get_feature(self.db, request)
if feature is None:
return route_guide_pb2.Feature(name="", location=request)
else:
return feature
このメソッドには、RPC の route_guide_pb2.Point
リクエストと、タイムアウトの制限などの RPC 固有の情報を提供する grpc.ServicerContext
オブジェクトが渡されます。route_guide_pb2.Feature
レスポンスが返されます。
サーバーを起動する
RouteGuide
メソッドをすべて実装したら、次のステップとして、クライアントが実際にサービスを使用できるように gRPC サーバーを起動します。
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
route_guide_pb2_grpc.add_RouteGuideServicer_to_server(
RouteGuideServicer(),
server,
)
listen_addr = "localhost:50051"
server.add_insecure_port(listen_addr)
print(f"Starting server on {listen_addr}")
server.start()
server.wait_for_termination()
サーバーの start()
メソッドはブロックされません。リクエストを処理するために新しいスレッドがインスタンス化されます。server.start()
を呼び出すスレッドは、その間に行う他の処理がないことがよくあります。この場合、server.wait_for_termination()
を呼び出して、サーバーが終了するまで呼び出しスレッドをクリーンにブロックできます。
6. クライアントを作成する
このセクションでは、RouteGuide
サービスのクライアントを作成する方法について説明します。初期のクライアント コードは start_here/route_guide_client.py
で確認できます。
スタブを作成する
サービス メソッドを呼び出すには、まずスタブを作成する必要があります。
route_guide_client.py
ファイル内の .proto
から生成された route_guide_pb2_grpc
モジュールの RouteGuideStub
クラスをインスタンス化します。
channel = grpc.insecure_channel("localhost:50051")
stub = route_guide_pb2_grpc.RouteGuideStub(channel)
サービス メソッドの呼び出し
単一のレスポンスを返す RPC メソッド(レスポンス単項メソッド)の場合、gRPC Python は同期(ブロッキング)と非同期(ノンブロッキング)の両方の制御フロー セマンティクスをサポートします。
Simple RPC
まず、サービスを呼び出すための Point
を定義しましょう。これは、いくつかのプロパティを持つ route_guide_pb2
パッケージからオブジェクトをインスタンス化するのと同じくらい簡単です。
point = route_guide_pb2.Point(latitude=412346009, longitude=-744026814)
シンプルな RPC GetFeature
の同期呼び出しは、ローカル メソッドの呼び出しとほぼ同じくらい簡単です。RPC 呼び出しはサーバーからの応答を待機し、応答を返すか例外を発生させます。メソッドを呼び出して、次のようにレスポンスを確認できます。
feature = stub.GetFeature(point)
print(feature)
Feature オブジェクトのフィールドを調べて、リクエストの結果を出力できます。
if feature.name:
print(f"Feature called '{feature.name}' at {format_point(feature.location)}")
else:
print(f"Found no feature at at {format_point(feature.location)}")
7. 試してみる
サーバーを実行します。
python route_guide_server.py
別のターミナルで、仮想環境を再度アクティブにして、クライアントを実行します。
python route_guide_client.py
次のような出力が表示されます(わかりやすくするため、タイムスタンプは省略されています)。
name: "16 Old Brook Lane, Warwick, NY 10990, USA" location { latitude: 412346009 longitude: -744026814 } Feature called '16 Old Brook Lane, Warwick, NY 10990, USA' at latitude: 412346009, longitude: -744026814
8. 次のステップ
- gRPC の概要とコアコンセプトで gRPC の仕組みを確認する
- 基本チュートリアルに取り組む
- Python API リファレンスを確認する