这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
链路追踪
为什么需要链路追踪
在分布式系统或者微服务架构中,一次请求往往需要调动内部的多个模块,多个中间件,多台机器相互协调才能完成。这些调用过程是较为复杂的,有的是串行调用的,有的是并行调用的。这种情况下,如果确定整个请求当中调用了哪些应用,哪些节点,哪些模块,以及他们的先后顺序和各部分的性能,这就是链路追踪。链路追踪就是将一次分布式请求还原成调用链路,将一次分布式请求的调用情况集中展示,比如,各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等。
Kitex提供了对OpenTelemetry和OpenTracing的支持,也支持用户自定义链路追踪
OpenTelemetry链路追踪
import (
...
"github.com/kitex-contrib/obs-opentelemetry/provider"
"github.com/kitex-contrib/obs-opentelemetry/tracing"
)
func main(){
serviceName := "echo-client"
//接入OpenTelemetry
p := provider.NewOpenTelemetryProvider(
provider.WithServiceName(serviceName),
provider.WithExportEndpoint("localhost:4317"),
provider.WithInsecure(),
)
defer p.Shutdown(context.Background())
}
svr := userservice.NewServer(
new(UserServiceImpl),
//注入trace到server实例中
server.WithSuite(tracing.NewServerSuite()),
server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: serviceName}),
)
服务注册与发现
Kitex服务注册与发现已经对接了主流的服务注册与发现中心 下面以注册ETCD为例
server
import (
api "example/kitex_gen/api/echo"
"fmt"
"github.com/cloudwego/kitex/pkg/rpcinfo"
"github.com/cloudwego/kitex/server"
etcd "github.com/kitex-contrib/registry-etcd"
"log"
)
func main() {
r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}) //创建一个etcd的注册,ectd占127.0.0.1的2379端口
if err != nil {
fmt.Println(err)
}
svr := api.NewServer(new(EchoImpl),
server.WithRegistry(r), //将server注册到etcd中
server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{
ServiceName: "example",
}),
)
err = svr.Run()
if err != nil {
log.Println(err.Error())
}
}
client
import (
"context"
"example/kitex_gen/api"
"example/kitex_gen/api/echo"
"fmt"
client "github.com/cloudwego/kitex/client"
etcd "github.com/kitex-contrib/registry-etcd"
"time"
)
func main() {
//根据127.0.0.1:2379地址创建一个etcd组件实例
r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"})
if err != nil {
fmt.Println(err)
}
c := echo.MustNewClient("example",
client.WithResolver(r)//client.WithResolver,我们能看到最后把一个服务发现实例放到了 client 的 options 结构体中:
)
if err != nil {
fmt.Println(err)
}
for {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
resp, err := c.Echo(ctx, &api.Request{Message: "hello world!"})
cancel()
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Second)
fmt.Println(resp)
}
}