追踪是一个强大的工具,可让您分析应用程序的性能并识别瓶颈。本教程将教您追踪的核心概念,以及如何使用 OpenTelemetry 和 Prisma 的追踪功能将追踪集成到您的应用程序中。
目录
- 介绍
- 前提条件
- 克隆仓库
- 将追踪集成到您的应用程序中
- 使用 Jaeger 可视化追踪
- 为您的 Prisma 查询添加追踪
- 为 Express 设置自动 instrumentation
- 降低追踪的性能影响
- 总结和最终说明
介绍
在本教程中,您将学习如何将追踪集成到使用 Prisma 和 Express 构建的现有 Web 应用程序中。您将使用 OpenTelemetry 实现追踪,OpenTelemetry 是一个供应商中立的标准,用于收集追踪和其他遥测数据(例如,日志、指标等)。
最初,您将为 HTTP 端点创建手动追踪,并将其打印到控制台。然后,您将学习如何使用 Jaeger 可视化您的追踪。您还将学习如何使用 Prisma 的追踪功能自动生成数据库查询的追踪。最后,您将了解在使用追踪时的自动 instrumentation 和性能注意事项。
什么是追踪?
追踪是一种可观测性工具,它记录请求在应用程序中传播时所经过的路径。追踪可以帮助您链接系统响应任何特定请求时执行的活动。追踪还提供有关这些活动的时间信息(例如,开始时间、持续时间等)。
单个追踪为您提供有关用户或应用程序发出请求时发生的情况的信息。每个追踪由一个或多个 span 组成,这些 span 包含有关请求期间发生的单个步骤或任务的信息。
使用诸如 Jaeger 之类的追踪工具,可以将追踪可视化为如下所示的图表
单个 span 可以有多个子 span,这些子 span 代表父 span 期间发生的子任务。例如,在上面的图表中,PRISMA QUERY span 有一个名为 PRISMA ENGINE 的子 span。最顶层的 span 称为根 span,表示从开始到结束的整个追踪。在上面的图表中,GET /ENDPOINT 是根 span。
追踪是深入了解和可见系统的一种绝佳方式。它使您可以精确地识别影响应用程序的错误和性能瓶颈。追踪对于调试分布式系统尤其有用,在分布式系统中,每个请求可能涉及多个服务,并且特定问题可能难以在本地重现。
您将使用的技术
在本教程中,您将使用以下工具
- OpenTelemetry 作为追踪库/API
- Prisma 作为对象关系映射器 (ORM)
- SQLite 作为数据库
- Jaeger 作为追踪可视化工具
- Express 作为 Web 框架
- TypeScript 作为编程语言
前提条件
预备知识
这是一个初学者友好的教程。但是,本教程假设您具备
- JavaScript 或 TypeScript 的基本知识(首选)
- 后端 Web 开发的基本知识
注意:本教程假设您没有关于追踪和可观测性的先验知识。
开发环境
要学习本教程,您需要
- ... 安装 Node.js。
- ... 安装 Docker 和 Docker Compose。
- ... 可选 安装 Prisma VS Code 扩展。Prisma VS Code 扩展为 Prisma 添加了一些非常好的 IntelliSense 和语法高亮。
- ... 可选 访问 Unix shell(如 Linux 和 macOS 中的终端/shell)以运行本系列中提供的命令。
如果您没有 Unix shell(例如,您在 Windows 机器上),您仍然可以学习本教程,但 shell 命令可能需要针对您的机器进行修改。
克隆仓库
您将需要一个 Web 应用程序来演示追踪。您可以使用我们为本教程构建的现有 Express Web 应用程序。
要开始使用,请执行以下操作
- 克隆 仓库
- 导航到克隆的目录
- 安装依赖项
- 从
prisma/migrations
目录应用数据库迁移
注意:此命令还将生成 Prisma Client 并 seed 数据库。
- 启动项目
注意:您应该在开发应用程序时保持服务器正在运行。
dev
脚本应在代码发生更改时重启服务器。
该应用程序只有一个端点:https://127.0.0.1:4000/users/random。此端点将从数据库返回 10 个用户的随机样本。通过访问上面的 URL 或运行以下命令来测试端点
项目结构和文件
您克隆的仓库具有以下结构
此仓库中值得注意的文件和目录是
prisma
schema.prisma
:定义数据库 schema。migrations
:包含数据库迁移历史记录。seed.ts
:包含一个脚本,用于使用虚拟数据 seed 您的开发数据库。dev.db
:存储 SQLite 数据库的状态。
server.ts
:带有GET /users/random
端点的 Express 服务器。tsconfig.json
&package.json
:配置文件。
将追踪集成到您的应用程序中
您的 Express 应用程序已实现所有核心“业务逻辑”(即返回 10 个随机用户)。为了衡量性能并提高应用程序的可观测性,您将集成追踪。
在本节中,您将学习如何初始化追踪并手动创建追踪。
初始化追踪
您将使用 OpenTelemetry 追踪来实现追踪。OpenTelemetry 提供了一个开源实现,该实现与各种平台和语言兼容。此外,它还附带用于实现追踪的库和 SDK。
首先安装以下 OpenTelemetry 包以开始追踪
这些包包含 OpenTelemetry 追踪的 Node.js 实现。
现在,创建一个新的 tracing.ts
文件以初始化追踪
在 tracing.ts
内部,如下初始化追踪
initializeTracing
函数执行以下几项操作
- 它初始化一个 tracer provider,该 provider 用于创建 tracer。Tracer 在您的应用程序内部创建追踪/span。
- 它定义一个 追踪导出器,并将其添加到您的 provider。追踪导出器将追踪发送到各种目的地。在这种情况下,
ConsoleSpanExporter
将追踪打印到控制台。 - 它通过调用
.register()
函数注册 provider 以便与 OpenTelemetry API 一起使用。 - 最后,它创建并返回一个 tracer,其名称作为参数传递给函数。
现在,在现有的 server.ts
中导入并调用 initializeTracing
现在您已准备好创建您的第一个追踪!
创建您的第一个追踪
在上一节中,您初始化了追踪并将 tracer 导入到您的服务器。现在,您可以使用 tracer
对象在您的服务器内部创建 span。首先,您将创建一个追踪,封装 GET /users/random
请求。如下更新请求处理程序定义
在这里,您使用 startActiveSpan()
创建一个新的 span,并将所有请求处理程序逻辑都包含在它提供的回调函数中。回调函数带有一个对 span
对象的引用,您已将其命名为 requestSpan
。您可以使用它来修改 span 或向 span 添加属性。在此代码中,您根据请求的结果,将一个名为 http.status
的属性设置为 span。最后,请求被服务后,您结束 span。
要查看您新创建的 span,请访问 https://127.0.0.1:4000/users/random。或者,您可以在终端中运行以下命令
转到正在运行 Express 服务器的终端窗口。您应该看到一个类似于以下内容的对象打印到控制台
此对象表示您刚刚创建的 span。这里一些值得注意的属性是
id
表示此特定 span 的唯一标识符。traceId
表示特定追踪的唯一标识符。特定追踪中的所有 span 都将具有相同的traceId
。现在,您的追踪仅由一个 span 组成。parentId
是父 span 的id
。在这种情况下,它是undefined
,因为根 span 没有父 span。name
表示 span 的名称。您在创建 span 时指定了这一点。timestamp
是一个 UNIX 时间戳,表示 span 创建时间。duration
是以微秒为单位的 span 持续时间。
使用 Jaeger 可视化追踪
目前,您正在控制台中查看追踪。虽然这对于单个追踪是可管理的,但对于大量追踪不是很有用。为了更好地理解您的追踪,您需要一些可以可视化追踪的追踪解决方案。在本教程中,您将为此目的使用 Jaeger。
设置 Jaeger
您可以通过两种方式设置 Jaeger
在本教程中,您将使用 Docker Compose 运行 Jaeger 的 Docker 镜像。首先,创建一个新的 docker-compose.yml
文件
在文件中定义以下服务
运行此镜像将在 Docker 容器内部设置并初始化 Jaeger 的所有必要组件。要运行 Jaeger,请打开一个新的终端窗口并在您的项目主文件夹中运行以下命令
注意:如果您关闭运行 docker 容器的终端窗口,也会停止容器。如果您在命令末尾添加
-d
选项,可以避免这种情况,如下所示:docker-compose up -d
。
如果一切顺利,您应该可以在 https://127.0.0.1:16686 访问 Jaeger。
由于您的应用程序尚未将追踪发送到 Jaeger,因此 Jaeger UI 将为空。
添加 Jaeger 追踪导出器
要在 Jaeger 中查看您的追踪,您需要设置一个新的追踪导出器,将追踪从您的应用程序发送到 Jaeger(而不是仅仅将它们打印到控制台)。
首先,在您的项目中安装导出器包
现在将导出器添加到 tracing.ts
在这里,您初始化了一个新的 JaegerExporter
并将其添加到您的 tracer provider。JaegerExporter
构造函数中的 endpoint
属性指向 Jaeger 正在侦听追踪数据的位置。您还移除了控制台导出器,因为它不再需要。
您现在应该能够在 Jaeger 中看到您的追踪。要查看您的第一个追踪
- 再次查询
GET /users/random
端点(curl https://127.0.0.1:4000/users/random
)。 - 前往 https://127.0.0.1:16686。
- 在左侧的Search 选项卡中,在 Service 下拉列表中,选择 express-server。
- 在 Search 选项卡的底部附近,点击 Find Traces。
- 您现在应该看到一个追踪列表。点击列表中的第一个追踪。
- 您将看到追踪的详细视图。应该有一个名为 GET /users/random 的 span。点击 span 以获取更多信息。
- 您应该能够看到关于追踪的各种信息,例如 Duration 和 Start Time。您还应该看到多个 Tags,其中一个您手动设置了(
http.status
)。
为您的 Prisma 查询添加追踪
在本节中,您将学习如何追踪您的数据库查询。最初,您将通过自己创建 span 来手动执行此操作。即使使用 Prisma 手动追踪不再必要,但实现手动追踪将使您更好地理解追踪的工作原理。
然后,您将使用 Prisma 中的新 追踪功能自动执行相同的操作。
手动追踪您的 Prisma 查询
要手动追踪您的 Prisma 查询,您必须将每个查询都包装在一个 span 中。您可以通过将以下代码添加到您的 server.ts
文件中来做到这一点
您为 Prisma 查询创建了一个名为 prisma.user.findmany
的新 span。您还对 users
变量的声明方式进行了一些更改,以使其与代码的其余部分保持一致。
通过再次查询 GET /users/random
端点(curl https://127.0.0.1:4000/users/random
)并在 Jaeger 中查看新生成的追踪来测试新 span。
您应该看到生成的追踪有一个新的子 span,名为 prisma.user.findmany
,嵌套在父 GET /users/random
span 下面。现在您可以看到请求的持续时间中花费在执行 Prisma 查询的时间。
手动与自动 instrumentation
到目前为止,您已经学习了如何设置追踪并为您的应用程序手动生成追踪和 span。像这样手动定义 span 称为手动 instrumentation。手动 instrumentation 使您可以完全控制如何追踪您的应用程序,但是,它也有一些缺点
- 手动追踪您的应用程序非常耗时,尤其是当您的应用程序很大时。
- 并非总是可以手动正确地 instrumentation 第三方库。例如,不可能使用手动 instrumentation 追踪 Prisma 内部组件的执行。
- 可能导致错误和错误(例如,不正确的错误处理、损坏的 span 等),因为它涉及手动编写大量代码。
幸运的是,许多框架和库都提供自动 instrumentation,使您可以自动为这些组件生成追踪。自动 instrumentation 几乎不需要代码更改,设置非常快速,并且可以为您提供开箱即用的基本遥测。
重要的是要注意,自动和手动 instrumentation 并非互斥。同时使用这两种技术可能是有益的。自动 instrumentation 可以提供良好的基线遥测,并在您的所有端点上实现高覆盖率。然后可以添加手动 instrumentation 以实现特定的细粒度追踪和自定义指标/元数据。
为 Prisma 设置自动 instrumentation
本节将教您如何使用新的追踪功能为 Prisma 设置自动 instrumentation。首先,在您的 schema.prisma
文件的 generator 块中启用 tracing 功能标志
注意:Tracing 目前是一个 预览功能。这就是为什么您必须添加
tracing
功能标志才能使用 tracing 的原因。
现在,重新生成 Prisma Client
要执行自动 instrumentation,您还需要使用 npm
安装两个新包
需要这些包是因为
@opentelemetry/instrumentation
是设置自动 instrumentation 所必需的。@prisma/instrumentation
为 Prisma Client 提供自动 instrumentation。
根据 OpenTelemetry 术语,instrumented library 是指收集追踪的库或包。另一方面,instrumentation library 是指为某个 instrumented library 生成追踪的库。在这种情况下,Prisma Client 是 instrumented library,而 @prisma/instrumentation
是 instrumentation library。
现在,您需要向 OpenTelemetry 注册 Prisma Instrumentation。为此,请将以下代码添加到您的 tracing.ts
文件中
registerInstrumentations
调用接受两个参数
instrumentations
接受您要注册的所有 instrumentation library 的数组。tracerProvider
接受您的 tracer 的 tracer provider。
设置自动 instrumentation 后,您不再需要手动为 Prisma 查询创建 span。通过删除 Prisma 查询的手动 span 来更新 server.ts
使用自动 instrumentation 时,初始化追踪的顺序很重要。需要在导入 instrumented library 之前设置追踪并注册 instrumentation。在这种情况下,initializeTracing
调用必须在 PrismaClient
的 import
语句之前。
再次向 GET /users/random
端点发出请求,并在 Jaeger 中查看生成的追踪。
这一次,相同的 Prisma 查询生成多个 span,提供关于查询的更精细的信息。启用自动 instrumentation 后,您添加到应用程序中的任何其他查询也将自动生成追踪。
注意: 要了解有关 Prisma 生成的 span 的更多信息,请参阅追踪文档的追踪输出部分。
为 Express 设置自动 instrumentation
目前,您正在通过手动创建 span 来追踪您的端点。随着端点数量的增长,手动追踪将变得难以管理。为了解决这个问题,您也可以为 Express 设置自动 instrumentation。
首先安装以下 instrumentation library
在 tracing.ts
内部注册这两个新的 instrumentation library
最后,删除 server.ts
中 GET /users/random
端点的手动 span
向 GET /users/random
端点发出请求,并在 Jaeger 中查看生成的追踪。
您应该看到更精细的 span,显示请求在您的代码中传递的不同步骤。特别是,您应该看到由 ExpressInstrumentation
library 生成的新 span,显示请求通过各种 Express 中间件和 GET /users/random
请求处理程序。
注意:有关可用 instrumentation library 的列表,请查看 OpenTelemetry Registry。
降低追踪的性能影响
如果您的应用程序向收集器(如 Jaeger)发送大量 span,则可能会对您的应用程序的性能产生重大影响。这通常在您的开发环境中不是问题,但在生产环境中可能是问题。您可以采取一些步骤来缓解这种情况。
批量发送追踪
目前,您正在使用 SimpleSpanProcessor
发送追踪。这是低效的,因为它一次发送一个 span。可以改为使用 BatchSpanProcessor
批量发送 span。
在您的 tracing.ts
文件中进行以下更改,以在生产环境中使用 BatchSpanProcessor
请注意,您仍然在开发环境中使用 SimpleSpanProcessor
,在开发环境中,优化性能不是一个大问题。这确保追踪在开发环境中生成后立即显示。
通过抽样发送更少的 span
概率抽样是一种技术,允许 OpenTelemetry 追踪用户通过使用随机抽样技术来降低 span 收集性能成本。使用此技术,您可以减少发送到收集器的 span 数量,同时仍然可以很好地表示您的应用程序中正在发生的事情。
更新 tracing.ts
以使用概率抽样
就像批量处理一样,您仅在生产环境中合并概率抽样。
总结和最终说明
恭喜!🎉
在本教程中,您学习了
- 什么是追踪,以及为什么要使用它。
- 什么是 OpenTelemetry,以及它与追踪的关系。
- 如何使用 Jaeger 可视化追踪。
- 如何将追踪集成到现有的 Web 应用程序中。
- 如何使用自动 instrumentation library 来提高代码可观测性。
- 如何在生产环境中降低追踪的性能影响。
您可以在 GitHub 上找到此项目的源代码。如果您发现问题,请随时在仓库中提出 issue 或提交 PR。您也可以在 Twitter 上直接联系我。
不要错过下一篇文章!
注册 Prisma 新闻邮件