connect-goとは
gRPC互換のサーバ―クライアント間通信プロトコルであるConnectの、Go言語実装。
Protocol BuffersでAPI設計を記述し、専用プログラムでトランスパイルすることで、
API設計に則った通信をするためのインターフェイス(Go言語コード)が生成できるようにする仕組み。
内部的にHTTP/1.1プロトコルによる通信を行っている。(gRPCはHTTP/2.0だが、ConnectはHTTP/2.0非対応環境でも使用可能となっている)
ProtocolBuffers → [ 専用Connectプログラム ] → インターフェイスコード(Go言語)
Connectは、Go言語向けのconnect-go以外にも、Webフロントエンド向けのconnect-webや、Androidアプリ向けのconnect-kotlinなども提供している。
なぜサーバ―サーバ間通信なのか
近年はLinux搭載ボードをメーカーが製品に使う機会が増えてきている。
従来は低レイヤーの設計も含めて「組込みソフト」としてメーカー自身で作り込んできたものが、
最近はLinux前提で高レイヤー部分だけをメーカーが作り込むケースも出てきている。
背景にはエンドユーザが求める機能水準の高度化やハードウェア部品の高機能化など様々な事情の変化が絡んでいるが、
Linux前提の開発が増えてきたことでプロセス間通信の常識も変わってきたように思う。
従来であれば共有メモリやパイプを使ってプロセス間通信を実現してきたと思うが、
Linuxとそれが「普通に」動作する基板が前提となる環境であればまずTCP/IP対応している場合が多い。
TCP/IP対応していればまずループバックアドレス(localhost:127.0.0.1)が使えるものだが、
ループバックアドレスを使った「自分自身への通信」は基板外部に漏れることはないため、
プロセス間通信を実現する手段の一つの候補となる。
加えて、先に挙げたConnectと組み合わせることで、開発者はビジネスロジックに注力しながら従来には無い手軽さでプロセス間通信が実現できるようになった。
Connectは本来、サーバ―クライアント間通信に用いる道具ではあるが、
これをそのままプロセス間通信に適用しようとすると時間の経過によるプロセス間の「コネクション切れ=プロセス間通信の意図しない遮断」につながる場合があるため、
各プロセスにサーバ機能を持たせて互いに能動的に通信させる実験をしてみた。
やったことの概要
サーバの設計(すっごくざっくり)
実験なので、最低限の機能だけ。
- ConnectサーバとしてAPIを公開する機能
- 他のプログラムが公開しているAPIを叩く機能=Connectクライアント機能
サーバ・クライアント双方の機能を併せ持つプログラムが必要。
サーバ―サーバ間通信できることが実証できれば良いので、複数立ち上げるプログラムは同一、プロセスと待受ポート番号が別となるようにする。
待受ポート番号は起動引数で指定できるようにする。
プロセス間通信実験のシーケンス図
下図のようにServerAとServerBの2つのConnectサーバを立ち上げ、相互に通信できることを確認する。
Protocol BuffersによるAPI定義
Protocol BuffersはConnectに限ったものではないため、Protocol Buffers自体の説明は割愛。
次のように1つのサービス、1つのUnary RPCだけ定義した。
yntax = "proto3";
package greet.v1;
option go_package = "example/gen/greet/v1;greetv1";
message GreetRequest {
string name = 1;
}
message GreetResponse {
string greeting = 1;
}
service GreetService {
rpc Greet(GreetRequest) returns (GreetResponse) {}
}
Protocol Buffersのトランスパイル
Connect公式サイトを参考に、Go言語用インターフェイスコードを生成した。
実験用サーバのソースコード
次のリンク先で公開している。
サーバ機能用・クライアント機能用それぞれにゴルーチンを用意し、
1つのプロセス内で合計2つのゴルーチンが並行処理する構成となっている。
サーバ立ち上げ
ターミナルを2つ開きそれぞれで次のコマンドを実行した。
# ServerA立ち上げ
cd cmd/server2server
go run main.go -MyPort 8080 -PartnerPort 8081 -ServerName ServerA
# ServerB立ち上げ
cd cmd/server2server
go run main.go -MyPort 8081 -PartnerPort 8080 -ServerName ServerB
サーバ―サーバ間通信の実行・結果
ターミナルそれぞれで文字を打ち込み、サーバ間でAPIを互いに呼び出し合った。
ServerAのターミナル:
Tom
ServerBのAPIからの返答:
Hello, Tom! by.ServerB
ServerBのターミナル:
Bob
ServerAのAPIからの返答:
Hello, Bob! by.ServerA
まとめ
Connectのサーバ―サーバ間通信によりプロセス間通信が比較的簡単に実現できることが分かった。