跟煎鱼学 Go
  • Introduction
  • 第1课 杂谈
    • 1.1 聊一聊,Go 的相对路径问题
    • 1.2 Go 的 fake-useragent 了解一下
    • 1.3 用 Go 来了解一下 Redis 通讯协议
    • 1.4 使用 Gomock 进行单元测试
    • 1.5 在 Go 中恰到好处的内存对齐
    • 1.6 来,控制一下 goroutine 的并发数量
    • 1.7 for-loop 与 json.Unmarshal 性能分析概要
    • 1.8 简单围观一下有趣的 //go: 指令
    • 1.9 我要在栈上。不,你应该在堆上
    • 1.10 defer 会有性能损耗,尽量不要用
    • 1.11 从实践到原理,带你参透 gRPC
    • 1.12 Go1.13 defer 的性能是如何提高的?
    • 1.13 Go 应用内存占用太多,让排查?(VSZ篇)
    • 1.14 干货满满的 Go Modules 和 goproxy.cn
  • 第2课 包管理
    • 2.1 Go依赖管理工具dep
    • 2.2 如此,用dep获取私有库
  • 第3课 gin
    • 3.1 Golang 介绍与环境安装
    • 3.2 Gin搭建Blog API's (一)
    • 3.3 Gin搭建Blog API's (二)
    • 3.4 Gin搭建Blog API's (三)
    • 3.5 使用JWT进行身份校验
    • 3.6 编写一个简单的文件日志
    • 3.7 优雅的重启服务
    • 3.8 为它加上Swagger
    • 3.9 将Golang应用部署到Docker
    • 3.10 定制 GORM Callbacks
    • 3.11 Cron定时任务
    • 3.12 优化配置结构及实现图片上传
    • 3.13 优化你的应用结构和实现Redis缓存
    • 3.14 实现导出、导入 Excel
    • 3.15 生成二维码、合并海报
    • 3.16 在图片上绘制文字
    • 3.17 用Nginx部署Go应用
    • 3.18 Golang交叉编译
    • 3.19 请入门 Makefile
  • 第4课 grpc
    • 4.1 gRPC及相关介绍
    • 4.2 gRPC Client and Server
    • 4.3 gRPC Streaming, Client and Server
    • 4.4 TLS 证书认证
    • 4.5 基于 CA 的 TLS 证书认证
    • 4.6 Unary and Stream interceptor
    • 4.7 让你的服务同时提供 HTTP 接口
    • 4.8 对 RPC 方法做自定义认证
    • 4.9 gRPC Deadlines
    • 4.10 分布式链路追踪
  • 第5课 grpc-gateway
    • 5.1 介绍与环境安装
    • 5.2 Hello World
    • 5.3 Swagger了解一下
    • 5.4 能不能不用证书?
  • 第6课 常用关键字
    • 6.1 panic and recover
    • 6.2 defer
  • 第7课 数据结构
    • 7.1 slice
    • 7.2 slice:最大容量大小是怎么来的
    • 7.3 map:初始化和访问元素
    • 7.4 map:赋值和扩容迁移
    • 7.5 map:为什么遍历 map 是无序的
  • 第8课 标准库
    • 8.1 fmt
    • 8.2 log
    • 8.3 unsafe
  • 第9课 工具
    • 9.1 Go 大杀器之性能剖析 PProf
    • 9.2 Go 大杀器之跟踪剖析 trace
    • 9.3 用 GODEBUG 看调度跟踪
    • 9.4 用 GODEBUG 看GC
  • 第10课 爬虫
    • 9.1 爬取豆瓣电影 Top250
    • 9.2 爬取汽车之家 二手车产品库
    • 9.3 了解一下Golang的市场行情
Powered by GitBook
On this page
  • Opentracing
  • 是什么
  • 名词解释
  • 一个案例
  • Zipkin
  • 是什么
  • 运行
  • 验证
  • gRPC + Opentracing + Zipkin
  • 目录结构
  • 安装
  • gRPC
  • 验证
  • 复杂点
  • 总结
  • 参考
  • 本系列示例代码
  • 资料

