OpenTelemetry与Jaeger集成指南

OpenTelemetry与Jaeger集成指南(大部分内容由 gpt 生成)

本文档介绍了如何在前端项目中使用OpenTelemetry进行分布式追踪,并将追踪数据发送到Jaeger服务以进行监控和分析。

目录

  1. OpenTelemetry简介
  2. 在前端项目中使用OpenTelemetry
    1. 安装依赖
    2. 配置OpenTelemetry
    3. 使用装饰器封装OpenTelemetry
  3. 创建自定义ClickHouse导出器
  4. 在Grafana中展示ClickHouse数据
  5. Jaeger简介
  6. 部署Jaeger服务

OpenTelemetry简介

OpenTelemetry是一个开源项目,其目标是为分布式系统提供一套统一的、可靠的和可扩展的跟踪和度量数据收集工具。它是由OpenTracing和OpenCensus两个项目合并而成的,现在由云原生计算基金会(CNCF)进行管理和维护。

OpenTelemetry提供了一套API、库和工具,使开发人员能够方便地为他们的应用程序和服务添加跟踪、度量和日志记录功能。这使得在整个系统中可以更容易地收集和分析性能数据,有助于监控、故障排查和优化分布式系统。

核心概念

OpenTelemetry具有一些核心概念,这些概念有助于理解和使用该框架进行分布式追踪和度量数据收集。以下是一些主要概念:

  1. 跟踪(Tracing):跟踪是一种记录分布式系统中请求路径和延迟的技术。通过收集和分析跟踪数据,可以监控系统性能、发现瓶颈并优化服务。

  2. 跨度(Span):跨度是一段连续的操作,表示分布式追踪中的一个工作单元。每个跨度包含一个操作名称、开始时间、结束时间、以及其他可选元数据。跨度可以嵌套,并形成一个跨度树,以表示请求在系统中的完整执行路径。

  3. 追踪上下文(Trace Context):追踪上下文包含了跟踪过程中的元数据,例如追踪ID(Trace ID)和跨度ID(Span ID)。追踪上下文在服务之间传递,以确保完整的请求路径可以在分布式系统中进行跟踪。

  4. 度量(Metrics):度量是对系统性能的定量测量,例如请求速率、错误计数、资源利用率等。OpenTelemetry提供了收集和导出度量数据的工具,以便在监控系统中进行分析。

  5. 资源(Resource):资源是一个表示可观测系统实体(如主机、容器、服务等)的对象。资源可以附加到跟踪和度量数据上,以提供有关数据来源的上下文信息。

  6. 导出器(Exporter):导出器负责将收集到的跟踪和度量数据发送到后端监控系统。OpenTelemetry支持多种导出器,可以将数据发送到不同的监控和分析工具,如Jaeger、Zipkin、Prometheus等。

  7. 处理器(Processor):处理器用于在导出跟踪数据之前处理和过滤数据。例如,可以使用处理器对跨度进行采样、聚合或丢弃。

  8. 提供者(Provider):提供者负责创建和管理追踪器(Tracer)和度量仪(Meter)实例。提供者还负责将处理器和导出器与OpenTelemetry SDK集成。

了解这些核心概念有助于您更好地使用OpenTelemetry来监控和优化您的分布式系统。

这是一个更详细的图示,展示了OpenTelemetry核心概念、组件及其关系:

+----------------+ +-----------+ +----------+ +----------+
| | | | | | | |
| Application +-----> Tracer +-----> Spans +-----> Processor|
| | | | | | | |
+----------------+ +-----------+ +----------+ +-----+----+
|
v
+----------------+ +-----------+ +----------+ +-------------+
| | | | | | | |
| Application +-----> Meter +-----> Metrics +-----> Exporter |
| | | | | | | |
+----------------+ +-----------+ +----------+ +-------------+
|
v
+-------+------+
| |
| Backend |
| Monitoring |
| System |
| |
+--------------+
+----------------+     +-----------+     +----------+     +----------+
|                |     |           |     |          |     |          |
|   Application  +----->  Tracer   +----->  Spans   +-----> Processor|
|                |     |           |     |          |     |          |
+----------------+     +-----------+     +----------+     +-----+----+
                                                       |
                                                       v
