新聞中心
在本章節(jié)中,我們將之前介紹?HTTP Client&Server?的示例修改為?GRPC?微服務(wù),并演示如何使用?GOFrame?框架開發(fā)一個簡單的?GRPC?服務(wù)端和客戶端,并且為?GRPC?微服務(wù)增加鏈路跟蹤特性。

成都創(chuàng)新互聯(lián)于2013年開始,先為仲巴等服務(wù)建站,仲巴等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為仲巴企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。
目錄結(jié)構(gòu)
Protocol
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標(biāo)簽。這里不詳細(xì)介紹,感興趣的小伙伴可以自行了解。未來?Katyusha?微服務(wù)框架的官網(wǎng)文檔也會做對這塊詳細(xì)介紹,包括?GRPC?工程目錄、開發(fā)規(guī)范、開發(fā)工具、攔截器、注冊發(fā)現(xiàn)、負(fù)載均衡等設(shè)計話題。
GRPC Server
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)
}服務(wù)端代碼簡要說明:
- 首先,服務(wù)端需要通過?
jaeger.Init?方法初始化?Jaeger?。 - 可以看到,業(yè)務(wù)邏輯和之前HTTP示例項目完全一致,只是接入層修改為了?
GRPC?協(xié)議。 - 我們?nèi)匀煌ㄟ^緩存適配器的方式注入?
Redis?緩存:
g.DB().GetCache().SetAdapter(gcache.NewAdapterRedis(g.Redis()))- 這里也是通過?
Cache?方法啟用?ORM?的緩存特性,之前已經(jīng)做過介紹,這里不再贅述。
GRPC Client
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?。 - 客戶端非常簡單,內(nèi)部初始化以及默認(rèn)攔截器的設(shè)置已經(jīng)由?
Katyusha?框架封裝好了,開發(fā)者只需要關(guān)心業(yè)務(wù)邏輯實現(xiàn)即可,
效果查看
啟動服務(wù)端:
啟動客戶端:
這里客戶端的執(zhí)行最后報了一個錯誤,那是我們故意為之,目的是演示?GRPC?報錯時的鏈路信息展示。我們打開?jaeger?查看一下鏈路跟蹤信息:
可以看到本次請求涉及到兩個服務(wù):?tracing-grpc-client?和?tracing-grpc-server?,即客戶端和服務(wù)端。整個請求鏈路涉及到17個?span?,客戶端5個?span?,服務(wù)端12個?span?,并且產(chǎn)生了2個錯誤。我們點擊查看詳情:
我們點擊查看一下最后接口調(diào)用錯誤的?span?情況:
看起來像個參數(shù)校驗錯誤,點擊查看?Events/Logs?中的請求參數(shù):
查看?Process?中的?Log?信息可以看到,是由于傳遞的參數(shù)為-1,不滿足校驗規(guī)則,因此在數(shù)據(jù)校驗的時候報錯返回了。
GRPC Client
由于?orm?、?redis?、?logging?組件在之前的章節(jié)中已經(jīng)介紹過鏈路信息,因此我們這里主要介紹?GRPC Client&Server?的鏈路信息。
Attributes
| Attribute/Tag | 說明 |
|---|---|
net.peer.ip |
請求的目標(biāo)IP。 |
net.peer.port |
請求的目標(biāo)端口。 |
rpc.grpc.status_code |
GRPC的內(nèi)部狀態(tài)碼,0表示成功,非0表示失敗。 |
rpc.service |
RPC的服務(wù)名稱,注意這里是RPC而不是GRPC,因為這里是通用定義,客戶端支持多種RPC通信協(xié)議,GRPC只是其中一種。 |
rpc.method |
RPC的方法名稱。 |
rpc.system |
RPC協(xié)議類型,如:grpc, thrift等。 |
Events/Logs
| Event/Log | 說明 |
|---|---|
grpc.metadata.outgoing |
GRPC客戶端請求提交的Metadata信息,可能會比較大。 |
grpc.request.baggage |
GRPC客戶端請求提交的Baggage信息,用于服務(wù)間鏈路信息傳遞。 |
grpc.request.message |
|
grpc.response.message |
GRPC客戶端請求接收返回的的Message信息,可能會比較大。僅對Unary請求類型有效。 |
GRPC Server
Attributes
?GRPC Server?端的?Attributes?含義同?GRPC Client?,在同一請求中,打印的數(shù)據(jù)基本一致。
Events
?GRPC Server?端的?Events?與?GRPC Client?不同的是,在同一請求中,服務(wù)端接收到的?metadata?為?grpc.metadata.incoming?,其他同?GRPC Client?。
分享題目:創(chuàng)新互聯(lián)GoFrame教程:GoFrame鏈路跟蹤-GRPC示例
標(biāo)題URL:http://m.fisionsoft.com.cn/article/dhhppce.html


咨詢
建站咨詢
