如何基于标准化的OpenTelemetry构建APM探针能力

导语 | 本文推选自腾讯云开发者社区-【技思广益 · 腾讯技术人原创集】专栏。该专栏是腾讯云开发者社区为腾讯技术人与广泛开发者打造的分享交流窗口。栏目邀约腾讯技术人分享原创的技术积淀,与广泛开发者互启迪共成长。本文作者是腾讯前端高级开发工程师常敏。

云原生为传统监控带来挑战。云原生场景下,企业大规模地部署容器,应用节点呈指数级增长,故障可能发生在任意节点,无法感知与预测的因素越来越多。业界将“可观测性”能力划分为5个层级,其中告警(Alerting)与应用概览(Overview)属于传统监控的概念范畴。腾讯云“应用性能观测”则补齐主动发现的能力。构建简单易用,高性能的全链路监控系统。如何做到简单易用,满足用户拿来即用的需求?构建标准化,完善的探针能力是关键。

监控与可观测性的关系

(一)“监控”是“可观测性”能力的一部分

业界将“可观测性”能力划分为5个层级,其中告警(Alerting)与应用概览(Overview)属于传统监控的概念范畴。由于触发告警的往往是明显的症状与表象,但随着架构与应用部署方式的转变,不告警并非意味着一切正常,因此,获取系统内部的信息就显得尤为重要,而这些信息则须借助“可观测性”能力的另一大组成部分——主动发现(Preactive)。

如上图所示,告警和应用概览属于传统监控。加上主动发现,才能组成可观测系统。

“主动发现”,由排错、剖析与依赖分析三部分组成:

  • 排错(Degugging),即运用数据和信息去诊断故障出现的原因。
  • 剖析(Profiling),即运用数据和信息进行性能分析。
  • 依赖分析(Dependency Analysis),即运用数据信息厘清系统之前的模块,并进行关联分析。

(二)面向的核心用户不同

监控是以运维为核⼼的系统,它通过各项指标数据来定义整体的运⾏状态、失败情况等;

观测则是以开发为核⼼的系统,除了监控,它还会对整个系统进⾏分析。

很多时候,运维给出的错误数据,只能算是提出了问题,但可观测性除了提出问题,还可以清晰地给出根因分析和故障预测等。

(三)维度不同

监控是从外围的⻆度,通过各种指标(机器CPU、负载、⽹络的维度等)来判断整个系统的执⾏情况;⽽可观测性则在这种外部指标的基础上,以应⽤内的各个维度来展开推测, 最后,通过⼆者结合的数据更加真实地反映出我们应⽤的运⾏情况。

(四)展现的信息不同

有些系统在正常运⾏时⼗分稳定,但是⼀到⾼并发的时候就会出现问题。此时,监控只能汇报问题出现的状况,但可观测性就可以很好地通过图形化的⽅式告知我们问题的原因,⽽不是由我们⽤经验来猜测。它可以将未知或者不确定的信息展现出来,使我们可以更好地了解系统的整体情况。

可观测性三大核心概念

  • Traces:分布式链路跟踪,提供了一个请求从接收到处理完成整个生命周期的跟踪路径。
  • Metrics:提供cpu、请求延迟、用户访问数等Counter、Gauge、Histogram指标。
  • Logs:传统的日志,提供精确的系统记录。

很长一段时间内,这三者是独立存在的,随着时间的推移,发现这三者是相互关联,相辅相成。

  • 基于Metrics告警发现异常。
  • 通过Tracing定位到具体的系统和方法。
  • 根据模块的日志最终定位到错误详情和根源。
  • 调整Metrics等设置,更精确的告警/发现问题。

为什么基于OpenTelemetry构建探针能力?

(一)OpenTelemetry是什么?

OpenTelemetry是CNCF的一个可观测性项目,旨在提供可观测性领域的标准化方案,解决观测数据的数据模型、采集、处理、导出等的标准化问题,提供与三方vendor无关的服务。

OpenTelemetry是云原生软件的可观察性框架。架构图如下图所示,由API,SDK和Collector三部分组成。您可以使用它来生成,收集和导出遥测数据(指标,日志和跟踪),然后进行分析,方便了解软件的性能和行为。

(二)APM探针技术选型和开发

探针开发的目标:

  • 满足大客户定探针制化需求。
  • 降低接入门槛;降低部署成本。
  • 完善语言生态。完善各个语言组件生态环境;Java语言方法栈、堆栈快照能力等。
  • 组件维度协议标准化,降低接入定制化成本。

JAVA开源框架对比:

探针的开发其实就是对语言所含的生态组件的开发,在java语言上就是通过字节码增强对技术,对组建的接口进行增强,在接口的头尾进行埋点的操作。

生态完善度统计了自动插桩支持的组件数量。

Node开源框架对比:

底层原理及本质区别:

自动插桩:实现原理没有本质区别,都是基于AOP,面向切面的编程实现,javascript的apply函数。实现方式,通过swapper函数进行封装,对每个层面的IO进行监控。

生态完善度统计了自动插桩支持的组件数量。

通过对比分析,OpenTelemetry支持标准化的SDK+数据接入能力,支持的插件也比较丰富。同时具有如下优势:

  • 完全中立的厂商,不收费。
  • 统一协议。现在与未来链路的标准协议,一套系统,数据关联。
  • 完善探针和组件。
  • 易扩展。
  • 兼容性好。兼容OpenTracing,OpenCensus,Promethus...

另外,在OpenTelemetry方面,腾讯有“云原生可观测性Oteam”,更利于协同打造完备的可观测生态系统。所以我们决定采用OpenTelemetry进行探针开发。

NodeJS SDK 探针实践

(一)OpenTelemetry JS项目概况

OpenTelemetry社区拆分为了三个仓库:

  • opentelemetry-js: 区分Node和Web等不同的场景,提供了 OpenTelemetry 的核心SDK,包含了OpenTelemetry的基础能力。
  • opentelemetry-js-api: 为用户提供了使用OpenTelemetry所需的 API,但默认不提供任何具体的实现。可以理解为,该仓库仅提供了 interface,然后通过SDK来注册具体的实现方式。也由于API不涉及具体实现,因此它在Node和Web等场景下都是通用的,只是需要在不同场景下使用不同的SDK进行注册。
  • opentelemetry-js-contrib: 区分Node和Web等不同的场景,提供了OpenTelemetry的非核心SDK,为JS生态下的常用库提供OpenTelemetry的能力,如koa、ioredis等。

(二)NodeJS项目如何接入自动插桩的能力

首先对OpenTelemetry Trace SDK进行初始化

在Node端使用@opentelemetry/sdk-trace-node。但 @opentelemetry/sdk-trace-node集成了很多包作为依赖,其中大部分我们可能并不会用到。因此我们建议使用@opentelemetry/sdk-trace-base,然后按需安装所需要的依赖:

代码语言:javascript
复制
import { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';
// 创建 tracerProviderconst tracerProvider = new BasicTracerProvider(/* 创建选项 */)// 添加 Span 上报方式tracerProvider.addSpanProcessor(/* Span 处理器,上报器 */)// 全局注册 tracerProvidertracerProvider.register(/* 注册选项 */)

初始化后,上报到“应用性能观测APM”, 只需要三步:

1)获取接入点和Token

获取地址:

https://console.cloud.tencent.com/apm/monitor/access

接入点:

grpc://ap-guangzhou.apm.tencentcs.com:4317

Token:Vds************CrKck

2)在创建tracerProvider时添加APM的额外attributes:

代码语言:javascript
复制
import { Resource } from '@opentelemetry/resources';import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';import { ApmResourceAttributes } from './ApmResourceAttributes';
/** * 获取上报的服务资源标签 */export const getResource = async (): Promise<Resource> => {  // 如果要上报apm,请添加这些字段。  // 服务名称等基础字段。更多字段可参考 @opentelemetry/semantic-conventions  return new Resource({    // 必填,服务名称(在“应用列表”或“调用链”等地方显示对应的服务)    [SemanticResourceAttributes.SERVICE_NAME]: 'node_simple_server',    // 必填,token(上报鉴权 ApmResourceAttributes.APM_TOKEN = token)    [ApmResourceAttributes.APM_TOKEN]: 'oSmwaUrjLIbBiTZiNtSv',    // 可选    [ApmResourceAttributes.APP_ID]: 'node_simple_server',    // 可选    [ApmResourceAttributes.SERVER_ID]: 'node_simple_server',    // 可选    [ApmResourceAttributes.SERVER_OWNER]: 'foo;bar',  })};

APM约束常量定义类:

代码语言:javascript
复制
/** * APM约定的 ResourceAttributes * * @see 暂时没有对外文档 */export const ApmResourceAttributes = {    /**     * (必选)APM的token     * 在APM创建一个实例后,APM会给这个实例创建一个对应的“上报地址”和“token”     *     * @see https://console.cloud.tencent.com/apm/monitor/access     */    APM_TOKEN: 'token',
/**     * (可选)模块 ID     *     * @example &#39;bigdata&#39;     */    APP_ID: &#39;app.id&#39;,
/**     * (可选)模块名称     *     * @example &#39;大数据模块&#39;     */    APP_NAME: &#39;app.name&#39;,
/**     * (可选)server ID     *     * @example &#39;collector&#39;     */    SERVER_ID: &#39;server.id&#39;,
/**     * (可选)server 名称     *     * @example &#39;收集服务&#39;     */    SERVER_NAME: &#39;server.name&#39;,
/**     * (可选)server 负责人     *     * 多个负责人用英文分号分隔     *     */    SERVER_OWNER: &#39;server.owner&#39;,};</code></pre></div></div><p>3)通过addSpanProcessor添加对应的上报方式:</p><ul class="ul-level-0"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">  import { OTLPTraceExporter } from &#39;@opentelemetry/exporter-trace-otlp-grpc&#39;;  import { SimpleSpanProcessor } from &#39;@opentelemetry/sdk-trace-base&#39;;

// 如果要将 trace 信息上报apm,请使用 grpc OTLPTraceExporter 上报至对应 URL tracerProvider.addSpanProcessor( new SimpleSpanProcessor( new OTLPTraceExporter({ // apm-collector URL(配置上报的实例地址) url: 'grpc://ap-guangzhou.apm.tencentcs.com', concurrencyLimit: 200, }), ), );

(三)OpenTelemetry nodejs探针支持的插件

OpenTelemetry支持丰富自动检测插件,使用比较简单。唯一要注意的是,需要认真查看插件client支持的版本号。

插件

说明

@opentelemetry/instrumentation-aws-lambda

AWS Lambda ,无需考虑服务器或集群即可运行代码。 类似腾讯的“云函数“

@opentelemetry/instrumentation-aws-sdk

此模块为 aws-sdk v2 和 @aws-sdk v3 提供自动检测。类似于腾讯的“云API”

@opentelemetry/instrumentation-bunyan

Nodejs的日志处理

@opentelemetry/instrumentation-pino

开销非常低的 Node.js 日志处理。

@opentelemetry/instrumentation-winston

日志处理

@opentelemetry/instrumentation-cassandra-driver

Cassandra是一套开源分布式NoSQL数据库系统

@opentelemetry/instrumentation-connect

Connect 是一个简单的框架,可以将各种“中间件”粘合在一起来处理请求。

@opentelemetry/instrumentation-dns

Node.js DNS 模块用于解析域名。

@opentelemetry/instrumentation-http

该模块为 http 和 https 提供自动检测。

@opentelemetry/instrumentation-grpc

Node.js gRPC 库

@opentelemetry/instrumentation-hapi

Nodejs 的框架

@opentelemetry/instrumentation-express

Nodejs 的框架

@opentelemetry/instrumentation-koa

Nodejs 的框架

@opentelemetry/instrumentation-fastify

Nodejs 的框架

@opentelemetry/instrumentation-generic-pool

数据库链接池

@opentelemetry/instrumentation-graphql

GraphQL

@opentelemetry/instrumentation-ioredis

Redis客户端

@opentelemetry/instrumentation-redis

Redis

@opentelemetry/instrumentation-pg

PostgreSQL 客户端

@opentelemetry/instrumentation-knex

SQL 查询生成器

@opentelemetry/instrumentation-memcached

Memcached 客户端。Memcached是一个自由开源的,高性能,分布式内存对象缓存系统。

@opentelemetry/instrumentation-mongodb

Node.js 的官方 MongoDB 驱动程序

@opentelemetry/instrumentation-mysql2

MySQL 2客户端

@opentelemetry/instrumentation-net

Node.js Net 模块提供了一些用于底层的网络通信的小工具,包含了创建服务器/客户端的方法

@opentelemetry/instrumentation-restify

restify 是一个框架,利用连接风格的中间件来构建 REST API

应用性能观测的架构和优势

(一)应用性能观测的架构

红色字体模块代表APM模块,蓝色背景色区域代表监控中台模块。

(二)应用性能监控的优势

  • APM基于OpenTelemetry探针进行了二次开发,给用户提供使用简单,功能强大的探针能力。用户拿来即用。

  • 提供监控中台计算、存储,查询和告警能力。
  • 高性能自研可视化图表库,提供高性能,差异化的调用链拓扑图。
  • 未来云原生下可观测性展望。

可观察性与AIOps(Artificial Intelligence for IT Operations智能运维)结合,可以把可观测性分为6个等级。

目前我们已实现智能告警的能力(Level 1)。相比较传统阈值监控:无需考虑阈值设置,基于算法自动生成动态边界;业务变更智能策略依然有效。

等级0:手工分析,依靠基础的Dashboard、告警、日志查询、分布式链路追踪等方式进行手动告警、分析,也是目前绝大部分公司使用的场景。

等级1:智能告警,能够自动去扫描所有的可观察性数据,利用机器学习的方式去识别一些异常并进行自动告警,免去人工设置/调整各种基线告警的工作。

等级2:异常关联+统一视图,对于自动识别的异常,能够进行上下文的关联,形成一个统一的业务视图,便于快速的定位问题。

等级3:根因分析+问题自愈,自动根据异常以及系统的CMDB信息直接定位问题的根因,根因定位准确后那边可以去做问题的自愈。这一阶段相当于是一次质的飞跃,在某些场景下可以在人不用参与的情况下实现问题的自愈。

等级4:故障预测,故障发生总会有损失,所以最好的情况是避免故障的发生,因此故障预测技术可以更好的来保证系统的可靠性,利用之前积累的一些故障先兆信息做到“未卜先知”。

等级5:变更影响预测,我们知道绝大部分的故障都是由变更引起的,因此如果能够模拟出每个变更对系统带来的影响以及可能产生的问题,我们就能够提前评估出是否能够允许此次变更。

 作者简介

常敏

腾讯云开发者社区【技思广益·腾讯技术人原创集】作者

腾讯前端高级工程师,负责腾讯基础监控和全链路监控相关业务。在数据可视化领域具有丰富的开发和设计经验。

 推荐阅读

DevOps难以落地之谜,揭开DevOps的神秘面纱!

看完这篇,轻松get限流!

自定义Clang命令,利用LLVM Pass实现对OC函数的静态插桩

深度解读Vite的依赖扫描

👇点击「阅读原文」,注册成为社区创作者,认识大咖,打造你的技术影响力!