Was this helpful?

  1. 第4课 grpc

4.10 分布式链路追踪

在实际应用中,你做了那么多 Server 端,写了 N 个 RPC 方法。想看看方法的指标,却无处下手?

本文将通过 gRPC + Opentracing + Zipkin 搭建一个分布式链路追踪系统来实现查看整个系统的链路、性能等指标。

Opentracing

是什么

OpenTracing 通过提供平台无关、厂商无关的API,使得开发人员能够方便的添加(或更换)追踪系统的实现

不过 OpenTracing 并不是标准。因为 CNCF 不是官方标准机构,但是它的目标是致力为分布式追踪创建更标准的 API 和工具

名词解释

Trace

一个 trace 代表了一个事务或者流程在(分布式)系统中的执行过程

Span

一个 span 代表在分布式系统中完成的单个工作单元。也包含其他 span 的 “引用”,这允许将多个 spans 组合成一个完整的 Trace

每个 span 根据 OpenTracing 规范封装以下内容:

  • 操作名称

  • 开始时间和结束时间

  • key:value span Tags

  • key:value span Logs

  • SpanContext

Tags

Span tags(跨度标签)可以理解为用户自定义的 Span 注释。便于查询、过滤和理解跟踪数据

Logs

Span logs(跨度日志)可以记录 Span 内特定时间或事件的日志信息。主要用于捕获特定 Span 的日志信息以及应用程序本身的其他调试或信息输出

SpanContext

SpanContext 代表跨越进程边界,传递到子级 Span 的状态。常在追踪示意图中创建上下文时使用

Baggage Items

Baggage Items 可以理解为 trace 全局运行中额外传输的数据集合

一个案例

图中可以看到以下内容:

  • 执行时间的上下文

  • 服务间的层次关系

  • 服务间串行或并行调用链

结合以上信息,在实际场景中我们可以通过整个系统的调用链的上下文、性能等指标信息,一下子就能够发现系统的痛点在哪儿

Zipkin

是什么

Zipkin 是分布式追踪系统。它的作用是收集解决微服务架构中的延迟问题所需的时序数据。它管理这些数据的收集和查找

运行

docker run -d -p 9411:9411 openzipkin/zipkin

验证

gRPC + Opentracing + Zipkin

在前面的小节中,我们做了以下准备工作:

  • 了解 Opentracing 是什么

  • 搭建 Zipkin 提供分布式追踪系统的功能

接下来实现 gRPC 通过 Opentracing 标准 API 对接 Zipkin,再通过 Zipkin 去查看数据

目录结构

新建 simple_zipkin_client、simple_zipkin_server 目录,目录结构如下:

go-grpc-example
├── LICENSE
├── README.md
├── client
│   ├── ...
│   ├── simple_zipkin_client
├── conf
├── pkg
├── proto
├── server
│   ├── ...
│   ├── simple_zipkin_server
└── vendor

安装

$ go get -u github.com/openzipkin/zipkin-go-opentracing
$ go get -u github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc

gRPC

Server

package main

import (
    "context"
    "log"
    "net"

    "github.com/grpc-ecosystem/go-grpc-middleware"
    "github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc"
    zipkin "github.com/openzipkin/zipkin-go-opentracing"
    "google.golang.org/grpc"

    "github.com/EDDYCJY/go-grpc-example/pkg/gtls"
    pb "github.com/EDDYCJY/go-grpc-example/proto"
)

type SearchService struct{}

func (s *SearchService) Search(ctx context.Context, r *pb.SearchRequest) (*pb.SearchResponse, error) {
    return &pb.SearchResponse{Response: r.GetRequest() + " Server"}, nil
}

const (
    PORT = "9005"

    SERVICE_NAME              = "simple_zipkin_server"
    ZIPKIN_HTTP_ENDPOINT      = "http://127.0.0.1:9411/api/v1/spans"
    ZIPKIN_RECORDER_HOST_PORT = "127.0.0.1:9000"
)

