Rpcx - Golang learning step 10-2

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

roadmap.sh > Go > Tool for Microservices > Rpcx の学習を進めていきます。

※ 学習メモとしての記録ですが、後にこのセクションを学ぶ道しるべとなるよう、ですます調で記載しています。

contents

  1. 開発環境
  2. 参考 URL
  3. Rpcx
  4. Rpcx のインストール
  5. 最小構成での rpcx サーバー構築
    1. 1. リクエスト・レスポンスの構造体定義
    2. 2. rpcx サーバーの実装
    3. 3. クライアントの実装
    4. 4. サーバー起動と動作確認
  6. Protocol Buffers の導入
    1. Protocol Buffers を使う構成
    2. 1. Protocol Buffers の定義
    3. 2. Protocol Buffers の Go コードを生成
    4. 3. server.go の修正
    5. 4. client.go の修正
    6. 動作確認
  7. rpcx と gRPC の違い
    1. rpcx から gRPC へ移行するメリット
    2. rpcx から gRPC へ移行を検討すべきケース

開発環境

  • チップ: 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.goproto/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 システムです。

比較項目rpcxgRPC
開発元コミュニティ開発Google 開発・維持
通信プロトコル独自バイナリプロトコル(Go RPC)HTTP/2(TLS対応)
シリアライズgob(デフォルト)、protobuf、JSONprotobuf(標準)
クロス言語対応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 を利用する場合、SerializeTypeprotocol.ProtoBuffer に設定する必要あり
  • 最小構成でサーバーとクライアントを実装可能
  • Protocol Buffers を導入することで型の明確化やクロス言語対応が可能
  • gRPC はクロスプラットフォーム対応やストリーミング機能を備える
  • rpcx は Go 内部の RPC に適し、シンプルで軽量
  • gRPC はマイクロサービス環境や多言語対応が求められる場合に有用


[Next] Step 10-3: Micro

[Prev] Step 10-1: gRPC-Gateway

Author

rito

  • Backend Engineer
  • Tokyo, Japan
  • PHP 5 技術者認定上級試験 認定者
  • 統計検定 3 級