跳到主要内容
版本:2.8.x(Latest)

链路跟踪 - HTTP带数据库

Code Source: https://github.com/gogf/examples/tree/main/observability/trace/http-with-db

简介

本示例演示了如何在 GoFrame 中实现HTTP服务与数据库交互的分布式跟踪。主要展示:

  • 配置HTTP服务的跟踪
  • 跟踪数据库操作
  • 传播跟踪上下文
  • 可视化分布式跟踪

环境要求

  • Go 1.22 或更高版本
  • GoFrame 框架
  • GoFrame MySQL 驱动
  • GoFrame Redis 驱动
  • GoFrame OpenTelemetry 跟踪

目录结构

.
├── client/ # 客户端示例
│ └── client.go # 带跟踪的客户端
├── server/ # 服务端示例
│ ├── server.go # 带跟踪的服务端
│ └── config.yaml # 服务端配置
├── sql.sql # 数据库模式
├── go.mod # Go模块文件
└── go.sum # Go模块校验和

前置条件

  1. 运行 MySQL 实例:

    docker run -d --name mysql \
    -p 3306:3306 \
    -e MYSQL_DATABASE=test \
    -e MYSQL_ROOT_PASSWORD=12345678 \
    mysql:5.7
  2. 初始化数据库模式:

    # 连接MySQL容器
    docker exec -i mysql mysql -uroot -p12345678 test < sql.sql
  3. 运行 Redis 实例:

    docker run -d --name redis \
    -p 6379:6379 \
    redis:6.0
  4. 运行 Jaeger 实例:

    docker run --rm --name jaeger \
    -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
    -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.55

配置说明

服务端配置在server/config.yaml中定义:

database:
logger:
level: "all" # 记录所有SQL操作
stdout: true # 打印到标准输出
default:
link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
debug: true # 启用调试模式

redis:
default:
address: 127.0.0.1:6379 # 默认Redis实例
db: 0
cache:
address: 127.0.0.1:6379 # 缓存Redis实例
db: 1

使用说明

  1. 启动服务端:

    cd server
    go run server.go
  2. 运行客户端:

    cd client
    go run client.go
  3. 查看跟踪: 在浏览器中打开 http://localhost:16686 查看 Jaeger UI中的跟踪信息。

API接口

服务器提供以下HTTP接口:

  1. 插入用户

    POST /insert
    请求: {"Name": "string"}
    响应: {"ID": number}
  2. 查询用户

    GET /query
    请求: {"ID": number}
    响应: {"User": object}
  3. 删除用户

    DELETE /delete
    请求: {"Id": number}
    响应: {}

实现说明

  1. 服务端实现

    // 配置Redis作为ORM缓存适配器
    g.DB().GetCache().SetAdapter(gcache.NewAdapterRedis(g.Redis()))

    // 启动HTTP服务器
    s := g.Server()
    s.Use(ghttp.MiddlewareHandlerResponse)
    s.Group("/", func(group *ghttp.RouterGroup) {
    group.ALL("/user", new(cTrace))
    })

    // 查询用户信息
    func (c *cTrace) Query(ctx context.Context, req *QueryReq) (res *QueryRes, err error) {
    one, err := g.Model("user").Ctx(ctx).Cache(gdb.CacheOption{
    Duration: 5 * time.Second,
    Name: c.userCacheKey(req.ID),
    Force: false,
    }).WherePri(req.ID).One()
    if err != nil {
    return nil, err
    }
    res = &QueryRes{
    User: one,
    }
    return
    }
  2. 客户端实现

    // 创建新的跟踪span
    ctx, span := gtrace.NewSpan(gctx.New(), "StartRequests")
    defer span.End()

    // 发送HTTP请求
    err = client.PostVar(ctx, "http://127.0.0.1:8199/user/insert", g.Map{
    "name": "john",
    }).Scan(&insertRes)