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

roadmap.sh > Go > Tool for Microservices > go-zero の学習を進めていきます。
※ 学習メモとしての記録ですが、後にこのセクションを学ぶ道しるべとなるよう、ですます調で記載しています。
contents
開発環境
- チップ: Apple M2 Pro
- OS: macOS Sonoma
- go version: go1.23.2 darwin/arm64
参考 URL
go-zero
go-zero は、軽量で効率的な Go 向けの API フレームワーク です。 マイクロサービスの開発を簡単にし、パフォーマンスを最適化するための機能が組み込まれています。
- 高パフォーマンス:ゼロコストの RPC を実現する zrpc を採用。
- シンプルなコード生成:goctl を使用して自動的に API コードを生成できる。
- 組み込みミドルウェア:認証やロギングなどが簡単に設定可能。
- 統合された RPC & REST API:REST と gRPC の両方をサポート。
インストール
プロジェクトの初期化
mkdir go_zero_sample
cd go_zero_sample
go mod init go_zero_sample
go-zero では goctl
コマンドを使ってファイル生成を行うためこれをインストールします。
go install github.com/zeromicro/go-zero/tools/goctl@latest
go-zero をインストールします。
go get -u github.com/zeromicro/go-zero
API の作成
goctl
コマンドを使って API を作成します。
.api ファイル作成
goctl api -o user/user.api
goctl
コマンドで生成された user/user.api
を編集してエンドポイントを定義します。
syntax = "v1"
type getUserRequest {
UserId string `path:"userId"`
}
type getUserResponse {
Message string `json:"message"`
}
service user-api {
@handler GetUser
get /users/id/:userId (getUserRequest) returns (getUserResponse)
}
以下 goctl
コマンドで Go のサーバーサイドコードを生成します。
goctl api go -api user/user.api -dir user
以下ファイル群が生成されます。
user
├── etc
│ └── user-api.yaml
├── internal
│ ├── config
│ │ └── config.go
│ ├── handler
│ │ ├── getuserhandler.go
│ │ └── routes.go
│ ├── logic
│ │ └── getuserlogic.go
│ ├── svc
│ │ └── servicecontext.go
│ └── types
│ └── types.go
├── user.api
└── user.go
user/internal/logic/getuserlogic.go
に GetUser を実装します。
func (l *GetUserLogic) GetUser(req *types.GetUserRequest) (resp *types.GetUserResponse, err error) {
return &types.GetUserResponse{
Message: fmt.Sprintf("Hello World, UserId: %s", req.UserId),
}, nil
}
ここまでやるとエンドポイントが動作するので実際に確認してみます。
user-api サーバーを起動させます。
cd user
go mod tidy
go run user.go -f etc/user-api.yaml
エンドポイントにリクエストを送信します。
curl -i http://localhost:8888/users/id/123
レスポンス:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Traceparent: xxxxx
Date: Tue, 11 Feb 2025 23:53:03 GMT
Content-Length: 38
{"message":"Hello World, UserId: 123"}
ミドルウェア
ミドルウェアは、リクエストとレスポンスの間に処理を挟む仕組みです。
例えば、以下のような処理を自動化できます。
- ロギング(リクエストの記録)
- 認証(JWT の検証)
- リクエストの前処理(ヘッダーの検査)
- レスポンスの後処理(データの圧縮)
ミドルウェアの実装
参考: https://go-zero.dev/en/docs/tutorials/api/middleware
リクエストの開始時刻を記録し、処理が完了するまでにかかった時間(Duration)をログに出力するミドルウェア RequestDurationLogger
を作成していきます。
user/user.api
にミドルウェアを宣言します。
syntax = "v1"
type getUserRequest {
UserId string `path:"userId"`
}
type getUserResponse {
Message string `json:"message"`
}
// ミドルウェアを宣言
@server (
middleware: RequestDurationLoggerMiddleware
)
service user-api {
@handler GetUser
get /users/id/:userId (getUserRequest) returns (getUserResponse)
}
以下 goctl
コマンドで Go のサーバーサイドコードを生成します。
goctl api go -api user/user.api -dir user
user/internal/middleware
に requestdurationloggermiddleware.go
が生成されますので、Handle
メソッドを実装していきます。
package middleware
import (
"log"
"net/http"
"time"
)
type RequestDurationLoggerMiddleware struct {
}
func NewRequestDurationLoggerMiddleware() *RequestDurationLoggerMiddleware {
return &RequestDurationLoggerMiddleware{}
}
func (m *RequestDurationLoggerMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
start := time.Now() // 処理開始時間を記録
// 次のハンドラーを実行
next(w, r)
// 処理時間を計測
duration := time.Since(start)
// ログに出力
log.Printf("[RequestDuration] %s %s took %v", r.Method, r.URL.Path, duration)
}
}
Handle
メソッドでリクエストを受け取る。start := time.Now()
で開始時間を記録。next(w, r)
を呼ぶことで、次の処理(API ハンドラー)にリクエストを渡す。time.Since(start)
で処理時間を測定し、ログを出力。
動作確認
user-api サーバーを起動し、ミドルウェア RequestDurationLogger
の動作確認を行います。
cd user
go run user.go -f etc/user-api.yaml
エンドポイントにリクエストを送信します。
curl -i http://localhost:8888/users/id/123
以下が出力されるようになります。
2025/02/12 22:28:26 [RequestDuration] GET /users/id/123 took 466.709µs
gRPC サーバー構築
次は gRPC サーバーを構築してみます。
参考: https://go-zero.dev/en/docs/tutorials/grpc/server/example
proto ファイルを生成します。
goctl rpc -o greet/greet.proto
生成された proto ファイルは以下のようになっています。
syntax = "proto3";
package greet;
option go_package="./greet";
message Request {
string ping = 1;
}
message Response {
string pong = 1;
}
service Greet {
rpc Ping(Request) returns(Response);
}
今回はこのままでいきます。
次に、この proto ファイルを元に Goサーバーサイドコードを生成します。
goctl rpc protoc greet/greet.proto --go_out=./greet --go-grpc_out=./greet --zrpc_out=./greet
greet/
配下に以下ファイル群が生成されます。
greet
├── etc
│ └── greet.yaml
├── greet
│ ├── greet.pb.go
│ └── greet_grpc.pb.go
├── greet.go
├── greet.proto
├── greetclient
│ └── greet.go
└── internal
├── config
│ └── config.go
├── logic
│ └── pinglogic.go
├── server
│ └── greetserver.go
└── svc
└── servicecontext.go
greet/internal/logic/pinglogic.go
の Ping
メソッドを実装します。
func (l *PingLogic) Ping(in *greet.Request) (*greet.Response, error) {
fmt.Printf("in %#v\n", in)
return &greet.Response{
Pong: "pong",
}, nil
}
gRPC Server Reflection を有効にするため、greet/etc/greet.yaml
で開発モードを指定します。
Name: greet.rpc
ListenOn: 0.0.0.0:8080
Mode: dev # 追加
Etcd:
Hosts:
- 127.0.0.1:2379
Key: greet.rpc
gRPC サーバーを起動し、リクエストを送信します。
# 初回のみ
cd greet
go mod tidy
# gRPC サーバーを起動
go run greet.go -f etc/greet.yaml
# サービス一覧
grpcurl localhost:8080 list
greet.Greet
grpc.health.v1.Health
grpc.reflection.v1.ServerReflection
# メソッド一覧
grpcurl -plaintext localhost:8080 list greet.Greet
greet.Greet.Ping
# メソッドの詳細情報
grpcurl -plaintext localhost:8080 describe greet.Greet.Ping
greet.Greet.Ping is a method:
rpc Ping ( .greet.Request ) returns ( .greet.Response );
# 実際に gRPC リクエストを送信
grpcurl -plaintext localhost:8080 greet.Greet.Ping
{
"pong": "pong"
}
etcd の設定と省略方法
greet/etc/greet.yaml
にはデフォルトで etcd の設定が記述されています
# etcd の設定
Etcd:
Hosts:
- 127.0.0.1:2379
Key: greet.rpc
この設定が有効なままだと、gRPC サーバーの起動時に etcd への接続が求められます。
etcd がインストールされていないと、以下のようなエラーが発生します。
rpc error: code = DeadlineExceeded desc = latest balancer error: last connection error:
connection error: desc = "transport: Error while dialing: dial tcp 127.0.0.1:2379: connect: connection refused"
etcd をインストールする方法
Mac の場合、Homebrew を使用して etcd をインストールできます。
brew install etcd
etcd を不要にする方法
etcd なしで gRPC サーバーを起動する場合は、以下のように Hosts を空のリストにし、Key を "" に設定します。
# etcd を無効化する設定
Etcd:
Hosts: []
Key: ""
この設定を適用すれば、etcd をインストールせずに gRPC サーバーを起動できます。
まとめ
この記事では、Go のマイクロサービス向けフレームワーク go-zero
の基本を学習しました。
goctl
を使用した API コードの自動生成go-zero
による REST API の実装- ミドルウェアの導入方法
- gRPC サーバーの構築手順
etcd
を使用したサービス管理とその省略方法
go-zero のさらなる優秀な機能
- モデル生成:SQL から Go のデータモデルを自動生成する
goctl model
- タスクキュー:非同期処理を簡単に管理できる
queue
パッケージ - 負荷分散:複数の RPC サーバー間でリクエストを分散処理
- トレーシング:OpenTelemetry によるリクエストトレースのサポート
- サービスリカバリ:クラッシュ時の自動回復機能
- コンフィグ管理:環境変数や YAML による設定の柔軟な管理
[Next] Step 10-5: Watermill
[Prev] Step 10-3: Micro