Rpcx - Golang learning step 10-2
- 公開日
- カテゴリ:ToolForMicroservices
- タグ:Golang,roadmap.sh,学習メモ

roadmap.sh > Go > Tool for Microservices > Rpcx の学習を進めていきます。
※ 学習メモとしての記録ですが、後にこのセクションを学ぶ道しるべとなるよう、ですます調で記載しています。
contents
開発環境
- チップ: Apple M2 Pro
- OS: macOS Sonoma
- go version: go1.23.2 darwin/arm64
参考 URL
Rpcx
Rpcx は、Go で実装された高性能な RPC (Remote Procedure Call) フレームワークです。gRPC に似ていますが、よりシンプルで Go に特化した設計がされています。以下の特徴があります。
- 高性能: バイナリプロトコルによる高速通信
- シンプルな API: サーバー・クライアントの実装が簡単
- プラグイン対応: ロードバランシングやサービスディスカバリーを簡単に導入可能
Rpcx のインストール
Go のプロジェクトをセットアップし、Rpcx をインストールします。
go mod init rpcx-example
go get github.com/smallnest/rpcx
最小構成での rpcx サーバー構築
以下のファイルを作成し、まずは最小構成で rpcx サーバー構築していきます。
この章で作成するファイルは以下です。
rpcx-example/
├── client.go
├── server.go
└── types/
└── hello.go
1. リクエスト・レスポンスの構造体定義
これから実装する SayHello メソッドの入出力に使われるリクエスト(input)とレスポンスの構造体を定義します。
types/hello.go
package types
// HelloRequest はクライアントが送るリクエストの構造体
type HelloRequest struct {
Name string
}
// HelloResponse はサーバーが返すレスポンスの構造体
type HelloResponse struct {
Message string
}
2. rpcx サーバーの実装
サーバーを作成し、クライアントからリモート呼び出しできる関数を定義します。
server.go
package main
import (
"context"
"fmt"
"log"
"github.com/smallnest/rpcx/server"
"rpcx-example/types"
)
// HelloService リモートから呼び出せるメソッドを持つ構造体
type HelloService struct{}
// SayHello リモートから呼び出されるメソッド
func (h *HelloService) SayHello(ctx context.Context, args *types.HelloRequest, reply *types.HelloResponse) error {
reply.Message = fmt.Sprintf("Hello, %s!", args.Name)
return nil
}
func main() {
s := server.NewServer()
err := s.RegisterName("HelloService", new(HelloService), "") // HelloService を登録
fmt.Println("RPCサーバーを起動します...")
if err := s.Serve("tcp", ":8972"); err != nil {
log.Fatalf("サーバー起動エラー: %v", err)
}
}
3. クライアントの実装
次に、この RPC サーバーに接続し、SayHello メソッドを呼び出すクライアントを作成します。
package main
import (
"context"
"fmt"
"log"
"github.com/smallnest/rpcx/client"
"rpcx-example/types"
)
func main() {
d, _ := client.NewPeer2PeerDiscovery("tcp@localhost:8972", "")
xclient := client.NewXClient("HelloService", client.Failover, client.RandomSelect, d, client.DefaultOption)
defer xclient.Close()
args := &types.HelloRequest{Name: "Go Developer"}
reply := &types.HelloResponse{}
// RPC メソッド呼び出し
err := xclient.Call(context.Background(), "SayHello", args, reply)
if err != nil {
log.Fatalf("RPCエラー: %v", err)
}
fmt.Println("サーバーからのレスポンス:", reply.Message)
}
4. サーバー起動と動作確認
ターミナルを2つ開き、それぞれ以下のコマンドを実行します。
# 1. RPC サーバーを起動
go run server.go
# 2.(別のターミナル)クライアントを実行
go run client.go
クライアントを実行すると、サーバーが SayHello を実行し、以下のようなレスポンスが返ります。
サーバーからのレスポンス: Hello, Go Developer!
server.go
一つで rpcx サーバーを実現できました。
Protocol Buffers の導入
types/hello.go
で定義した HelloRequest や HelloResponse を Protocol Buffers(protobuf) で定義することもできます。これにより、型の明確化、クロス言語対応、バイナリシリアライズによる効率化 が可能になります。
protoc
をインストールします。(protobuf を Go で使うためには protoc も必要)
# Mac の場合
brew install protobuf
# Linux の場合(Ubuntu)
sudo apt install -y protobuf-compiler
# Windows の場合
# 公式サイトからダウンロード: https://github.com/protocolbuffers/protobuf/releases
protobuf
をインストールします。
go get -u google.golang.org/protobuf
Protocol Buffers を使う構成
現在のディレクトリ構成を、Protocol Buffers を使うように拡張すると、最終的に以下のようになります。
rpcx-example/
├── client.go
├── server.go
├── proto/
│ ├── hello.proto # Protocol Buffers の定義ファイル
│ ├── hello.pb.go # protoc で生成された Go コード
1. Protocol Buffers の定義
まず、proto/hello.proto を作成します。
proto/hello.proto
syntax = "proto3";
package proto;
option go_package = "rpcx-example/proto"; // Go のパッケージ名を指定
// HelloRequest: クライアントから送られるリクエスト
message HelloRequest {
string name = 1;
}
// HelloResponse: サーバーが返すレスポンス
message HelloResponse {
string message = 1;
}
2. Protocol Buffers の Go コードを生成
Protocol Buffers を Go で使うには、以下のツールをインストールする必要があります。
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
以下、protoc コマンドを実行し、.proto
から .pb.go
を生成します。
protoc --go_out=. --go_opt=paths=source_relative proto/hello.proto
このコマンドを実行すると、proto/hello.pb.go
が自動生成されます。
3. server.go の修正
Protocol Buffers の proto/hello.pb.go
を使うように修正します。
package main
import (
"context"
"fmt"
"log"
"github.com/smallnest/rpcx/server"
"rpcx-example/proto" // Protocol Buffers のパッケージをインポート
)
// HelloService: RPC サーバーのサービス
type HelloService struct{}
// SayHello: リモートで呼び出されるメソッド
func (h *HelloService) SayHello(ctx context.Context, args *proto.HelloRequest, reply *proto.HelloResponse) error {
reply.Message = fmt.Sprintf("Hello, %s!", args.Name)
return nil
}
func main() {
s := server.NewServer()
err := s.RegisterName("HelloService", new(HelloService), "")
if err != nil {
return
} // サービスを登録
fmt.Println("RPCサーバーを起動します...")
if err := s.Serve("tcp", ":8972"); err != nil {
log.Fatalf("サーバー起動エラー: %v", err)
}
}
4. client.go の修正
client.go
も proto/hello.pb.go
を使うように修正します。
package main
import (
"context"
"fmt"
"log"
"github.com/smallnest/rpcx/client"
"rpcx-example/proto" // Protocol Buffers のパッケージをインポート
)
func main() {
d, _ := client.NewPeer2PeerDiscovery("tcp@localhost:8972", "")
client.DefaultOption.SerializeType = protocol.ProtoBuffer // シリアライズ方式を protobuf に設定
xclient := client.NewXClient("HelloService", client.Failover, client.RandomSelect, d, client.DefaultOption)
defer xclient.Close()
args := &proto.HelloRequest{Name: "Go Developer"}
reply := &proto.HelloResponse{}
// RPC メソッド呼び出し
err := xclient.Call(context.Background(), "SayHello", args, reply)
if err != nil {
log.Fatalf("RPCエラー: %v", err)
}
fmt.Println("サーバーからのレスポンス:", reply.Message)
}
動作確認
サーバーを起動し、クライアントを実行します
# 1. RPC サーバーを起動
go run server.go
# 2.(別のターミナル)クライアントを実行
go run client.go
実行結果:
サーバーからのレスポンス: Hello, Go Developer!
rpcx と gRPC の違い
gRPC は、Google によって開発された 高性能な RPC(Remote Procedure Call)フレームワーク です。rpcx も Go 向けの RPC フレームワークですが、gRPC は クロス言語対応 や 強力なストリーミング機能 などを備えた RPC システムです。
比較項目 | rpcx | gRPC |
---|---|---|
開発元 | コミュニティ開発 | Google 開発・維持 |
通信プロトコル | 独自バイナリプロトコル(Go RPC) | HTTP/2(TLS対応) |
シリアライズ | gob(デフォルト)、protobuf、JSON | protobuf(標準) |
クロス言語対応 | Go のみ(他言語バインディングなし) | Go, Java, Python, C++, Rust など |
ストリーミング | なし(非同期処理は可能) | 双方向ストリーミング対応 |
ロードバランス | クライアント側で可能 | 内蔵ロードバランスあり |
認証 | 独自実装が必要 | TLS/SSL & Google Auth 対応 |
サービスディスカバリー | etcd, Consul などと連携 | Kubernetes, etcd, Consul など |
拡張性 | etcd, Consul との連携可能だがエコシステムは小規模 | Google Cloud, Istio など広範なエコシステム |
rpcx は Go プログラム内でシンプルに使えますが、gRPC はマイクロサービスや分散システムで広く採用されているのが特徴です。
rpcx も優れたフレームワークですが、gRPC には以下のような利点があります。
項目 | 説明 |
---|---|
クロスプラットフォーム対応 | 複数のプログラミング言語と通信可能(Go, Java, Python など) |
高性能通信 | HTTP/2 を活用し、高速で効率的なデータ転送が可能 |
双方向ストリーミング | クライアント・サーバー間でリアルタイムなデータ通信が可能 |
強力な認証機能 | TLS/SSL や Google 認証が標準で利用可能 |
ロードバランス内蔵 | クライアント・サーバー間の負荷分散が組み込みで利用可能 |
豊富なエコシステム | Kubernetes との親和性が高く、クラウド環境向けに最適化 |
これらより、rpcx は Go のプロジェクト内で軽量な RPC を作るのに便利 ですが、gRPC は 企業レベルのマイクロサービスやクロス言語環境に適しています。
rpcx から gRPC へ移行するメリット
- クロスプラットフォーム対応(Go 以外の言語とも通信できる)
- HTTP/2 による高性能な通信
- 双方向ストリーミングやチャットのような機能が簡単に実装可能
- ロードバランシングや認証のサポートが強力
もし Go 内部での RPC だけを考えるなら rpcx で十分ですが、マイクロサービスの拡張性や他言語との連携を考えるなら、gRPC の方が優れた選択肢になるでしょう。
rpcx から gRPC へ移行を検討すべきケース
以下のような要件がある場合は、rpcx から gRPC への移行を検討するとよいでしょう。
- 複数のプログラミング言語で通信したい: rpcx は Go 専用だが、gRPC は他の言語とも通信可能
- HTTP/2 による効率的な通信が必要: gRPC は HTTP/2 を標準採用し、効率的な通信が可能
- 双方向ストリーミングが必要: rpcx にはない機能で、リアルタイム通信に適用可能
- マイクロサービス環境での採用を検討している: gRPC は Kubernetes との親和性が高く、大規模システム向き
- ロードバランシングや認証を組み込みで利用したい: gRPC なら標準機能で提供されるため、実装コストを削減できる
一方で、Go 内部での RPC 通信をシンプルに実装したい場合は、rpcx が有力な選択肢となります。
まとめ
- Rpcx は Go に特化した高性能な RPC フレームワーク
- デフォルトのシリアライズ方式は gob
- Protocol Buffers を利用する場合、
SerializeType
をprotocol.ProtoBuffer
に設定する必要あり
- Protocol Buffers を利用する場合、
- 最小構成でサーバーとクライアントを実装可能
- Protocol Buffers を導入することで型の明確化やクロス言語対応が可能
- gRPC はクロスプラットフォーム対応やストリーミング機能を備える
- rpcx は Go 内部の RPC に適し、シンプルで軽量
- gRPC はマイクロサービス環境や多言語対応が求められる場合に有用
[Next] Step 10-3: Micro
[Prev] Step 10-1: gRPC-Gateway