gRPC 服務要加 HTTP 介面?
go-zero 給大家帶來極簡的 RESTful 和 gRPC 服務開發體驗的同時,社群又給我們提出了新的期望:
- 我想只寫一次程式碼
- 既要 gRPC 介面
- 也要 HTTP 介面
- 既要。。。也要。。。
也有道理嘛!你看使用者怎麼說:
使用者A:一套邏輯,api和rpc一起
使用者B:go-zero要是能簡化這一步我感覺會成為go生態中最好的微服務框架沒有之一
於是,我陷入了深深的思考:使用者從來是不會錯的,但是我們要不要提供呢?
於是,你看到了這篇文章。。。
我們先提供 gRPC 服務
對於這種服務,我們太熟了。新建一個目錄,就叫 grpc-restufl
吧,裡面放個 sum.proto
檔案
syntax = "proto3";
package sum;
option go_package="./pb";
message Numbers {
int64 a = 1;
int64 b = 2;
}
message SumRequest {
Numbers numbers =1;
}
message SumResponse {
int64 result = 1;
}
service Sum {
rpc Add(SumRequest) returns (SumResponse) {}
}
一鍵生成,你懂的。。。
$ goctl rpc protoc --go_out=. --go-grpc_out=. --zrpc_out=. sum.proto
看看都有了啥
.
├── etc
│ └── sum.yaml
├── go.mod
├── internal
│ ├── config
│ │ └── config.go
│ ├── logic
│ │ └── addlogic.go
│ ├── server
│ │ └── sumserver.go
│ └── svc
│ └── servicecontext.go
├── pb
│ ├── sum.pb.go
│ └── sum_grpc.pb.go
├── sum
│ └── sum.go
├── sum.go
└── sum.proto
實現一下業務邏輯,將 internal/logic/addlogic.go
裡的 Add
方法修改如下:
func (l *AddLogic) Add(in *pb.SumRequest) (*pb.SumResponse, error) {
return &pb.SumResponse{
Result: in.Numbers.A+in.Numbers.B,
}, nil
}
可以跑了,業務邏輯也是有了的(雖然很簡單,演示嘛。。。)
$ go mod tidy && go run sum.go
Starting rpc server at 127.0.0.1:8080...
對於熟悉 go-zero 的同學來說,至此無亮點(新知識),接下來 GET 新技能~
提供 HTTP 介面
更新 go-zero
首先,我們更新 go-zero 至 master
版,因為 gateway
還沒正式發版,八月初會正式跟大家見面
$ go get -u github.com/zeromicro/go-zero@master
修改 proto 檔案
修改 sum.proto
,我新建了一個 sum-api.proto
,如下:
syntax = "proto3";
package sum;
option go_package="./pb";
import "google/api/annotations.proto";
message Numbers {
int64 a = 1;
int64 b = 2;
}
message SumRequest {
Numbers numbers =1;
}
message SumResponse {
int64 result = 1;
}
service Sum {
rpc Add(SumRequest) returns (SumResponse) {
option (google.api.http) = {
post: "/v1/sum"
body: "*"
};
}
}
生成 proto descriptor 檔案
protoc --include_imports --proto_path=. --descriptor_set_out=sum.pb sum-api.proto
修改配置檔案
修改後的 internal/config/config.go
如下(部分):
type Config struct {
zrpc.RpcServerConf
Gateway gateway.GatewayConf
}
修改後的 etc/sum.yaml
如下:
Gateway:
Name: gateway
Port: 8081
Upstreams:
- Grpc:
Endpoints:
- localhost:8080
ProtoSet: sum.pb
修改 main 函式
建立 gateway
並用 ServiceGroup
來管理 gRPC server
和 gateway server
,部分程式碼如下:
gw := gateway.MustNewServer(c.Gateway)
group := service.NewServiceGroup()
group.Add(s)
group.Add(gw)
defer group.Stop()
fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
fmt.Printf("Starting gateway at %s:%d...\n", c.Gateway.Host, c.Gateway.Port)
group.Start()
大功告成
讓我們來啟動服務
$ go run sum.go
Starting rpc server at 127.0.0.1:8080...
Starting gateway at 0.0.0.0:8081...
用 curl
測試一下
$ curl -i -H "Content-Type: application/json" -d '{"numbers":{"a":2,"b":3}}' localhost:8081/v1/sum
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Traceparent: 00-ad5b7df7a834a1c05ee64999e3310811-195ba1f4f9956cc4-00
Date: Mon, 18 Jul 2022 14:33:11 GMT
Content-Length: 20
{
"result": "5"
}
再看我們的 gateway
和 gRPC
的日誌裡的鏈路資訊和客戶端收到的都能對應上,贊!
{"@timestamp":"2022-07-18T22:33:11.437+08:00","caller":"serverinterceptors/statinterceptor.go:76","content":"127.0.0.1:61635 - /sum.Sum/Add - {\"numbers\":{\"a\":2,\"b\":3}}","duration":"0.0ms","level":"info","span":"b3c85cd32a76f8c9","trace":"ad5b7df7a834a1c05ee64999e3310811"}
{"@timestamp":"2022-07-18T22:33:11.438+08:00","caller":"handler/loghandler.go:197","content":"[HTTP] 200 - POST /v1/sum - 127.0.0.1:61662 - curl/7.79.1","duration":"0.7ms","level":"info","span":"195ba1f4f9956cc4","trace":"ad5b7df7a834a1c05ee64999e3310811"}
結束語
你看,給我們的 gRPC
服務加上 HTTP
介面是不是五分鐘就可以完成了?是不是?
另外,不要小看這個簡單的 gateway
,配置裡如果是對接後面的 gRPC
服務發現的話,會自動負載均衡的,並且還可以自定義中介軟體,想怎麼控制就怎麼控制。
是不是有點心動了呢?
對了,這個示例的完整程式碼在:
https://github.com/kevwan/grpc-restful
專案地址
https://github.com/zeromicro/go-zero
歡迎使用 go-zero
並 star 支援我們!
微信交流群
關注『微服務實踐』公眾號並點選 交流群 獲取社群群二維碼。