本教程最初发布于SigNoz Blog由Naman Jain撰写

在本文中,我们将为具有三个微服务的 Golang 应用程序实现分布式跟踪。为了实现分布式跟踪,我们将使用开源解决方案 - SigNoz 和 OpenTelemetry,因此您可以轻松地按照教程进行操作。

什么是分布式跟踪?

使用云原生、容器化和微服务的现代应用程序架构是一个非常复杂的分布式系统。一个典型的网络搜索示例将说明此类系统需要解决的一些挑战。

前端服务可以将 Web 查询分发到数百个查询服务器。查询也可以发送到许多其他子系统,这些子系统可以处理广告或寻找图像、新闻等专门的结果。这可能涉及数据库访问、缓存查找、网络调用等。总共有数千台机器并且可能需要许多不同的服务来处理一个搜索查询。

此外,网络搜索用户对延迟很敏感,这可能是由于任何子系统的性能不佳造成的。仅查看整体延迟的工程师可能知道存在问题,但可能无法猜测哪个服务有问题,也无法猜测它为什么表现不佳。而且这些服务也不是由一个团队编写和管理的。此外,日复一日,新组件可能会添加到系统中。分布式跟踪提供了对这样一个复杂系统的内部运作的洞察。跟踪此类复杂系统使工程团队能够建立可观察性框架。

分布式跟踪可以深入了解特定服务在分布式软件系统中作为整体的一部分是如何执行的。它涉及为每个用户请求传递跟踪上下文,然后跨主机、服务和协议传递以跟踪用户请求。

在本文中,我们将使用 OpenTelemetry 和 SigNoz 在带有微服务的示例 Golang 应用程序中启用分布式跟踪。但在我们深入探讨实施步骤之前,让我们简要介绍一下 OpenTelemetry 和 SigNoz。

OpenTelemetry 和 SigNoz

OpenTelemetry是一组与供应商无关的工具、API 和 SDK,用于检测应用程序以创建和管理遥测数据(日志、指标和跟踪)。它旨在使遥测数据成为云原生软件应用程序的内置功能。

OpenTelemetry 提供检测层来生成遥测数据并将其导出到后端。然后,您需要选择一个后端工具,为您的遥测数据提供数据存储和可视化。这就是 SigNoz 发挥作用的地方。

SigNoz是一个提供指标监控和分布式跟踪的全栈开源 APM 工具。

OpenTelemetry 是希望建立强大的可观察性框架的云原生应用程序所有者的前进方向。它还为您提供选择任何后端分析工具的自由。 SigNoz 是为原生支持 OpenTelemetry 而构建的,因此是一个很好的组合。

Golang 应用程序中的分布式跟踪

我们将在以下部分演示在 Golang 应用程序中实现分布式跟踪:

  • 使用 OpenTelemetry 检测 Golang 应用程序

  • 运行示例 Golang 应用程序

  • 使用 SigNoz 仪表板可视化跟踪数据

先决条件

serve

安装 SigNoz

首先,您需要安装 SigNoz,以便 OpenTelemetry 可以向其发送数据。

只需三个步骤,使用简单的安装脚本即可将 SigNoz 安装在 macOS 或 Linux 计算机上。

安装脚本会自动在 Linux 上安装 Docker Engine。但是,在 macOS 上,您必须在运行安装脚本之前手动安装Docker Engine。

git clone -b main https://github.com/SigNoz/signoz.git
cd signoz/deploy/
./install.sh

进入全屏模式 退出全屏模式

您可以访问我们的文档以获取有关如何使用 Docker Swarm 和 Helm Charts 安装 SigNoz 的说明。

部署文档

完成 SigNoz 安装后,您可以通过http://localhost:3301访问 UI。