+----------------+     +-----------+     +----------+     +-------------+
|                |     |           |     |          |     |             |
|   Application  +----->  Meter    +-----> Metrics  +----->  Exporter   |
|                |     |           |     |          |     |             |
+----------------+     +-----------+     +----------+     +-------------+
                                                       |
                                                       v
                                               +-------+------+
                                               |              |
                                               |  Backend     |
                                               |  Monitoring  |
                                               |  System      |
                                               |              |
                                               +--------------+
+----------------+ +-----------+ +----------+ +----------+ | | | | | | | | | Application +-----> Tracer +-----> Spans +-----> Processor| | | | | | | | | +----------------+ +-----------+ +----------+ +-----+----+ | v +----------------+ +-----------+ +----------+ +-------------+ | | | | | | | | | Application +-----> Meter +-----> Metrics +-----> Exporter | | | | | | | | | +----------------+ +-----------+ +----------+ +-------------+ | v +-------+------+ | | | Backend | | Monitoring | | System | | | +--------------+
  • Application:这是您的应用程序或服务,它使用OpenTelemetry库进行跟踪和度量数据收集。
  • Tracer:Tracer负责在应用程序中创建和管理跨度。它通常与提供者关联,以便在需要时创建Tracer实例。
  • Spans:Spans是跟踪过程中的工作单元,表示一个操作或事件。Spans可以嵌套,并形成一个跨度树,表示请求在分布式系统中的执行路径。
  • Processor:处理器用于在导出跟踪数据之前处理和过滤数据。例如,可以使用处理器对跨度进行采样、聚合或丢弃。
  • Meter:Meter负责在应用程序中创建和管理度量数据。它通常与提供者关联,以便在需要时创建Meter实例。
  • Metrics:这些是收集到的度量数据,例如计数器、计时器、值记录器等。度量数据可用于监控系统性能和资源利用率。
  • Exporter:Exporter负责将收集到的跨度和度量数据发送到后端监控系统。可以配置不同的导出器,将数据发送到不同的监控和分析工具。
  • Backend Monitoring System:这是一个后端监控系统,如Jaeger、Prometheus或Grafana,用于存储、分析和可视化收集到的跟踪和度量数据。

这个图示展示了应用程序如何使用Tracer和Meter来收集跨度和度量数据,然后通过Processor和Exporter发送到后端监控系统。这些核心概念共同构成了OpenTelemetry框架的基础。

在前端项目中使用OpenTelemetry

安装依赖

使用npm或yarn安装所需的依赖包:

npm install --save @opentelemetry/api
npm install --save @opentelemetry/core
npm install --save @opentelemetry/web
npm install --save @opentelemetry/tracing
npm install --save @opentelemetry/exporter-jaeger
npm install --save @opentelemetry/exporter-zipkin
npm install --save @opentelemetry/api
npm install --save @opentelemetry/core
npm install --save @opentelemetry/web
npm install --save @opentelemetry/tracing
npm install --save @opentelemetry/exporter-jaeger
npm install --save @opentelemetry/exporter-zipkin
npm install --save @opentelemetry/api npm install --save @opentelemetry/core npm install --save @opentelemetry/web npm install --save @opentelemetry/tracing npm install --save @opentelemetry/exporter-jaeger npm install --save @opentelemetry/exporter-zipkin

配置OpenTelemetry

在您的前端项目中创建一个文件(例如:tracing.ts),并添加以下内容:

import { ConsoleSpanExporter, SimpleSpanProcessor, WebTracerProvider } from '@opentelemetry/sdk-trace-web';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
import { Resource } from "@opentelemetry/resources";
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";
const resource = Resource.default().merge(new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: "service-name-here",
[SemanticResourceAttributes.SERVICE_VERSION]: "0.1.0",
}));
// 初始化WebTracerProvider
const provider = new WebTracerProvider({
resource,
});
provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));
// 配置 SimpleSpanProcessor 使用指定的导出器
provider.addSpanProcessor(
new SimpleSpanProcessor(new OTLPTraceExporter())
);
// 注册 provider
// provider.register({
// contextManager: new ZoneContextManager(),
// propagator: new B3Propagator(),
// });
provider.register();
import { ConsoleSpanExporter, SimpleSpanProcessor, WebTracerProvider } from '@opentelemetry/sdk-trace-web';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
import { Resource } from "@opentelemetry/resources";
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";



const resource = Resource.default().merge(new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: "service-name-here",
    [SemanticResourceAttributes.SERVICE_VERSION]: "0.1.0",
}));
// 初始化WebTracerProvider
const provider = new WebTracerProvider({
    resource,
});



provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));
// 配置 SimpleSpanProcessor 使用指定的导出器
provider.addSpanProcessor(
    new SimpleSpanProcessor(new OTLPTraceExporter())
);

// 注册 provider
// provider.register({
//     contextManager: new ZoneContextManager(),
//     propagator: new B3Propagator(),
// });
provider.register();
import { ConsoleSpanExporter, SimpleSpanProcessor, WebTracerProvider } from '@opentelemetry/sdk-trace-web'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'; import { Resource } from "@opentelemetry/resources"; import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions"; const resource = Resource.default().merge(new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: "service-name-here", [SemanticResourceAttributes.SERVICE_VERSION]: "0.1.0", })); // 初始化WebTracerProvider const provider = new WebTracerProvider({ resource, }); provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); // 配置 SimpleSpanProcessor 使用指定的导出器 provider.addSpanProcessor( new SimpleSpanProcessor(new OTLPTraceExporter()) ); // 注册 provider // provider.register({ // contextManager: new ZoneContextManager(), // propagator: new B3Propagator(), // }); provider.register();

使用装饰器封装OpenTelemetry

创建一个装饰器文件(例如:trace-decorator.ts):

import { trace, Tracer, Span, context } from '@opentelemetry/api';
export function Trace() {
const tracer: Tracer = trace.getTracer('your-frontend-service-name');
return function (
target: Object,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
const span: Span = tracer.startSpan(`${target.constructor.name}.${propertyKey}`);
const result = context.with(trace.setSpan(context.active(), span), () => {
try {
return originalMethod.apply(this, args);
} catch (error: any) {
span.recordException(error);
span.setStatus({ code: 2, message: error.message });
throw error;
} finally {
span.end();
}
});
return result;
};
return descriptor;
};
}
import { trace, Tracer, Span, context } from '@opentelemetry/api';


export function Trace() {
    const tracer: Tracer = trace.getTracer('your-frontend-service-name');


    return function (
        target: Object,
        propertyKey: string,
        descriptor: PropertyDescriptor
    ) {
        const originalMethod = descriptor.value;

        descriptor.value = function (...args: any[]) {
            const span: Span = tracer.startSpan(`${target.constructor.name}.${propertyKey}`);



            const result = context.with(trace.setSpan(context.active(), span), () => {
                try {
                    return originalMethod.apply(this, args);
                } catch (error: any) {
                    span.recordException(error);
                    span.setStatus({ code: 2, message: error.message });
                    throw error;
                } finally {
                    span.end();
                }
            });

            return result;
        };

        return descriptor;
    };
}
import { trace, Tracer, Span, context } from '@opentelemetry/api'; export function Trace() { const tracer: Tracer = trace.getTracer('your-frontend-service-name'); return function ( target: Object, propertyKey: string, descriptor: PropertyDescriptor ) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { const span: Span = tracer.startSpan(`${target.constructor.name}.${propertyKey}`); const result = context.with(trace.setSpan(context.active(), span), () => { try { return originalMethod.apply(this, args); } catch (error: any) { span.recordException(error); span.setStatus({ code: 2, message: error.message }); throw error; } finally { span.end(); } }); return result; }; return descriptor; }; }

在您的类和方法上应用装饰器:

index.ts

import { Trace } from './trace-decorator';
class ExampleClass {
@Trace()
public topLevelMethod(): void {
console.log('Executing top-level method');
this.nestedMethod();
}
@Trace()
public nestedMethod(): void {
console.log('Executing nested method');
}
}
const exampleInstance = new ExampleClass();
exampleInstance.topLevelMethod();
import { Trace } from './trace-decorator';


class ExampleClass {
  @Trace()
  public topLevelMethod(): void {
    console.log('Executing top-level method');
    this.nestedMethod();
  }

  @Trace()
  public nestedMethod(): void {
    console.log('Executing nested method');
  }
}



const exampleInstance = new ExampleClass();
exampleInstance.topLevelMethod();
import { Trace } from './trace-decorator'; class ExampleClass { @Trace() public topLevelMethod(): void { console.log('Executing top-level method'); this.nestedMethod(); } @Trace() public nestedMethod(): void { console.log('Executing nested method'); } } const exampleInstance = new ExampleClass(); exampleInstance.topLevelMethod();

Jaeger简介

Jaeger是一个开源的分布式追踪系统,用于监控、分析和调试微服务架构中的事务流程和性能。Jaeger由Uber开发,后来成为了云原生计算基金会(CNCF)的项目。Jaeger提供了端到端的请求追踪功能,帮助开发人员识别性能瓶颈、延迟问题、服务依赖关系等,从而优化分布式系统的性能。

部署Jaeger服务

部署Jaeger服务有多种方法,以下是使用Docker的快速部署方法:

  1. 确保您已经安装了Docker

  2. Docker Hub获取Jaeger的all-in-one镜像。这个镜像包含了Jaeger的所有组件(Agent、Collector、Query和UI),并使用内存作为存储后端。这种部署方式非常适合本地开发和测试:

docker pull jaegertracing/all-in-one
docker pull jaegertracing/all-in-one
docker pull jaegertracing/all-in-one
  1. 运行Jaeger all-in-one容器:
docker run -d --name jaeger \
-e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
-p 5775:5775/udp \
-p 6831:6831/udp \
-p 6832:6832/udp \
-p 5778:5778 \
-p 16686:16686 \
-p 14268:14268 \
-p 14250:14250 \
-p 9411:9411 \
jaegertracing/all-in-one:latest
docker run -d --name jaeger \
  -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
  -p 5775:5775/udp \
  -p 6831:6831/udp \
  -p 6832:6832/udp \
  -p 5778:5778 \
  -p 16686:16686 \
  -p 14268:14268 \
  -p 14250:14250 \
  -p 9411:9411 \
  jaegertracing/all-in-one:latest
docker run -d --name jaeger \ -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \ -p 5775:5775/udp \ -p 6831:6831/udp \ -p 6832:6832/udp \ -p 5778:5778 \ -p 16686:16686 \ -p 14268:14268 \ -p 14250:14250 \ -p 9411:9411 \ jaegertracing/all-in-one:latest

这将启动一个名为“jaeger”的容器,并将Jaeger的各个组件端口映射到宿主机。现在,您可以通过访问http://localhost:16686来使用Jaeger UI。

请注意,这种部署方式主要用于本地开发和测试。对于生产环境,您需要考虑使用更可扩展的部署方式,例如将Jaeger组件分别部署,并使用外部存储后端(如Cassandra或Elasticsearch)。

有关Jaeger部署的更多详细信息和选项,请参阅Jaeger官方文档

构建和运行项目

使用 tsc 编译 index.ts 文件,然后执行

node dist/index.js
node dist/index.js
node dist/index.js

执行完之后, 打开 http://localhost:16686 页面,就可以看到有数据上报了。

image.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYU8N66d' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片