使用opentelemetry-go操作Jaeger

使用opentelemetry-go操作Jaeger

最近工作上需要做性能优化需要对服务性能做监控,之前了解过一点分布式链路追踪,所以水篇文章。

可观察性入门

下面放一段opentelemetry的谷歌翻译,翻译不太好但是看个大概是可以的。

感兴趣可以看 opentelemetry的官网:

https://opentelemetry.io/

什么是可观察性?

可观察性让我们从外部了解一个系统,让我们在不知道其内部运作的情况下就该系统提出问题。此外,使我们能够轻松解决和处理新问题(即“未知的未知数”),并帮助我们回答“为什么会发生这种情况?”的问题。

为了能够询问系统的这些问题,必须对应用程序进行适当的检测。也就是说,应用程序代码必须发出 tracesmetricslogssignals。当开发人员不需要添加更多工具来解决问题时,应用程序会被正确地检测,因为他们拥有所需的所有信息。

OpenTelemetry是检测应用程序代码的机制,以帮助使系统可观察。

可靠性和指标

Telemetry(遥测) 是指从系统发出的关于其行为的数据。数据可以以TracesMetricsLogs的形式出现。

Reliability(可靠性) 回答了这个问题:“服务是否在做用户期望它做的事情?” 一个系统可能 100% 的时间都在运行,但是如果当用户点击“添加到购物车”将一条黑色裤子添加到他们的购物车时,系统却不断添加一条红色裤子,那么系统会被说成是 可靠的。

Metrics(指标) 指标是一段时间内有关您的基础架构或应用程序的数字数据的聚合。示例包括:系统错误率、CPU 利用率、给定服务的请求率。

SLI或 Service Level Indicator,表示对服务行为的度量。一个好的 SLI 从用户的角度衡量您的服务。一个示例 SLI 可以是网页加载的速度。

SLO或服务水平目标是向组织/其他团队传达可靠性的方法。这是通过将一个或多个 SLI 附加到业务价值来实现的。

了解分布式跟踪

要了解分布式跟踪,让我们从一些基础知识开始。

Log

Log是由服务或其他组件发出的带时间戳的消息。然而,与Traces不同的是,它们不一定与任何特定的用户请求或事务相关联。它们几乎在软件中随处可见,过去开发人员和运营商都非常依赖它们来帮助他们理解系统行为。

样本日志:

