链路追踪的集成与使用
介绍
链路追踪Tracing Analysis为分布式应用的开发者提供了完整的调用链路还原、调用请求量统计、链路拓扑、应用依赖分析等工具,可以帮助开发者快速分析和诊断分布式应用架构下的性能瓶颈,提高微服务时代下的开发诊断效率。
```
## 集成到go-zero系统(以product api服务和product rpc服务举例)
1.在各个服务的配置文件增加【链路追踪配置】:
```yaml
Name: product
Host: 0.0.0.0
Port: 6511
ProductRPC:
Endpoints: - 127.0.0.1:7511 Timeout: 0 NonBlock: true# jwtAuth
JwtAuth:
AccessSecret: 3d0f2052dede4b44caff1f643d0a4e1f AccessExpire: 86400
# 缓存
Cache:
- Host: 192.168.1.168:6379 Pass:# 链路追踪配置
Telemetry:
Name: product Endpoint: http://192.168.1.53:14268/api/traces Sampler: 1.0 Batcher: jaeger
```
2.修改config.go
```go
package config
import (
"github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/trace" //新增
"github.com/zeromicro/go-zero/zrpc")
type Config struct {
zrpc.RpcServerConf Mysql struct { DataSource string } Cache cache.CacheConf MqRpcConf zrpc.RpcClientConf ChainRpcConf zrpc.RpcClientConf CheckoutRpcConf zrpc.RpcClientConf CommonRpcConf zrpc.RpcClientConf Order struct { PayingTimeout uint64 } Telemetry trace.Config //新增
}
```
## span和trace介绍
为什么能够进行整条链路的追踪? 其实就是一个trace id将一连串的span信息连起来了。根据Span记录的信息再进行整合就可以获取整条链路的信息。下面是链路追踪的核心概念:
span:
```text
基本的工作单元,每次发送一个远程调用服务就会产生一个 Span。
Span 是一个 64 位的唯一 ID。
通过计算 Span 的开始和结束时间,就可以统计每个服务调用所花费的时间。
```
trace:
```text
每次客户端访问微服务系统的 API 接口,可能中间会调用多个微服务,
每次调用都会产生一个新的 Span,而多个 Span 组成了 Trace
```
## 使用
span:
系统默认情况下会自动记录api和rpc服务请求的链路,如图所示:
<img src="https://wakie.oss-cn-beijing.aliyuncs.com/screenshot-20220825-142839.png">
1.从context中获取span:
```go
span := tracking.SpanFromContext(l.ctx)
```
2.设置span的属性:
```go
tracking.SetAttributes(span, attribute.KeyValue{Key: "key", Value: attribute.StringValue("value")})
```
3.设置span状态:
```go
span.SetStatus(codes.Error, "描述信息")
```
4.记录错误:
```go
span.RecordError(errors.New("这是一个错误"))
```
5.添加日志:
```go
tracking.AddEvent(span, "名称", trace.WithAttributes(
attribute.KeyValue{Key: "k1", Value: attribute.StringValue("v1")}, attribute.KeyValue{Key: "k2", Value: attribute.StringValue("v2")}, attribute.KeyValue{Key: "k3", Value: attribute.StringValue("v3")}, attribute.KeyValue{Key: "k4", Value: attribute.StringValue("v4")},))
```
6.新建span:
当需要记录新函数调用链的时候用到,首选需要传入当前context到该函数中:
```go
music, err := l.svcCtx.CustomProductModel.GetMusicMusic(l.ctx, in)
if err != nil {
return nil, xerr.NewErrCode(xerr.DbError, err)}
```
然后在该函数中就记录使用上述步骤,但这时候获取span的方式不同应使用NewSpanFromContext:
```go
func (m *CustomProductModel) GetMusicMusic(ctx context.Context, in *pb.ProductPageReq) (*pb.MusicListResp, error) {
_, span := tracking.NewSpanFromContext(ctx, "GetMusicMusic") span.SetAttributes(attribute.KeyValue{Key: "dddd", Value: attribute.StringValue("2233423423")}) defer span.End()}
```
如果不再需要有新增子链路则需要调用 defer span.End()
tracking包为自定义span方法的扩展包,调用这里面的方法会自动加上caller
## jaeger 安装
```shell
docker run -d --name jaeger \
-e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
-e COLLECTOR_OTLP_ENABLED=true \
-p 6831:6831/udp \
-p 6832:6832/udp \
-p 5778:5778 \
-p 16686:16686 \
-p 4317:4317 \
-p 4318:4318 \
-p 14250:14250 \
-p 14268:14268 \
-p 14269:14269 \
-p 9411:9411 \
jaegertracing/all-in-one:1.37
16686 为UI访问端口
{"TransactionNo":"002112022082311461310407997136606896128","Amount":0.01,"AppId":"app_3e5d214b-dff9-42de-a347-1796916e7c97","Reason":"测试退款"}