Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Jaeger Client Go 链路追踪|入门详解

Jaeger Client Go 链路追踪|入门详解

作者头像
痴者工良
发布于 2021-04-26 02:46:41
发布于 2021-04-26 02:46:41
2.1K00
代码可运行
举报
文章被收录于专栏:痴者工良痴者工良
运行总次数:0
代码可运行

目录

从何说起

之前参加柠檬大佬的训练营(免费白嫖),在大佬的指导下我们技术蒸蒸日上,然后作业我们需要实现一个 Jaeger 后端,笔者采用 .NET + MongoDB 来实现(大佬说用C#写的扣10分,呜呜呜...),C# 版本的实现项目地址https://github.com/whuanle/DistributedTracing,项目支持 Jaeger Collector、Query 等。

现在笔者开始转 Go 语言,所以开始 Go 重新实现一次,下一篇文章将完整介绍如何实现一个 Jaeger Collector。在这篇文章,我们可以先学习 Jaeger client Go 的使用方法,以及 Jaeger Go 的一些概念。

在此之前,建议读者稍微看一下 分布式链路追踪框架的基本实现原理 这篇文章,需要了解 Dapper 论文和一些 Jaeger 的概念。

接下来我们将一步步学习 Go 中的一些技术,后面慢慢展开 Jaeger Client。

Jaeger

OpenTracing 是开放式分布式追踪规范,OpenTracing API 是一致,可表达,与供应商无关的API,用于分布式跟踪和上下文传播。

OpenTracing 的客户端库以及规范,可以到 Github 中查看:https://github.com/opentracing/

Jaeger 是 Uber 开源的分布式跟踪系统,详细的介绍可以自行查阅资料。

部署 Jaeger

这里我们需要部署一个 Jaeger 实例,以供微服务以及后面学习需要。

使用 Docker 部署很简单,只需要执行下面一条命令即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
docker run -d -p 5775:5775/udp -p 16686:16686 -p 14250:14250 -p 14268:14268 jaegertracing/all-in-one:latest

访问 16686 端口,即可看到 UI 界面。

后面我们生成的链路追踪信息会推送到此服务,而且可以通过 Jaeger UI 查询这些追踪信息。

从示例了解 Jaeger Client Go

这里,我们主要了解一些 Jaeger Client 的接口和结构体,了解一些代码的使用。

为了让读者方便了解 Trace、Span 等,可以看一下这个 Json 的大概结构:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        {
            "traceID": "2da97aa33839442e",
            "spans": [
                {
                    "traceID": "2da97aa33839442e",
                    "spanID": "ccb83780e27f016c",
                    "flags": 1,
                    "operationName": "format-string",
                    "references": [...],
                    "tags": [...],
                    "logs": [...],
                    "processID": "p1",
                    "warnings": null
                },
                ... ...
            ],
            "processes": {
                "p1": {
                    "serviceName": "hello-world",
                    "tags": [...]
                },
                "p2": ...,
            "warnings": null
        }

创建一个 client1 的项目,然后引入 Jaeger client 包。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
go get -u github.com/uber/jaeger-client-go/

然后引入包

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import (
	"github.com/uber/jaeger-client-go"
)

了解 trace、span

链路追踪中的一个进程使用一个 trace 实例标识,每个服务或函数使用一个 span 标识,jaeger 包中有个函数可以创建空的 trace:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
tracer := opentracing.GlobalTracer()	// 生产中不要使用

然后就是调用链中,生成父子关系的 Span:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func main() {
	tracer := opentracing.GlobalTracer()
	// 创建第一个 span A
	parentSpan := tracer.StartSpan("A")
    defer parentSpan.Finish()		// 可手动调用 Finish()

}
func B(tracer opentracing.Tracer,parentSpan opentracing.Span){
	// 继承上下文关系,创建子 span
	childSpan := tracer.StartSpan(
		"B",
		opentracing.ChildOf(parentSpan.Context()),
		)
	defer childSpan.Finish()	// 可手动调用 Finish()
}

每个 span 表示调用链中的一个结点,每个结点都需要明确父 span。

现在,我们知道了,如何生成 trace{span1,span2},且 span1 -> span2 即 span1 调用 span2,或 span1 依赖于 span2。

tracer 配置

由于服务之间的调用是跨进程的,每个进程都有一些特点的标记,为了标识这些进程,我们需要在上下文间、span 携带一些信息。

例如,我们在发起请求的第一个进程中,配置 trace,配置服务名称等。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 引入 jaegercfg "github.com/uber/jaeger-client-go/config"
	cfg := jaegercfg.Configuration{
		ServiceName: "client test", // 对其发起请求的的调用链,叫什么服务
		Sampler: &jaegercfg.SamplerConfig{
			Type:  jaeger.SamplerTypeConst,
			Param: 1,
		},
		Reporter: &jaegercfg.ReporterConfig{
			LogSpans: true,
		},
	}

Sampler 是客户端采样率配置,可以通过 sampler.typesampler.param 属性选择采样类型,后面详细聊一下。

Reporter 可以配置如何上报,后面独立小节聊一下这个配置。

传递上下文的时候,我们可以打印一些日志:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	jLogger := jaegerlog.StdLogger

配置完毕后就可以创建 tracer 对象了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	tracer, closer, err := cfg.NewTracer(
		jaegercfg.Logger(jLogger),
	)
	
	defer closer.Close()
	if err != nil {
	}

完整代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import (
    "github.com/opentracing/opentracing-go"
	"github.com/uber/jaeger-client-go"
	jaegercfg "github.com/uber/jaeger-client-go/config"
	jaegerlog "github.com/uber/jaeger-client-go/log"
)

func main() {

	cfg := jaegercfg.Configuration{
		ServiceName: "client test", // 对其发起请求的的调用链,叫什么服务
		Sampler: &jaegercfg.SamplerConfig{
			Type:  jaeger.SamplerTypeConst,
			Param: 1,
		},
		Reporter: &jaegercfg.ReporterConfig{
			LogSpans: true,
		},
	}

	jLogger := jaegerlog.StdLogger
	tracer, closer, err := cfg.NewTracer(
		jaegercfg.Logger(jLogger),
	)

	defer closer.Close()
	if err != nil {
	}

	// 创建第一个 span A
	parentSpan := tracer.StartSpan("A")
	defer parentSpan.Finish()

	B(tracer,parentSpan)
}

func B(tracer opentracing.Tracer, parentSpan opentracing.Span) {
	// 继承上下文关系,创建子 span
	childSpan := tracer.StartSpan(
		"B",
		opentracing.ChildOf(parentSpan.Context()),
	)
	defer childSpan.Finish()
}

启动后:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
2021/03/30 11:14:38 Initializing logging reporter
2021/03/30 11:14:38 Reporting span 689df7e83255d05d:75668e8ed5ec61da:689df7e83255d05d:1
2021/03/30 11:14:38 Reporting span 689df7e83255d05d:689df7e83255d05d:0000000000000000:1
2021/03/30 11:14:38 DEBUG: closing tracer
2021/03/30 11:14:38 DEBUG: closing reporter

Sampler 配置

sampler 配置代码示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
		Sampler: &jaegercfg.SamplerConfig{
			Type:  jaeger.SamplerTypeConst,
			Param: 1,
		}

这个 sampler 可以使用 jaegercfg.SamplerConfig,通过 typeparam 两个字段来配置采样器。

为什么要配置采样器?因为服务中的请求千千万万,如果每个请求都要记录追踪信息并发送到 Jaeger 后端,那么面对高并发时,记录链路追踪以及推送追踪信息消耗的性能就不可忽视,会对系统带来较大的影响。当我们配置 sampler 后,jaeger 会根据当前配置的采样策略做出采样行为。

详细可以参考:https://www.jaegertracing.io/docs/1.22/sampling/

jaegercfg.SamplerConfig 结构体中的字段 Param 是设置采样率或速率,要根据 Type 而定。

下面对其关系进行说明:

Type

Param

说明

"const"

0或1

采样器始终对所有 tracer 做出相同的决定;要么全部采样,要么全部不采样

"probabilistic"

0.0~1.0

采样器做出随机采样决策,Param 为采样概率

"ratelimiting"

N

采样器一定的恒定速率对tracer进行采样,Param=2.0,则限制每秒采集2条

"remote"

采样器请咨询Jaeger代理以获取在当前服务中使用的适当采样策略。

sampler.Type="remote"/sampler.Type=jaeger.SamplerTypeRemote 是采样器的默认值,当我们不做配置时,会从 Jaeger 后端中央配置甚至动态地控制服务中的采样策略。

Reporter 配置

看一下 ReporterConfig 的定义。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type ReporterConfig struct {
    QueueSize                  int `yaml:"queueSize"`
    BufferFlushInterval        time.Duration
    LogSpans                   bool   `yaml:"logSpans"`
    LocalAgentHostPort         string `yaml:"localAgentHostPort"`
    DisableAttemptReconnecting bool   `yaml:"disableAttemptReconnecting"`
    AttemptReconnectInterval   time.Duration
    CollectorEndpoint          string            `yaml:"collectorEndpoint"`
    User                       string            `yaml:"user"`
    Password                   string            `yaml:"password"`
    HTTPHeaders                map[string]string `yaml:"http_headers"`
}

Reporter 配置客户端如何上报追踪信息的,所有字段都是可选的。

这里我们介绍几个常用的配置字段。

  • QUEUESIZE,设置队列大小,存储采样的 span 信息,队列满了后一次性发送到 jaeger 后端;defaultQueueSize 默认为 100;
  • BufferFlushInterval 强制清空、推送队列时间,对于流量不高的程序,队列可能长时间不能满,那么设置这个时间,超时可以自动推送一次。对于高并发的情况,一般队列很快就会满的,满了后也会自动推送。默认为1秒。
  • LogSpans 是否把 Log 也推送,span 中可以携带一些日志信息。
  • LocalAgentHostPort 要推送到的 Jaeger agent,默认端口 6831,是 Jaeger 接收压缩格式的 thrift 协议的数据端口。
  • CollectorEndpoint 要推送到的 Jaeger Collector,用 Collector 就不用 agent 了。

例如通过 http 上传 trace:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
		Reporter: &jaegercfg.ReporterConfig{
			LogSpans:           true,
			CollectorEndpoint: "http://127.0.0.1:14268/api/traces",
		},

据黑洞大佬的提示,HTTP 走的就是 thrift,而 gRPC 是 .NET 特供,所以 reporter 格式只有一种,而且填写 CollectorEndpoint,我们注意要填写完整的信息。

完整代码测试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import (
	"bufio"
    "github.com/opentracing/opentracing-go"
	"github.com/uber/jaeger-client-go"
	jaegercfg "github.com/uber/jaeger-client-go/config"
	jaegerlog "github.com/uber/jaeger-client-go/log"
	"os"
)

func main() {

	var cfg = jaegercfg.Configuration{
		ServiceName: "client test", // 对其发起请求的的调用链,叫什么服务
		Sampler: &jaegercfg.SamplerConfig{
			Type:  jaeger.SamplerTypeConst,
			Param: 1,
		},
		Reporter: &jaegercfg.ReporterConfig{
			LogSpans:           true,
			CollectorEndpoint: "http://127.0.0.1:14268/api/traces",
		},
	}

	jLogger := jaegerlog.StdLogger
	tracer, closer, _ := cfg.NewTracer(
		jaegercfg.Logger(jLogger),
	)

	// 创建第一个 span A
	parentSpan := tracer.StartSpan("A")
	// 调用其它服务
	B(tracer, parentSpan)
	// 结束 A
	parentSpan.Finish()
	// 结束当前 tracer
	closer.Close()

	reader := bufio.NewReader(os.Stdin)
	_, _ = reader.ReadByte()
}
func B(tracer opentracing.Tracer, parentSpan opentracing.Span) {
	// 继承上下文关系,创建子 span
	childSpan := tracer.StartSpan(
		"B",
		opentracing.ChildOf(parentSpan.Context()),
	)
	defer childSpan.Finish()
}

运行后输出结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
2021/03/30 15:04:15 Initializing logging reporter
2021/03/30 15:04:15 Reporting span 715e0af47c7d9acb:7dc9a6b568951e4f:715e0af47c7d9acb:1
2021/03/30 15:04:15 Reporting span 715e0af47c7d9acb:715e0af47c7d9acb:0000000000000000:1
2021/03/30 15:04:15 DEBUG: closing tracer
2021/03/30 15:04:15 DEBUG: closing reporter
2021/03/30 15:04:15 DEBUG: flushed 1 spans
2021/03/30 15:04:15 DEBUG: flushed 1 spans

打开 Jaeger UI,可以看到已经推送完毕(http://127.0.0.1:16686)。

这时,我们可以抽象代码代码示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func CreateTracer(servieName string) (opentracing.Tracer, io.Closer, error) {
	var cfg = jaegercfg.Configuration{
		ServiceName: servieName,
		Sampler: &jaegercfg.SamplerConfig{
			Type:  jaeger.SamplerTypeConst,
			Param: 1,
		},
		Reporter: &jaegercfg.ReporterConfig{
			LogSpans:          true,
			// 按实际情况替换你的 ip
			CollectorEndpoint: "http://127.0.0.1:14268/api/traces",
		},
	}

	jLogger := jaegerlog.StdLogger
	tracer, closer, err := cfg.NewTracer(
		jaegercfg.Logger(jLogger),
	)
	return tracer, closer, err
}

这样可以复用代码,调用函数创建一个新的 tracer。这个记下来,后面要用。

分布式系统与span

前面介绍了如何配置 tracer 、推送数据到 Jaeger Collector,接下来我们聊一下 Span。请看图。

下图是一个由用户 X 请求发起的,穿过多个服务的分布式系统,A、B、C、D、E 表示不同的子系统或处理过程。

在这个图中, A 是前端,B、C 是中间层、D、E 是 C 的后端。这些子系统通过 rpc 协议连接,例如 gRPC。

一个简单实用的分布式链路追踪系统的实现,就是对服务器上每一次请求以及响应收集跟踪标识符(message identifiers)和时间戳(timestamped events)。

这里,我们只需要记住,从 A 开始,A 需要依赖多个服务才能完成任务,每个服务可能是一个进程,也可能是一个进程中的另一个函数。这个要看你代码是怎么写的。后面会详细说一下如何定义这种关系,现在大概了解一下即可。

怎么调、怎么传

如果有了解过 Jaeger 或读过 分布式链路追踪框架的基本实现原理 ,那么已经大概了解的 Jaeger 的工作原理。

jaeger 是分布式链路追踪工具,如果不用在跨进程上,那么 Jaeger 就失去了意义。而微服务中跨进程调用,一般有 HTTP 和 gRPC 两种,下面将来讲解如何在 HTTP、gPRC 调用中传递 Jaeger 的 上下文。

HTTP,跨进程追踪

A、B 两个进程,A 通过 HTTP 调用 B 时,通过 Http Header 携带 trace 信息(称为上下文),然后 B 进程接收后,解析出来,在创建 trace 时跟传递而来的 上下文关联起来。

一般使用中间件来处理别的进程传递而来的上下文。inject 函数打包上下文到 Header 中,而 extract 函数则将其解析出来。

这里我们分为两步,第一步从 A 进程中传递上下文信息到 B 进程,为了方便演示已经实践,我们使用 client-webserver 的形式,编写代码。

客户端

在 A 进程新建一个方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 请求远程服务,获得用户信息
func GetUserInfo(tracer opentracing.Tracer, parentSpan opentracing.Span) {
	// 继承上下文关系,创建子 span
	childSpan := tracer.StartSpan(
		"B",
		opentracing.ChildOf(parentSpan.Context()),
	)

	url := "http://127.0.0.1:8081/Get?username=痴者工良"
	req,_ := http.NewRequest("GET", url, nil)
	// 设置 tag,这个 tag 我们后面讲
	ext.SpanKindRPCClient.Set(childSpan)
	ext.HTTPUrl.Set(childSpan, url)
	ext.HTTPMethod.Set(childSpan, "GET")
	tracer.Inject(childSpan.Context(), opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(req.Header))
	resp, _ := http.DefaultClient.Do(req)
	_ = resp 	// 丢掉
	defer childSpan.Finish()
}

然后复用前面提到的 CreateTracer 函数。

main 函数改成:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func main() {
	tracer, closer, _ := CreateTracer("UserinfoService")
	// 创建第一个 span A
	parentSpan := tracer.StartSpan("A")
	// 调用其它服务
	GetUserInfo(tracer, parentSpan)
	// 结束 A
	parentSpan.Finish()
	// 结束当前 tracer
	closer.Close()

	reader := bufio.NewReader(os.Stdin)
	_, _ = reader.ReadByte()
}

完整代码可参考:https://github.com/whuanle/DistributedTracingGo/issues/1

Web 服务端

服务端我们使用 gin 来搭建。

新建一个 go 项目,在 main.go 目录中,执行 go get -u github.com/gin-gonic/gin

创建一个函数,该函数可以从创建一个 tracer,并且继承其它进程传递过来的上下文信息。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 从上下文中解析并创建一个新的 trace,获得传播的 上下文(SpanContext)
func CreateTracer(serviceName string, header http.Header) (opentracing.Tracer,opentracing.SpanContext, io.Closer, error) {
	var cfg = jaegercfg.Configuration{
		ServiceName: serviceName,
		Sampler: &jaegercfg.SamplerConfig{
			Type:  jaeger.SamplerTypeConst,
			Param: 1,
		},
		Reporter: &jaegercfg.ReporterConfig{
			LogSpans: true,
			// 按实际情况替换你的 ip
			CollectorEndpoint: "http://127.0.0.1:14268/api/traces",
		},
	}

	jLogger := jaegerlog.StdLogger
	tracer, closer, err := cfg.NewTracer(
		jaegercfg.Logger(jLogger),
	)
	// 继承别的进程传递过来的上下文
	spanContext, _ := tracer.Extract(opentracing.HTTPHeaders,
		opentracing.HTTPHeadersCarrier(header))
	return tracer, spanContext, closer, err
}

为了解析 HTTP 传递而来的 span 上下文,我们需要通过中间件来解析了处理一些细节。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func UseOpenTracing() gin.HandlerFunc {
	handler := func(c *gin.Context) {
		// 使用 opentracing.GlobalTracer() 获取全局 Tracer
		tracer,spanContext, closer, _ := CreateTracer("userInfoWebService", c.Request.Header)
		defer closer.Close()
		// 生成依赖关系,并新建一个 span、
		// 这里很重要,因为生成了  References []SpanReference 依赖关系
		startSpan:= tracer.StartSpan(c.Request.URL.Path,ext.RPCServerOption(spanContext))
		defer startSpan.Finish()

		// 记录 tag
		// 记录请求 Url
		ext.HTTPUrl.Set(startSpan, c.Request.URL.Path)
		// Http Method
		ext.HTTPMethod.Set(startSpan, c.Request.Method)
		// 记录组件名称
		ext.Component.Set(startSpan, "Gin-Http")

		// 在 header 中加上当前进程的上下文信息
		c.Request=c.Request.WithContext(opentracing.ContextWithSpan(c.Request.Context(),startSpan))
		// 传递给下一个中间件
		c.Next()
		// 继续设置 tag
		ext.HTTPStatusCode.Set(startSpan, uint16(c.Writer.Status()))
	}

	return handler
}

别忘记了 API 服务

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func GetUserInfo(ctx *gin.Context) {
	userName := ctx.Param("username")
	fmt.Println("收到请求,用户名称为:", userName)
	ctx.String(http.StatusOK, "他的博客是 https://whuanle.cn")
}

然后是 main 方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func main() {
	r := gin.Default()
	// 插入中间件处理
	r.Use(UseOpenTracing())
	r.GET("/Get",GetUserInfo)
	r.Run("0.0.0.0:8081") // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}

完整代码可参考:https://github.com/whuanle/DistributedTracingGo/issues/2

分别启动 webserver、client,会发现打印日志。并且打开 jaerger ui 界面,会出现相关的追踪信息。

Tag 、 Log 和 Ref

Jaeger 的链路追踪中,可以携带 Tag 和 Log,他们都是键值对的形式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
                        {
                            "key": "http.method",
                            "type": "string",
                            "value": "GET"
                        },

Tag 设置方法是 ext.xxxx,例如 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ext.HTTPUrl.Set(startSpan, c.Request.URL.Path)

因为 opentracing 已经规定了所有的 Tag 类型,所以我们只需要调用 ext.xxx.Set() 设置即可。

前面写示例的时候忘记把日志也加一下了。。。日志其实很简单的,通过 span 对象调用函数即可设置。

示例(在中间件里面加一下):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        startSpan.LogFields(
            log.String("event", "soft error"),
            log.String("type", "cache timeout"),
            log.Int("waited.millis", 1500))

ref 就是多个 span 之间的关系。span 可以是跨进程的,也可以是一个进程内的不同函数中的。

其中 span 的依赖关系表示示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
                    "references": [
                        {
                            "refType": "CHILD_OF",
                            "traceID": "33ba35e7cc40172c",
                            "spanID": "1c7826fa185d1107"
                        }]

spanID 为其依赖的父 span。

可以看下面这张图。

一个进程中的 tracer 可以包装一些代码和操作,为多个 span 生成一些信息,或创建父子关系。

而 远程请求中传递的是 SpanContext,传递后,远程服务也创建新的 tracer,然后从 SpanContext 生成 span 依赖关系。

子 span 中,其 reference 列表中,会带有 父 span 的 span id。

关于 Jaeger Client Go 的文章到此完毕,转 Go 没多久,大家可以互相交流哟。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-03-30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
基于opentracing + jaeger 实现全链路追踪
当代互联网服务,通常都是用复杂,大规模分布式集群来实现,微服务化,这些软件模块分布在不同的机器,不同的数据中心,由不同团队,语言开发而成。因此,需要工具帮助理解,分析这些系统、定位问题,做到追踪每一个请求的完整调用链路,收集性能数据,反馈到服务治理中,链路追踪系统应运而生。
orientlu
2019/06/14
3.1K0
jaeger入门
有两个服务组成,svc1,svc2 有三个span组成,svc1 sayhello --> svc1 req svc2 --> svc2 get bagger
有点技术
2020/07/14
9610
链路追踪学习四:gin集成jaeger
本文为仙士可原创文章,转载无需和我联系,但请注明来自仙士可博客www.php20.cn
仙士可
2022/04/25
1.2K0
golang源码分析:分布式链路追踪
在上一节搭完分布式追踪的采集展示链路后,这一节开始分析分析分布式链路追踪的核心源码。我们知道分布式追踪的原理是通过traceId串联调用链路上的所有服务和日志,每个服务都有一个自己的spanId,每一次rpc调用都需要生成一个子spanId,通过父子spanID的对应关系,构建一个有向无环图实现分布式追踪的。因此在业务代码的接入过程中需要实现如下功能,父子span关系的构建,父子span关系的传递(包括context内部传递和rpc服务之间的传递有可能跨协议比如http和grpc协议之间传递),rpc日志的采样,上报等等。每一个厂商都有自己的实现,opentrace定义了统一的标准接口,我们按照标准实现即可。在业务代码中实现包括四步:
golangLeetcode
2022/12/17
8400
golang源码分析:分布式链路追踪
[系列] - go-gin-api 路由中间件 - Jaeger 链路追踪(六)
说实话,这篇文章确实让大家久等了,主要是里面有一些技术点都是刚刚研究的,没有存货。
新亮
2019/09/25
1.3K0
[系列] - go-gin-api 路由中间件 - Jaeger 链路追踪(六)
研究调用链跟踪技术之jaeger
最近在做微服务构架里有关调用链跟踪(也有叫分布式追踪)的部分,有一些心得,这里总结一些。
jeremyxu
2019/03/13
3.3K0
研究调用链跟踪技术之jaeger
微服务线上问题排查困难?不知道问题出在哪一环?那是你还不会分布式链路追踪
咱们以前单体应用里面有很多的应用和功能,依赖各个功能之间相互调用,使用公共的代码包等等,排查问题,使用类似于 gdb/dlv 工具或者直接查看代码日志,进行定位和分析
阿兵云原生
2023/09/28
4420
微服务线上问题排查困难?不知道问题出在哪一环?那是你还不会分布式链路追踪
技术阅读摘要-3.Jaeger技术分析
通过上一次技术阅读摘要,我们了解了分布式链路追踪这项技术,Jaeger是其主流的实现方案。
junedayday
2021/10/27
5430
分布式追踪实战
分布式监控是一个市场庞大的领域,尤其在现在微服务越来越被广泛采用的的现代,监控和追踪系统可以说百花齐放,诞生了很多开源框架和商业公司。
王磊-字节跳动
2020/07/19
1.9K0
链路追踪学习二:Jaeger
Jaeger是一个基于opentracing规范的链路追踪工具,官方地址:https://www.jaegertracing.io/
仙士可
2022/04/15
1.5K0
链路追踪学习二:Jaeger
微服务之分布式链路
在过去10-15 年间,移动互联网时代大背景下,诞生了无数日活都是千万级以上的 app 产品。我们在客户端的任何一次操作,往往都需要经过后端服务的多个模块、多个基础组件、多台机器的相互协作才能完成请求的处理和响应。在这一系列的请求中,可能是串行也可能是并行,那么如何确定客户端的一次操作背后调用了哪些应用、哪些模块,经过了哪些节点,每个模块的调用先后顺序是怎样的,每个模块的性能问题如何?随着业务系统模型的日趋复杂化,分布式系统中急需一套链路追踪(Trace)系统来解决这些痛点。
磊叔的技术博客
2025/06/07
730
微服务之分布式链路
分布式链路追踪
微服务架构 作为云原生核心技术之一,提倡将单一应用程序划分成一组小的服务(微服务),服务之间互相协调、互相配合,为用户提供最终价值。
gopher云原生
2021/10/18
1.3K1
Tempo - 分布式Loki链路追踪利器
Tempo是Grafana Labs在ObservabilityCON 2020大会上新开源的一个用于做分布式式追踪的后端服务。它和Cortex、Loki一样,Tempo也是一个兼备高扩展和低成本效应的系统。
米开朗基杨
2020/12/14
4K0
Tempo - 分布式Loki链路追踪利器
Go语言微服务框架 - 9.分布式链路追踪-OpenTracing的初步引入
随着模块的增加,我们会越发感受到系统的复杂性,开始关注系统的可维护性。这时,有个名词会进入我们的视野:分布式链路追踪。相关的内容可以参考这我的两篇文章:
junedayday
2021/11/10
2.4K0
链路跟踪之Jaeger简介,架构,opentracing解析,安装
Jaeger Client - 为不同语言实现了符合 OpenTracing 标准的 SDK。应用程序通过 API 写入数据,client library 把 trace 信息按照应用程序指定的采样策略传递给 jaeger-agent。
iginkgo18
2021/07/13
2.2K0
2w字长文,让你瞬间拥有「调用链」开发经验
很多同学表示,对于微服务中常用的调用链功能的原理,感觉很模糊。本文将真正的从零开始,介绍调用链客户端开发的一些要点。让你瞬间拥有APM开发经验。文章很长很长,照例看一下相关目录。
xjjdog
2019/11/19
1.6K0
2w字长文,让你瞬间拥有「调用链」开发经验
一探究竟新一代可观测标准OpenTelemetry
相信大家日常经常使用kibana、grafana、jaeger等平台观察系统状态和定位问题,这些就是可观测体系的一部分。可观测主要包括:
用户1093396
2023/09/01
1.4K0
一探究竟新一代可观测标准OpenTelemetry
拥抱 Agent,“0” 代码玩转 Trace 之 OpenTelemetry 系列第二弹!
自2006年以来,曾就职于SonyEricsson、SAP等多家公司,历任软件开发工程师,数据开发工程师,解决方案架构师
腾讯云中间件团队
2021/03/24
1.6K0
拥抱 Agent,“0” 代码玩转 Trace 之 OpenTelemetry 系列第二弹!
[业界方案]用Jaeger来学习分布式追踪系统Opentracing
笔者之前有过zipkin的经验,希望扩展到Opentracing,于是在学习Jaeger基础上总结出此文,与大家分享。
罗西的思考
2020/09/16
2.3K0
链路追踪学习三:跨服务,跨进程追踪
首先,我们要了解,跨服务追踪需要有个traceId标识,以及其他需要传递的链路数据:
仙士可
2022/04/25
8130
链路追踪学习三:跨服务,跨进程追踪
相关推荐
基于opentracing + jaeger 实现全链路追踪
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验