RPCの基礎と核心技術

RPCとは何か

RPC(Remote Procedure Call)は、ネットワークを通じて遠隔地のコンピュータプログラムからサービスを要求するためのプロトコルです。低レベルのネットワーク技術を意識することなく利用できます。RPCプロトコルはTCPやUDPなどの伝送プロトコルの存在を前提としており、通信プログラム間で情報を伝達します。OSI通信モデルにおいて、RPCは伝送層とアプリケーション層にまたがる機能を持ちます。

RPCはクライアント/サーバーモデルを採用しています。クライアントが呼び出しリクエストをサーバーに送信し、サーバーがパラメータを受け取って処理を行い、結果をクライアントに返却します。この仕組みにより、分散システムの開発が容易になります。

なぜRPCが必要なのか

アプリケーション開発が進展するにつれて、単一のアプリケーションでは対応しきれない状況が生まれます。業務が複雑化し、トラフィックが増えた際には、システムを複数の独立したアプリケーションに分割することが一般的です。しかし、共通のビジネスロジックが存在する場合、それらを独立したサービスとして切り出すことで、再利用性と保守性が向上します。このような場面で、効率的なアプリケーション間通信手段としてRPCが活躍します。これはまさにサービス指向アーキテクチャ(SOA)やマイクロサービスアーキテクチャの基盤となる考え方です。

RPCの動作原理と構成要素

Nelsonの論文によると、RPCの実装には以下の5つの要素があります:

  • User(クライアント)
  • User-stub(クライアント側スタブ)
  • RPCRuntime(RPCランタイム)
  • Server-stub(サーバー側スタブ)
  • Server(サーバー)

クライアントはUser-stubを介してリモート呼び出しを行います。User-stubは呼び出し情報をエンコードし、RPCRuntimeを通じてサーバーへ転送します。サーバー側ではServer-stubがデコードを行い、ローカルの処理を実行し、結果をクライアントへ返します。

RPCフレームワークの主要コンポーネント

  • RpcServer: リモートインターフェースの公開
  • RpcClient: リモートインターフェースのインポート
  • RpcProxy: インターフェースのプロキシ実装
  • RpcInvoker: 呼び出し情報のエンコード・デコードと実行
  • RpcProtocol: プロトコルのエンコード・デコード
  • RpcConnector: クライアントとサーバー間の接続維持
  • RpcAcceptor: クライアントからのリクエスト受信
  • RpcProcessor: 呼び出しプロセスの制御
  • RpcChannel: データ伝送チャネル

代表的なJava RPCフレームワーク

  • Thrift: 複数言語に対応したサービス開発フレームワーク。C++、Java、Pythonなど多くの言語をサポート。
  • Dubbo: アリババが開発した分散サービスフレームワーク。高性能なNIO通信、動的サービスディスカバリ、負荷分散などを提供。
  • Spring Cloud: マイクロサービス向けツール群。設定管理、サービスディスカバリ、サーキットブレーカーなどの機能を含む。

RPCとメッセージキューの比較

比較項目RPCメッセージキュー
同期性同期呼び出しが可能非同期単方向通信
リアルタイム性即時応答遅延処理可能
信頼性直接通信中間ノード依存
適用場景同期応答が必要な処理バッチ処理、負荷分散

RPCフレームワークの核心技術

1. サービスの公開と取得

リモートサービスの利用には、インターフェース定義やデータ構造などの情報を共有する必要があります。ThriftのIDLファイルやWebサービスのWSDLファイルなどがこれに該当します。クロスプラットフォーム対応ではコードジェネレータによるスタブ生成が一般的ですが、同じ言語内では実行時コード生成も可能です。

Javaにおけるポリモーフィズム(多態性)の場合は、どの実装クラスを呼び出すかを明示的に指定する必要があります。例えば、同じインターフェースに複数の実装がある場合、エクスポート時に識別子を付与し、呼び出し時にその識別子を渡すことで適切な実装を選択します。

2. リモートプロキシオブジェクト

クライアントが使用するのは実際にはローカルのプロキシオブジェクトです。JavaではJDK動的プロキシまたはバイトコード生成技術を使用して実現します。動的プロキシは使いやすいもののパフォーマンスは劣り、バイトコード生成は効率的だが可読性に欠けるというトレードオフがあります。

3. 通信機構

RPCはHTTPやTCPなどのプロトコル上で動作します。WebサービスはHTTPベースのRPCですが、TCPベースの方がパフォーマンスが優れています。

  • TCP vs HTTP: TCPは伝送層プロトコル、HTTPはアプリケーション層プロトコルであり、より低レベルのTCPの方が高速。
  • メッセージID: 各メッセージにユニークIDを割り当てることで、コネクションの再利用が容易になる。
  • IO方式: 高並列処理にはブロッキングIOではなくNIO(非同期IO)を使用。
  • マルチコネクション: 大容量データ転送時は複数コネクションによるバッファ分散が効果的。
  • ハートビート: 負荷分散装置経由の場合、定期的にハートビート信号を送信して接続を維持。

4. シリアライゼーション

RPCのパフォーマンスに影響を与える主な要素は伝送方式とシリアライゼーションです。

シリアライゼーション方式

Java標準のシリアライゼーションは高負荷時にボトルネックとなるため、Protobuf、Kryo、Hessian、Jacksonなどの代替技術が利用されます。

エンコード内容

-- 呼び出し情報 --
1. インターフェースメソッド(名前、パラメータ)
2. メソッド引数(型、値)
3. 呼び出し属性(タイムアウト時間、隠しパラメータ)

-- 戻り情報 --
1. 戻り値
2. ステータスコード
3. 例外情報

プロトコルメッセージ設計例

-- メッセージヘッダー --
magic       : プロトコル識別子
header size : ヘッダーサイズ
version     : プロトコルバージョン
st          : シリアライズ種別
hb          : ハートビートフラグ
rp          : レスポンスフラグ
status code : ステータスコード
message id  : メッセージID
body size   : ボディサイズ

-- メッセージボディ --
xml/json/binaryなど任意の形式でシリアライズ

タグ: RPC 分散システム マイクロサービス Thrift Dubbo

9月26日 22:04 投稿