I, [2021-02-23T13:26:23.505892 #22473]  INFO -- : [6459ffe1-ea53-4044-aaa3-bf902868f730] Started GET "/" for ::1 at 2021-02-23 13:26:23 -0800

不幸的是,日志对于跟踪代码执行并不是非常有用,因为它们通常缺少上下文信息,例如从哪里调用它们。

当它们作为Span的一部分包含时,它们变得更加有用。

Span

一个Span代表一个工作或操作单元。它跟踪请求进行的特定操作,描绘在执行该操作期间发生的事情。

Span 包含名称、时间相关数据、 结构化日志消息其他元数据(即属性),以提供有关它跟踪的操作的信息。

以下是 Span 中出现的信息类型示例:
请添加图片描述

有关 Spans 以及它们如何与 OTel 相关的更多信息,请访问 OpenTelemetry 中的 Spans

分布式跟踪

分布式跟踪,通常称为跟踪,记录请求(由应用程序或最终用户发出)在通过多服务架构(如微服务和无服务器应用程序)传播时所采用的路径。

在没有跟踪的情况下,很难确定分布式系统中性能问题的原因。

它提高了我们应用程序或系统健康状况的可见性,并让我们能够调试难以在本地重现的行为。跟踪对于分布式系统至关重要,这些系统通常存在不确定性问题或过于复杂而无法在本地重现。

跟踪通过分解请求流经分布式系统时发生的情况,使调试和理解分布式系统变得不那么令人生畏。

Trace 由一个或多个 Span 组成。第一个 Span 代表 Root Span。每个 Root Span 代表一个从开始到结束的请求。父级下的 Span 提供了请求期间发生的更深入的上下文(或构成请求的步骤)。

许多可观察性后端将跟踪可视化为瀑布图,可能看起来像这样:

请添加图片描述

瀑布图显示了 Root Span 与其子 Span 之间的父子关系。当一个 Span 封装另一个 Span 时,这也代表了一种嵌套关系。

opentelemetry 简介

OpenTelemetry is a collection of tools, APIs, and SDKs. Use it to instrument, generate, collect, and export telemetry data (metrics, logs, and traces) to help you analyze your software’s performance and behavior.

OpenTelemetry 是工具、API 和 SDK 的集合。使用它来检测、生成、收集和导出遥测数据(指标、日志和跟踪),以帮助您分析软件的性能和行为。

Jaeger简介

Jaeger: open source, end-to-end distributed tracing

Jaeger:开源、端到端的分布式链路链路追踪框架。

Monitor and troubleshoot transactions in complex distributed systems

在复杂分布式系统中进行监控和故障排除

Jaeger 解决的问题

  • distributed transaction monitoring分布式事务监控
  • performance and latency optimization性能和延迟优化
  • root cause analysis根本原因分析
  • service dependency analysis服务依赖分析
  • distributed context propagation分布式上下文传播

感兴趣可以看看的官网

https://www.jaegertracing.io/

Jaeger服务docker部署

为了方便使用,部署采用官网的all-in-one的 镜像。

All-in-one is an executable designed for quick local testing, launches the Jaeger UI, collector, query, and agent, with an in memory storage component.

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.35

执行命令后,打开http://127.0.0.1:16686/,出现下图则,安装成功

opentelemetry-go

opentelemetry-go 是go语言版本的客户端,使用opentelemetry-go 进行trace 上报十分简单。

官网如下:

https://github.com/open-telemetry/opentelemetry-go

官方举例:

package main

import (
	"context"
	"log"
	"time"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/exporters/jaeger"
	"go.opentelemetry.io/otel/sdk/resource"
	tracesdk "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.10.0"
)

const (
	service     = "trace-demo" // 服务名
	environment = "production" // 环境
	id          = 1      // id
)

// tracerProvider returns an OpenTelemetry TracerProvider configured to use
// the Jaeger exporter that will send spans to the provided url. The returned
// TracerProvider will also use a Resource configured with all the information
// about the application.

// tracerProvider 创建trace的提供者
func tracerProvider(url string) (*tracesdk.TracerProvider, error) {
	// Create the Jaeger exporter
    // 创建 Jaeger exporter
	exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(url)))
	if err != nil {
		return nil, err
	}
	tp := tracesdk.NewTracerProvider(
		// Always be sure to batch in production.
		tracesdk.WithBatcher(exp),
		// Record information about this application in a Resource.
		tracesdk.WithResource(resource.NewWithAttributes(
			semconv.SchemaURL,
			semconv.ServiceNameKey.String(service),
			attribute.String("environment", environment),
			attribute.Int64("ID", id),
		)),
	)
	return tp, nil
}

func main() {
	tp, err := tracerProvider("http://localhost:14268/api/traces")
	if err != nil {
		log.Fatal(err)
	}

	// Register our TracerProvider as the global so any imported
	// instrumentation in the future will default to using it.
    // 设置全局的TracerProvider,方便后面使用
	otel.SetTracerProvider(tp)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// Cleanly shutdown and flush telemetry when the application exits.
    // 优雅退出
	defer func(ctx context.Context) {
		// Do not make the application hang when it is shutdown.
		ctx, cancel = context.WithTimeout(ctx, time.Second*5)
		defer cancel()
		if err := tp.Shutdown(ctx); err != nil {
			log.Fatal(err)
		}
	}(ctx)

    // trace 上报
	tr := tp.Tracer("component-main")

	ctx, span := tr.Start(ctx, "foo")
	defer span.End()

    // Context 向下传递
	bar(ctx)
}

func bar(ctx context.Context) {
	// Use the global TracerProvider.
    // 使用 全局 TracerProvider
	tr := otel.Tracer("component-bar")
	_, span := tr.Start(ctx, "bar")
	span.SetAttributes(attribute.Key("testset").String("value"))
	defer span.End()

	// Do bar...
}

简单说明一下上报流程:

  1. 创建tracerProvider,通过tracerProvider来连接 Jaeger
  2. 创建Tracer ,推荐使用 全局的TracerProvider 来创建如:otel.Tracer("component-bar")
  3. 创建span ctx, span := tr.Start(ctx, "foo")
  4. 调用span.End(),完成上报。 defer span.End()