func main() {
    collector, err := zipkin.NewHTTPCollector(ZIPKIN_HTTP_ENDPOINT)
    if err != nil {
        log.Fatalf("zipkin.NewHTTPCollector err: %v", err)
    }

    recorder := zipkin.NewRecorder(collector, true, ZIPKIN_RECORDER_HOST_PORT, SERVICE_NAME)

    tracer, err := zipkin.NewTracer(
        recorder, zipkin.ClientServerSameSpan(false),
    )
    if err != nil {
        log.Fatalf("zipkin.NewTracer err: %v", err)
    }

    tlsServer := gtls.Server{
        CaFile:   "../../conf/ca.pem",
        CertFile: "../../conf/server/server.pem",
        KeyFile:  "../../conf/server/server.key",
    }
    c, err := tlsServer.GetCredentialsByCA()
    if err != nil {
        log.Fatalf("GetTLSCredentialsByCA err: %v", err)
    }

    opts := []grpc.ServerOption{
        grpc.Creds(c),
        grpc_middleware.WithUnaryServerChain(
            otgrpc.OpenTracingServerInterceptor(tracer, otgrpc.LogPayloads()),
        ),
    }
    ...
}
  • zipkin.NewHTTPCollector:创建一个 Zipkin HTTP 后端收集器

  • zipkin.NewRecorder:创建一个基于 Zipkin 收集器的记录器

  • zipkin.NewTracer:创建一个 OpenTracing 跟踪器(兼容 Zipkin Tracer)

  • otgrpc.OpenTracingClientInterceptor:返回 grpc.UnaryServerInterceptor,不同点在于该拦截器会在 gRPC Metadata 中查找 OpenTracing SpanContext。如果找到则为该服务的 Span Context 的子节点

  • otgrpc.LogPayloads:设置并返回 Option。作用是让 OpenTracing 在双向方向上记录应用程序的有效载荷(payload)

总的来讲,就是初始化 Zipkin,其又包含收集器、记录器、跟踪器。再利用拦截器在 Server 端实现 SpanContext、Payload 的双向读取和管理

Client

func main() {
    // the same as zipkin server
    // ...
    conn, err := grpc.Dial(":"+PORT, grpc.WithTransportCredentials(c),
        grpc.WithUnaryInterceptor(
            otgrpc.OpenTracingClientInterceptor(tracer, otgrpc.LogPayloads()),
        ))
    ...
}
  • otgrpc.OpenTracingClientInterceptor:返回 grpc.UnaryClientInterceptor。该拦截器的核心功能在于:

(1)OpenTracing SpanContext 注入 gRPC Metadata

(2)查看 context.Context 中的上下文关系,若存在父级 Span 则创建一个 ChildOf 引用,得到一个子 Span

其他方面,与 Server 端是一致的,先初始化 Zipkin,再增加 Client 端特需的拦截器。就可以完成基础工作啦

验证

复杂点

来,自己实践一下

总结

在多服务下的架构下,串行、并行、服务套服务是一个非常常见的情况,用常规的方案往往很难发现问题在哪里(成本太大)。而这种情况就是分布式追踪系统大展拳脚的机会了

希望你通过本章节的介绍和学习,能够了解其概念和搭建且应用一个追踪系统。

参考

本系列示例代码

资料

Previous4.9 gRPC DeadlinesNext第5课 grpc-gateway

Last updated 5 years ago

Was this helpful?

image
image

Zipkin 的设计基于 论文。

其他方法安装参见:

访问 检查 Zipkin 是否运行正常

image

启动 Server.go,执行 Client.go。查看 的示意图:

image
image
image
image

Google Dapper
https://github.com/openzipkin/zipkin
http://127.0.0.1:9411/zipkin/
http://127.0.0.1:9411/zipkin/
go-grpc-example
opentracing
zipkin