[SigNoz 仪表板](https://res.cloudinary.com/practicaldev/image/fetch/s--5Tk7PGlR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to- uploads.s3.amazonaws.com/uploads/articles/j69siq8mimei45f8d4uw.png)

SigNoz 仪表板 - 它显示来自与应用程序捆绑的示例应用程序的服务

使用 OpenTelemetry 检测 Golang 应用程序

为了本教程的目的,我们构建了一个示例 Golang 应用程序。它有 3 项服务:

  • 用户服务

  • 支付服务,和

  • 订单服务

这些服务使用 OpenTelemetry 库进行检测,当它们相互交互时,OpenTelemetry 将遥测数据发送到与 SigNoz 捆绑在一起的 OTel 收集器。

[微服务应用程序如何适应 OpenTelemetry 和 SigNoz](https://res.cloudinary.com/practicaldev/image/fetch/s--IfbRsbYo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/ https://signoz.io/img/blog/2022/05/distributed_tracing_app_otel_signoz.webp)

应用程序架构以及 OpenTelemetry(OTel 收集器)和 SigNoz

步骤 1: 克隆示例 Golang 应用程序存储库并转到根文件夹

我们将在这个GitHub repo中使用示例 Golang 应用程序。

git clone https://github.com/SigNoz/distributed-tracing-golang-sample.git
cd distributed-tracing-golang-sample

进入全屏模式 退出全屏模式

第 2 步:安装所需的依赖项

从 go.mod 检查所有必需模块的列表。对于 OpenTelemetry,我们需要:

go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.32.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0
go.opentelemetry.io/otel v1.7.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0
go.opentelemetry.io/otel/sdk v1.7.0
go.opentelemetry.io/otel/trace v1.7.0
github.com/XSAM/otelsql v0.14.1

进入全屏模式 退出全屏模式

可以使用以下方式安装所有依赖项:

go mod tidy
go mod vendor

进入全屏模式 退出全屏模式

步骤 3:配置 OpenTelemetry 收集器

Shutdown
tp := config.Init(serviceName)
defer func() {
    if err := tp.Shutdown(context.Background()); err != nil {
        log.Printf("Error shutting down tracer provider: %v", err)
    }
}()
// tracer is later used to create spans
tracer = otel.Tracer(serviceName)

进入全屏模式 退出全屏模式

tracer
Initconfig/config.go
  1. 初始化导出器:

SDK 中的导出器负责将遥测信号(跟踪)从应用程序导出到远程后端、记录到文件等。

在此演示中,我们正在创建一个 gRPC 导出器,以将跟踪发送到在 collectorURL (SigNoz) 上运行的 OpenTelemetry Collector 后端。它还支持使用标头的 TLS 和应用程序身份验证。

secureOption :u003d otlptracegrpc.WithTLSCredentials(credentials.NewClientTLSFromCert(nil, "")) // 可以传递config来配置TLS
如果 len(不安全)> 0 {
安全选项 u003d otlptracegrpc.WithInsecure()
}
出口商,错误:u003d otlptrace.New(
上下文.背景(),
otlptracegrpc.NewClient(
安全选项,
otlptracegrpc.WithEndpoint(collectorURL),
otlptracegrpc.WithHeaders(标题),
),
)
  1. 构造跟踪提供者:
serviceName
traceProvider :u003d sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithSpanProcessor(sdktrace.NewBatchSpanProcessor(exporter)),
sdktrace.WithResource(resource.NewWithAttributes(semconv.SchemaURL, semconv.ServiceNameKey.String(serviceName))),
)

现在,我们准备在我们的应用程序中配置各种组件。

第 4 步: 使用 OpenTelemetry 检测 HTTP 处理程序

gorilla/mux
router.Use(otelmux.Middleware(serviceName))

进入全屏模式 退出全屏模式

现在,所有 HTTP 调用都通过 OpenTelemetry 中间件。

我们的服务使用 HTTP API 相互通信。我们需要配置我们的客户端以传递跟踪元数据。我们可以使用:

func SendRequest(ctx context.Context, method string, url string, data []byte) (*http.Response, error) {
    request, err := http.NewRequestWithContext(ctx, method, url, bytes.NewBuffer(data))
    if err != nil {
        return nil, fmt.Errorf("create request error: %w", err)
    }

    client := http.Client{
        // Wrap the Transport with one that starts a span and injects the span context
        // into the outbound request headers.
        Transport: otelhttp.NewTransport(http.DefaultTransport),
        Timeout:   10 * time.Second,
    }

    return client.Do(request)
}

进入全屏模式 退出全屏模式

ctx

除了otelhttp库已经提供的工具之外,我们可能希望有自定义跨度用于各种目的(例如跟踪数据库调用或跟踪函数执行)。我们可以使用:

ctx, span := tracer.Start(r.Context(), "update user amount")
defer span.End()

进入全屏模式 退出全屏模式

我们还可以将属性、事件等附加到这个跨度。请参阅文档。

第 5 步: 使用 OpenTelemetry 检测 MySQL

数据库位于大多数应用程序的热门路径中,对其性能的任何见解都是有价值的。我们借助github.com/XSAM/otelsql对其进行检测。在进行任何数据库调用时,我们会传递上下文。

db, err = otelsql.Open("mysql", datasourceName(username, password, host, dbName))
....
....
res, err := stmt.ExecContext(ctx, p.Vars...)

进入全屏模式 退出全屏模式

注意:http://github.com/XSAM/otelsqlOpenTelemetry 尚未正式支持。

运行示例 Golang 应用程序

第 1 步:配置

要设置 OpenTelemetry 以收集和导出遥测数据,您需要指定 OTLP(OpenTelemetry 协议)端点。它由安装 SigNoz 的机器的 IP 和 SigNoz 侦听的端口号组成。

:4317
127.0.0.1:4317
http://test.com:4317
.env
# service config
USER_URL=localhost:8080
PAYMENT_URL=localhost:8081
ORDER_URL=localhost:8082

# database config
SQL_USER=root
SQL_PASSWORD=password
SQL_HOST=localhost:3306
SQL_DB=signoz

# telemetry config
OTEL_EXPORTER_OTLP_ENDPOINT=localhost:4317
INSECURE_MODE=true

进入全屏模式 退出全屏模式

第 2 步:运行微服务

因为我们已经在上一节中克隆了 repo,所以从根文件夹中运行这些命令,每个命令都在一个单独的终端中:

go run ./users
go run ./payment
go run ./order

进入全屏模式 退出全屏模式

步骤 3:确认表创建:

ORDERSUSERS
mysql> use signoz;
mysql> show tables;

进入全屏模式 退出全屏模式

[显示 MySQL 数据库工作的终端屏幕截图](https://res.cloudinary.com/practicaldev/image/fetch/s--UxZ-ZlVJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https ://signoz.io/img/blog/2022/05/distributed_tracing_golang_sql.webp)

使用 Signoz 可视化分布式跟踪数据

要使用 SigNoz 可视化跟踪数据,我们首先需要通过与前端交互来生成一些用户数据。

通过与示例应用程序交互生成用户数据:

您需要生成一些用户数据以查看它在 SigNoz 仪表板中的显示方式。示例应用程序带有一个与应用程序交互的 UI。在根文件夹中使用以下命令启动 UI:

serve -l 5000 frontend

进入全屏模式 退出全屏模式

现在转到在localhost:5000运行的应用程序前端。执行以下给定步骤 4-5 次以生成一些数据。

Create User

[使用 UI 创建用户](https://res.cloudinary.com/practicaldev/image/fetch/s--JJXAb9Fi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://signoz. io/img/blog/2022/05/dt_golang_create_user.webp)

Transfer Fund

[使用 UI 转移资金](https://res.cloudinary.com/practicaldev/image/fetch/s--rNG9ci2u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://signoz. io/img/blog/2022/05/dt_golang_transfer_fund.webp)

1.下订单:通过从下拉列表中选择产品下订单。

[使用 UI 下订单](https://res.cloudinary.com/practicaldev/image/fetch/s--O1OysSkT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://signoz. io/img/blog/2022/05/dt_golang_place_order.webp)

现在转到 SigNoz 仪表板(默认在http://localhost:3301/上运行),等待一段时间,然后刷新仪表板。您会注意到我们配置的服务名称列表:

  • 用户服务

  • 订购服务

  • 支付服务

使用 Signoz 仪表板分析跟踪和指标

在指标选项卡中,您可以看到应用程序指标、外部调用和数据库调用:

应用指标:

在这里,我们可以看到应用程序延迟、每秒请求数 (rps)、错误百分比以及给定服务命中的端点。

[SigNoz 仪表板显示应用程序指标](https://res.cloudinary.com/practicaldev/image/fetch/s--ekhrUYb6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://signoz .io/img/blog/2022/05/dt_golang_application_metrics.webp)

使用 SigNoz 跟踪重要的应用程序指标,例如延迟、每秒请求数 (rps)、错误百分比和顶级端点

外部电话:

在这里,您可以看到有关对外部服务的调用的指标。在我们的例子中,我们在 localhost 上运行服务;因此我们看到一条线。外部呼叫持续时间(按地址)等指标可以快速了解与外部服务的网络连接。这可能有助于检测网络问题。

[SigNoz 仪表板显示外部调用](https://res.cloudinary.com/practicaldev/image/fetch/s--c4UCrko4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://signoz .io/img/blog/2022/05/dt_golang_external_calls.webp)

监控来自服务的外部呼叫,该服务可以帮助您深入了解网络连接

有关指标的更多功能,请阅读文档。

使用火焰图和甘特图识别延迟问题

您可以使用火焰图和甘特图检查跨度表中的每个事件,以查看请求的完整细分。建立用户请求的顺序流以及请求每个部分所用时间的信息可以帮助快速识别延迟问题。让我们看看它在我们的示例 Go 应用程序中是如何工作的。

order-service

[SigNoz 仪表板显示按火焰图和甘特图分解的用户请求](https://res.cloudinary.com/practicaldev/image/fetch/s--Phq69J2y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto %2Cw_880/https://signoz.io/img/blog/2022/05/dt_golang_gantt.webp)

SigNoz 仪表板上的火焰图和甘特图可用于查看用户请求在跨服务传播时的完整分解

insert order

[甘特图显示各种 SQL DB 调用中使用的时间详细信息](https://res.cloudinary.com/practicaldev/image/fetch/s--UyMJcHRu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto% 2Cw_880/https://signoz.io/img/blog/2022/05/dt_golang_gantt_2.webp)

甘特图可以为您提供有关 Db 调用之类的详细信息

另外,请注意,我们还有关于在右侧标签面板中运行的查询的其他信息。

结论

分布式跟踪是开发人员基于微服务架构创建应用程序的强大且关键的工具包。对于使用微服务架构的 Golang 应用程序,分布式跟踪可以集中概览请求在微服务之间的执行情况。

这使应用程序所有者可以重建请求的整个路径,并查看各个组件如何作为整个用户请求的一部分执行。

OpenTelemetry 和 SigNoz 提供了一个很好的开源解决方案来为您的应用程序实现分布式跟踪。您可以通过访问其 GitHub 存储库来试用 SigNoz 👇

SigNoz GitHub repo

#support

SigNoz Slack 社区

如果您想了解有关分布式跟踪或 SigNoz 的更多信息,请随时关注以下链接:

SigNoz - DataDog 的开源替代品

分布式跟踪指南