关键组件

TracerProvider 接口

// TracerProvider provides access to instrumentation Tracers.
//
// Warning: methods may be added to this interface in minor releases.
type TracerProvider interface {
	// Tracer creates an implementation of the Tracer interface.
	// The instrumentationName must be the name of the library providing
	// instrumentation. This name may be the same as the instrumented code
	// only if that code provides built-in instrumentation. If the
	// instrumentationName is empty, then a implementation defined default
	// name will be used instead.
	//
	// This method must be concurrency safe.
	Tracer(instrumentationName string, opts ...TracerOption) Tracer
}

可以简单理解为Tracer提供者,只有一个方法Tracer 返回tracer

Tracer 接口

// Tracer is the creator of Spans.
//
// Warning: methods may be added to this interface in minor releases.
type Tracer interface {
   // Start creates a span and a context.Context containing the newly-created span.
   //
   // If the context.Context provided in `ctx` contains a Span then the newly-created
   // Span will be a child of that span, otherwise it will be a root span. This behavior
   // can be overridden by providing `WithNewRoot()` as a SpanOption, causing the
   // newly-created Span to be a root span even if `ctx` contains a Span.
   //
   // When creating a Span it is recommended to provide all known span attributes using
   // the `WithAttributes()` SpanOption as samplers will only have access to the
   // attributes provided when a Span is created.
   //
   // Any Span that is created MUST also be ended. This is the responsibility of the user.
   // Implementations of this API may leak memory or other resources if Spans are not ended.
   Start(ctx context.Context, spanName string, opts ...SpanStartOption) (context.Context, Span)
}

Tracer is the creator of Spans.Tracer是span的创造者,也只提供一个对象span

Span 接口

// Span is the individual component of a trace. It represents a single named
// and timed operation of a workflow that is traced. A Tracer is used to
// create a Span and it is then up to the operation the Span represents to
// properly end the Span when the operation itself ends.
//
// Warning: methods may be added to this interface in minor releases.
type Span interface {
	// End completes the Span. The Span is considered complete and ready to be
	// delivered through the rest of the telemetry pipeline after this method
	// is called. Therefore, updates to the Span are not allowed after this
	// method has been called.
	End(options ...SpanEndOption)

	// AddEvent adds an event with the provided name and options.
	AddEvent(name string, options ...EventOption)

	// IsRecording returns the recording state of the Span. It will return
	// true if the Span is active and events can be recorded.
	IsRecording() bool

	// RecordError will record err as an exception span event for this span. An
	// additional call to SetStatus is required if the Status of the Span should
	// be set to Error, as this method does not change the Span status. If this
	// span is not being recorded or err is nil then this method does nothing.
	RecordError(err error, options ...EventOption)

	// SpanContext returns the SpanContext of the Span. The returned SpanContext
	// is usable even after the End method has been called for the Span.
	SpanContext() SpanContext

	// SetStatus sets the status of the Span in the form of a code and a
	// description, overriding previous values set. The description is only
	// included in a status when the code is for an error.
	SetStatus(code codes.Code, description string)

	// SetName sets the Span name.
	SetName(name string)

	// SetAttributes sets kv as attributes of the Span. If a key from kv
	// already exists for an attribute of the Span it will be overwritten with
	// the value contained in kv.
	SetAttributes(kv ...attribute.KeyValue)

	// TracerProvider returns a TracerProvider that can be used to generate
	// additional Spans on the same telemetry pipeline as the current Span.
	TracerProvider() TracerProvider
}

Span is the individual component of a trace. It represents a single named and timed operation of a workflow that is traced. Span是trace的单个组成部分。 它代表了跟踪的工作流的单个命名和定时操作。

常用方法End:End completes the Span. The Span is considered complete and ready to be delivered through the rest of the telemetry pipeline after this method is called.完成span,此时Span被认为是完整的,已经准备好在此方法调用后通过剩下的 telemetry pipeline 传递。

简单理解下:调用end方法后,此时span是完整的,准备被上报。

更多opentelemetry-go操作其他分布式链路追踪组件可以看下方

https://github.com/open-telemetry/opentelemetry-go/tree/main/example

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值