Table of contents
foreword
The original link of this article is:
https://blog.csdn.net/freewebsys/article/details/108971807
Not to be reproduced without permission of the blogger.
The blogger’s CSDN address is: https://blog.csdn.net/freewebsys
The blogger’s nugget address is: https://juejin.cn/user/585379920479288
The blogger’s Zhihu address is: https://www.zhihu. com/people/freewebsystem
1. About grpc microservices
Project reference:
https://grpc.io/docs/languages/go/quickstart/
You need the protoc tool to install it directly:
# 手动安装 gf 工具:
git clone https://github.com/gogf/gf && cd gf/cmd/gf && go install
# 安装工具
sudo apt install -y protobuf-compiler
protoc --version
libprotoc 3.12.4
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
Project address:
https://github.com/gogf/gf-demo-grpc
Then you can execute the pb command
make pb finally shows done! The execution is successful:
$ make pb
/usr/bin/protoc --proto_path=/data/home/test/go/src/gf-demo-grpc/manifest/protobuf --go_out=paths=source_relative:/data/home/test/go/src/gf-demo-grpc/api --go-grpc_out=paths=source_relative:/data/home/test/go/src/gf-demo-grpc/api /data/home/test/go/src/gf-demo-grpc/manifest/protobuf/pbentity/user.proto
/usr/bin/protoc --proto_path=/data/home/test/go/src/gf-demo-grpc/manifest/protobuf --go_out=paths=source_relative:/data/home/test/go/src/gf-demo-grpc/api --go-grpc_out=paths=source_relative:/data/home/test/go/src/gf-demo-grpc/api /data/home/test/go/src/gf-demo-grpc/manifest/protobuf/user/v1/user.proto
done!
Then write the proto file, which is also very simple:
reference document:
https://juejin.cn/post/6978474549025177608
user.proto
// ==========================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
syntax = "proto3";
package pbentity;
option go_package = "github.com/gogf/gf-demo-grpc/api/pbentity";
import "google/protobuf/timestamp.proto";
message User {
uint32 Id = 1 ; // User ID
string Passport = 2 ; // User Passport
string Password = 3 ; // User Password
string Nickname = 4 ; // User Nickname
google.protobuf.Timestamp CreateAt = 5 ; // Created Time
google.protobuf.Timestamp UpdateAt = 6 ; // Updated Time
google.protobuf.Timestamp DeleteAt = 7 ; // Deleted Time
}
user api proto, a simple method with only one service
// protoc --go_out=plugins=grpc:. *.proto
syntax = "proto3";
package user;
option go_package = "gf-demo-grpc/api/user/v1";
service User{
rpc Create(CreateReq) returns (CreateRes) {}
}
message CreateReq {
string Passport = 1; // v: required
string Password = 2; // v: required
string Nickname = 3; // v: required
}
message CreateRes {
string Data = 1; // v: required
}
2. Modify the generated code
Goframe will create a controller-like service by default, which is actually a gprc service:
package user
import (
"context"
v1 "github.com/gogf/gf-demo-grpc/api/user/v1"
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
)
type Controller struct {
v1.UnimplementedUserServer
}
func Register(s *grpcx.GrpcServer) {
v1.RegisterUserServer(s.Server, &Controller{
})
}
func (*Controller) Create(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error) {
return nil, gerror.NewCode(gcode.CodeNotImplemented)
}
But to modify, the default grpc directly returns an exception of unimplemented code:
return nil, gerror.NewCode(gcode.CodeNotImplemented)
changed to:
func (*Controller) Create(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error) {
g.Log().Printf(ctx, `Create user get Nickname : %+v`, req.Nickname)
res = &v1.CreateRes{
}
res.Data = "OK"
return res, nil
}
Then modify the test method:
package test
import (
"fmt"
"testing"
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/test/gtest"
v1 "github.com/gogf/gf-demo-grpc/api/user/v1"
)
func Test_Create(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
ctx = gctx.GetInitCtx()
conn = grpcx.Client.MustNewGrpcClientConn("demo")
user = v1.NewUserClient(conn)
)
for i := 1; i <= 10; i++ {
res, err := user.Create(ctx, &v1.CreateReq{
Passport: fmt.Sprintf(`passport-%d`, i),
Nickname: fmt.Sprintf(`nickname-%d`, i),
})
if err != nil {
g.Log().Fatalf(ctx, `create user failed: %+v`, err)
} else {
g.Log().Printf(ctx, `create user success : %+v`, res.Data)
}
}
})
}
Execute 10 times:
Result:
2023-06-06 11:44:26.456 {003338c60bf5651781952122252686fb} create user success : OK
The data data returned by grpc can be obtained.
You can also request data through a direct connection:
host := "localhost:8000"
ctx := gctx.GetInitCtx()
conn, err := grpc.Dial(host, grpc.WithTransportCredentials(insecure.NewCredentials()) )
g.Log().Print(ctx, `create ChatMessage response `, err)
user = v1.NewUserClient(conn)
Why do you want to connect directly, because it may be necessary to provide services to others on the external network.
At the same time, you can use nginx for load balancing, and use grpc_pass reverse proxy directly, which is similar to proxying other services.
Other references: https://juejin.cn/post/7179907227031994405
upstream grpc_servers {
server 192.168.1.101:8000;
server 192.168.1.102:8000;
}
location / {
grpc_pass grpc://grpc_servers:8000;
}
3. Related goframe grpc configuration
Configuration reference:
https://goframe.org/pages/viewpage.action?pageId=80488218
The config.yaml configuration in it:
# GRPC Server.
#
grpc:
address: ":8000" # 自定义服务监听地址
name: "demo"
logPath: ""
logStdout: true
errorStack: true
errorLogEnabled: true
errorLogPattern: "error-{Ymd}.log"
accessLogEnabled: true
accessLogPattern: "access-{Ymd}.log"
Then start the service in main:
package main
import (
"github.com/gogf/gf-demo-grpc/internal/controller/user"
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
)
func main() {
// cmd.Main.Run(gctx.New())
s := grpcx.Server.New()
user.Register(s)
s.Run()
}
4. Summary
The service of grpc is indeed a little more troublesome than other service development.
Mainly the installation and configuration of proto tools.
But after mastering it, I found that it is also very convenient, and it can support the mutual calling of multiple languages.
At the same time, with the tool integration of goframe, it is easier to directly help configure the service.
I have helped to write them all, and the rest can be used to write business logic, which is very convenient. Recommended.
The original link of this article is:
https://blog.csdn.net/freewebsys/article/details/108971807