W3Cschool
恭喜您成為首批注冊用戶
獲得88經驗值獎勵
在本章節(jié)中,我們將之前介紹?HTTP Client&Server
?的示例修改為?GRPC
?微服務,并演示如何使用?GoFrame
?框架開發(fā)一個簡單的?GRPC
?服務端和客戶端,并且為?GRPC
?微服務增加鏈路跟蹤特性。
本章節(jié)的示例代碼位于:https://github.com/gogf/gf/tree/master/example/trace/grpc_with_db
syntax = "proto3";
package user;
option go_package = "protobuf/user";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
// User service for tracing demo.
service User {
rpc Insert(InsertReq) returns (InsertRes) {}
rpc Query(QueryReq) returns (QueryRes) {}
rpc Delete(DeleteReq) returns (DeleteRes) {}
}
message InsertReq {
string Name = 1 [(gogoproto.moretags) = 'v:"required#Please input user name."'];
}
message InsertRes {
int32 Id = 1;
}
message QueryReq {
int32 Id = 1 [(gogoproto.moretags) = 'v:"min:1#User id is required for querying."'];
}
message QueryRes {
int32 Id = 1;
string Name = 2;
}
message DeleteReq {
int32 Id = 1 [(gogoproto.moretags) = 'v:"min:1#User id is required for deleting."'];
}
message DeleteRes {}
這里使用到了第三方的 github.com/gogo/protobuf 開源項目,用于注入自定義的Golang struct標簽。這里不詳細介紹,感興趣的小伙伴可以自行了解。未來?Katyusha
?微服務框架的官網(wǎng)文檔也會做對這塊詳細介紹,包括?GRPC
?工程目錄、開發(fā)規(guī)范、開發(fā)工具、攔截器、注冊發(fā)現(xiàn)、負載均衡等設計話題。
package main
import (
"context"
"fmt"
"time"
"github.com/gogf/gf/contrib/trace/jaeger/v2"
"github.com/gogf/gf/example/trace/grpc_with_db/protobuf/user"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcache"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/katyusha/krpc"
)
type server struct{}
const (
ServiceName = "grpc-server-with-db"
JaegerUdpEndpoint = "localhost:6831"
)
func main() {
var ctx = gctx.New()
tp, err := jaeger.Init(ServiceName, JaegerUdpEndpoint)
if err != nil {
g.Log().Fatal(ctx, err)
}
defer tp.Shutdown(ctx)
// Set ORM cache adapter with redis.
g.DB().GetCache().SetAdapter(gcache.NewAdapterRedis(g.Redis()))
s := krpc.Server.NewGrpcServer()
user.RegisterUserServer(s.Server, &server{})
s.Run()
}
// Insert is a route handler for inserting user info into database.
func (s *server) Insert(ctx context.Context, req *user.InsertReq) (res *user.InsertRes, err error) {
result, err := g.Model("user").Ctx(ctx).Insert(g.Map{
"name": req.Name,
})
if err != nil {
return nil, err
}
id, _ := result.LastInsertId()
res = &user.InsertRes{
Id: int32(id),
}
return
}
// Query is a route handler for querying user info. It firstly retrieves the info from redis,
// if there's nothing in the redis, it then does db select.
func (s *server) Query(ctx context.Context, req *user.QueryReq) (res *user.QueryRes, err error) {
err = g.Model("user").Ctx(ctx).Cache(gdb.CacheOption{
Duration: 5 * time.Second,
Name: s.userCacheKey(req.Id),
Force: false,
}).WherePri(req.Id).Scan(&res)
if err != nil {
return nil, err
}
return
}
// Delete is a route handler for deleting specified user info.
func (s *server) Delete(ctx context.Context, req *user.DeleteReq) (res *user.DeleteRes, err error) {
err = g.Model("user").Ctx(ctx).Cache(gdb.CacheOption{
Duration: -1,
Name: s.userCacheKey(req.Id),
Force: false,
}).WherePri(req.Id).Scan(&res)
return
}
func (s *server) userCacheKey(id int32) string {
return fmt.Sprintf(`userInfo:%d`, id)
}
服務端代碼簡要說明:
jaeger.Init
?方法初始化?Jaeger
?。GRPC
?協(xié)議。Redis
?緩存:g.DB().GetCache().SetAdapter(gcache.NewAdapterRedis(g.Redis()))
Cache
?方法啟用?ORM
?的緩存特性,之前已經做過介紹,這里不再贅述。package main
import (
"github.com/gogf/gf/contrib/trace/jaeger/v2"
"github.com/gogf/gf/example/trace/grpc_with_db/protobuf/user"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/gtrace"
"github.com/gogf/gf/v2/os/gctx"
)
const (
ServiceName = "grpc-client-with-db"
JaegerUdpEndpoint = "localhost:6831"
)
func main() {
var ctx = gctx.New()
tp, err := jaeger.Init(ServiceName, JaegerUdpEndpoint)
if err != nil {
g.Log().Fatal(ctx, err)
}
defer tp.Shutdown(ctx)
StartRequests()
}
func StartRequests() {
ctx, span := gtrace.NewSpan(gctx.New(), "StartRequests")
defer span.End()
var client, err = user.NewClient()
if err != nil {
g.Log().Fatalf(ctx, `%+v`, err)
}
// Baggage.
ctx = gtrace.SetBaggageValue(ctx, "uid", 100)
// Insert.
insertRes, err := client.User().Insert(ctx, &user.InsertReq{
Name: "john",
})
if err != nil {
g.Log().Fatalf(ctx, `%+v`, err)
}
g.Log().Info(ctx, "insert id:", insertRes.Id)
// Query.
queryRes, err := client.User().Query(ctx, &user.QueryReq{
Id: insertRes.Id,
})
if err != nil {
g.Log().Errorf(ctx, `%+v`, err)
return
}
g.Log().Info(ctx, "query result:", queryRes)
// Delete.
_, err = client.User().Delete(ctx, &user.DeleteReq{
Id: insertRes.Id,
})
if err != nil {
g.Log().Errorf(ctx, `%+v`, err)
return
}
g.Log().Info(ctx, "delete id:", insertRes.Id)
// Delete with error.
_, err = client.User().Delete(ctx, &user.DeleteReq{
Id: -1,
})
if err != nil {
g.Log().Errorf(ctx, `%+v`, err)
return
}
g.Log().Info(ctx, "delete id:", -1)
}
客戶端代碼簡要說明:
jaeger.Init
?方法初始化?Jaeger
?。Katyusha
?框架封裝好了,開發(fā)者只需要關心業(yè)務邏輯實現(xiàn)即可,啟動服務端:
啟動客戶端:
這里客戶端的執(zhí)行最后報了一個錯誤,那是我們故意為之,目的是演示?GRPC
?報錯時的鏈路信息展示。我們打開?jaeger
?查看一下鏈路跟蹤信息:
可以看到本次請求涉及到兩個服務:?tracing-grpc-client
?和?tracing-grpc-server
?,即客戶端和服務端。整個請求鏈路涉及到17個?span
?,客戶端5個?span
?,服務端12個?span
?,并且產生了2個錯誤。我們點擊查看詳情:
我們點擊查看一下最后接口調用錯誤的?span
?情況:
看起來像個參數(shù)校驗錯誤,點擊查看?Events/Logs
?中的請求參數(shù):
查看?Process
?中的?Log
?信息可以看到,是由于傳遞的參數(shù)為-1,不滿足校驗規(guī)則,因此在數(shù)據(jù)校驗的時候報錯返回了。
由于?orm
?、?redis
?、?logging
?組件在之前的章節(jié)中已經介紹過鏈路信息,因此我們這里主要介紹?GRPC Client&Server
?的鏈路信息。
Attribute/Tag
|
說明
|
---|---|
net.peer.ip
|
請求的目標IP。 |
net.peer.port
|
請求的目標端口。 |
rpc.grpc.status_code
|
GRPC 的內部狀態(tài)碼,0 表示成功,非0 表示失敗。 |
rpc.service
|
RPC 的服務名稱,注意這里是RPC 而不是GRPC ,因為這里是通用定義,客戶端支持多種RPC 通信協(xié)議,GRPC 只是其中一種。 |
rpc.method
|
RPC 的方法名稱。 |
rpc.system
|
RPC 協(xié)議類型,如:grpc , thrift 等。 |
Event/Log
|
說明
|
---|---|
grpc.metadata.outgoing
|
GRPC 客戶端請求提交的Metadata 信息,可能會比較大。 |
grpc.request.baggage
|
GRPC 客戶端請求提交的Baggage 信息,用于服務間鏈路信息傳遞。 |
grpc.request.message
|
|
grpc.response.message
|
GRPC 客戶端請求接收返回的的Message 信息,可能會比較大。僅對Unary 請求類型有效。 |
?GRPC Server
?端的?Attributes
?含義同?GRPC Client
?,在同一請求中,打印的數(shù)據(jù)基本一致。
?GRPC Server
?端的?Events
?與?GRPC Client
?不同的是,在同一請求中,服務端接收到的?metadata
?為?grpc.metadata.incoming
?,其他同?GRPC Client
?。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: