作為一個(gè) RPC 框架,Kitex 服務(wù)之間的通信都是基于 IDL(thrift、protobuf 等)描述的協(xié)議進(jìn)行的。IDL 定義的服務(wù)接口決定了客戶(hù)端和服務(wù)端之間可以傳輸?shù)臄?shù)據(jù)結(jié)構(gòu)。
然而在實(shí)際生產(chǎn)環(huán)境,我們偶爾會(huì)有特殊的信息需要傳遞給對(duì)端服務(wù),而又不希望將這些可能是臨時(shí)或者格式不確定的內(nèi)容顯式定義在 IDL 里面,這就需要框架能夠支持一定的元信息傳遞能力。
如果底層傳輸協(xié)議支持(例如 TTheader、HTTP),那么 Kitex 可以進(jìn)行元信息的透?jìng)鳌?
為了和底層的協(xié)議解耦,同時(shí)也為了支持與不同框架之間的互通,Kitex 并沒(méi)有直接提供讀寫(xiě)底層傳輸協(xié)議的元信息的 API,而是通過(guò)一個(gè)獨(dú)立維護(hù)的基礎(chǔ)庫(kù) metainfo 來(lái)支持元信息的傳遞。
包 metainfo 提供了兩種類(lèi)型的正向元信息傳遞 API:臨時(shí)的(transient)和持續(xù)的(persistent)。前者適用于通常的元信息傳遞的需求;后者是在對(duì)元信息有持續(xù)傳遞需求的場(chǎng)合下使用,例如日志 ID、染色等場(chǎng)合,當(dāng)然,持續(xù)傳遞的前提是下游以及更下游的服務(wù)都是支持這一套數(shù)據(jù)透?jìng)鞯募s定,例如都是 Kitex 服務(wù)。
客戶(hù)端的例子:
import "github.com/bytedance/gopkg/cloud/metainfo"
func main() {
...
ctx := context.Background()
cli := myservice.MustNewClient(...)
req := myservice.NewSomeRequest()
ctx = metainfo.WithValue(ctx, "temp", "temp-value") // 附加元信息到 context 里
ctx = metainfo.WithPersistentValue(ctx, "logid", "12345") // 附加能持續(xù)透?jìng)鞯脑畔? resp, err := cli.SomeMethod(ctx, req) // 將得到的 context 作為客戶(hù)端的調(diào)用參數(shù)
...
}
服務(wù)端的例子:
import (
"context"
"github.com/bytedance/gopkg/cloud/metainfo"
)
var cli2 = myservice2.MustNewClient(...) // 更下游的服務(wù)的客戶(hù)端
func (MyServiceImpl) SomeMethod(ctx context.Context, req *SomeRequest) (res *SomeResponse, err error) {
temp, ok1 := metainfo.GetValue(ctx, "temp")
logid, ok2 := metainfo.GetPersistentValue(ctx, "logid")
if !(ok1 && ok2) {
panic("It looks like the protocol does not support transmitting meta information")
}
println(temp) // "temp-value"
println(logid) // "12345"
// 如果需要調(diào)用其他服務(wù)的話
req2 := myservice2.NewRequset()
res2, err2 := cli2.SomeMethod2(ctx, req2) // 在調(diào)用其他服務(wù)時(shí)繼續(xù)傳遞收到的 context,可以讓持續(xù)的元信息繼續(xù)傳遞下去
...
}
一些傳輸協(xié)議還支持反向的元數(shù)據(jù)傳遞,因此 Kitex 也利用 metainfo 做了支持。
客戶(hù)端的例子:
import "github.com/bytedance/gopkg/cloud/metainfo"
func main() {
...
ctx := context.Background()
cli := myservice.MustNewClient(...)
req := myservice.NewSomeRequest()
ctx = metainfo.WithBackwardValues(ctx) // 標(biāo)記要接收反向傳遞的數(shù)據(jù)的 context
resp, err := cli.SomeMethod(ctx, req) // 將得到的 context 作為客戶(hù)端的調(diào)用參數(shù)
if err == nil {
val, ok := metainfo.RecvBackwardValue(ctx, "something-from-server") // 獲取服務(wù)端傳回的元數(shù)據(jù)
println(val, ok)
}
...
}
服務(wù)端的例子:
import (
"context"
"github.com/bytedance/gopkg/cloud/metainfo"
)
func (MyServiceImpl) SomeMethod(ctx context.Context, req *SomeRequest) (res *SomeResponse, err error) {
ok := metainfo.SendBackwardValue(ctx, "something-from-server")
if !ok) {
panic("It looks like the protocol does not support transmitting meta information backward")
}
...
}
更多建議: