关于nginx:现代应用参考架构之-OpenTelemetry-集成进展报告

210次阅读

共计 10102 个字符,预计需要花费 26 分钟才能阅读完成。

原文作者:Elijah Zupancic of F5 和 Jason Schmidt of F5
原文链接:古代利用参考架构之 OpenTelemetry 集成停顿报告
转载起源:NGINX 官方网站


去年秋天咱们在 Sprint 2.0 上介绍 NGINX 古代利用参考架构 (MARA) 我的项目时,就曾强调过这不是一个随随便便的架构,咱们的初衷是打造一款“稳固牢靠、通过测试且能够部署到在 Kubernetes 环境中运行的实时生产利用”的解决方案。对于这样一个我的项目来说,可观测性工具能够说是必不可少。MARA 团队的所有成员都曾亲自体验过,不足状态和性能洞察会让利用开发和交付变得如许艰难。咱们很快就达成了共识,即 MARA 必须增加能够在生产环境中进行调试和跟踪的工具。

MARA 的另一项领导准则是首选开源解决方案。本文形容了咱们对多功能开源可观测性工具的谋求是如何使咱们将眼光转向 OpenTelemetry 的,而后具体介绍了其中的利弊衡量和设计决策,以及采纳了哪些技术将 OpenTelemetry 与应用 Python、Java 和 NGINX 构建的微服务利用相集成。

咱们心愿咱们的教训能够帮忙您避开可能的陷阱,并放慢您对 OpenTelemetry 的采纳。请留神,本文是一份具备时效性的停顿报告 —— 咱们探讨的技术预计将在一年内成熟。此外,只管咱们指出了某些我的项目以后的不足之处,但咱们依然对所有曾经实现的开源工作深表感谢,并期待它们将来获得更好的停顿。

咱们的利用

咱们抉择了 Bank of Sirius 作为集成可观测性解决方案的利用。Bank of Sirius 是咱们从 Google 提供的 Bank of Anthos 示例利用引出的分支,是一个具备微服务架构的 Web 利用,能够通过基础架构即代码进行部署。尽管咱们能够通过很多种形式来改良此利用的性能和可靠性,但它曾经足够成熟,能够被正当地认为是一种“棕地”利用。因而,咱们认为这是一个展现如何将 OpenTelemetry 集成到利用中的好例子,因为实践上分布式跟踪能够生成无关利用架构毛病的贵重洞察。

如图所示,反对利用的 service 绝对简略。

咱们是怎么抉择了 OpenTelemetry

咱们抉择 OpenTelemetry 的路线相当波折,经验了几个阶段。

创立性能清单

在评估可用的开源可观测性工具之前,咱们确定了哪些方面须要关注。依据过来的教训,咱们列出了以下清单。

  • 日志记录 —— 顾名思义,这意味着从利用中生成经典的、以换行符分隔的音讯集;Bank of Sirius 利用会以 Bunyan 格局构建日志
  • 分布式跟踪 —— 整个利用中每个组件的 Timing 和元数据,例如供应商提供的利用性能治理 (APM)
  • 指标 —— 在一段时间内捕捉并以工夫序列数据的模式绘制的测量值 /li>
  • 异样 / 谬误聚合和告诉 —— 一个聚合了最常见的异样和谬误的汇合,该汇合必须是可搜寻的,以便咱们能够确定哪些利用谬误是最常见的谬误
  • 健康检查 —— 发送给 service 的定期探针,用于确定它们是否在利用中失常运行
  • 运行时状态自检 —— 一组仅对管理员可见的 API,能够返回无关利用运行时状态的信息
  • 堆转储 / 外围转储 —— service 运行时状态的综合快照;思考到咱们的目标,很重要的一点就是看在须要时或在 service 解体时获取这些堆转储的难易水平

对照性能清单比拟工具性能

当然,咱们并不指望一个开源工具或一种办法就能搞定所有性能,但至多它为咱们提供了一个比拟可用工具的现实根据。咱们查阅了每个工具的文档,确定了各个工具可反对七项性能清单中的哪些性能。下表对咱们的发现进行了总结。

技术日志记录分布式跟踪指标谬误聚合健康检查运行时自检堆 / 外围转储
ELK + Elastic APM
Grafana
Graylog
Jaeger
OpenCensus
OpenTelemetryBeta✅*
Prometheus
StatsD
Zipkin

* 作为一项扩大性能

做完这张表格后,咱们忽然意识到一个问题。各个工具的性能和预期用处差异很大,咱们基本不能将它们归为一类,这样的比拟能够说是驴唇不对马嘴!

举例来说,ELK(Elasticsearch-Logstash-Kibana,再加上 Filebeat)和 Zipkin 的作用具备根本性的不同,两相比拟只会让人摸不着头脑。遗憾的是,为了响应用户申请,有些工具无疑还会增加一些主要的性能,从而与其余工具产生性能上的重叠,这就是臭名远扬的“工作蔓延”问题。从外表上看,ELK 主攻日志存储和可视化,Zipkin 善于分布式跟踪。但如果您略微深入研究一下 Elastic 产品组合,您很快就会发现其中的 Elastic APM 也反对分布式跟踪,甚至兼容 Jaeger。

除了工作蔓延的问题外,许多工具还能够互相集成,从而产生各种不同的收集器、聚合器、仪表板等性能组合。有些技术互相兼容,有些则不兼容。

执行定性考察

综上所述,这个比拟表格无奈帮忙咱们足够精确地做出抉择。思考到一个我的项目的价值观与咱们的价值观越类似,咱们就越有可能在一段时间内放弃兼容,咱们决定对每个我的项目的指标、领导准则和可能的将来方向进行定性考察。拜访 OpenCensus 页面时,咱们一眼就发现了这段话。

OpenCensus 和 OpenTracing 合并造成了 OpenTelemetry,以作为 OpenCensus 和 OpenTracing 的下一个主版本。OpenTelemetry 将向后兼容现有的 OpenCensus 集成,咱们将在将来两年内持续为现有 OpenCensus 库打安全补丁。

这条信息对咱们来说很要害。咱们晓得咱们无奈保障咱们的抉择肯定会经得起将来考验,但咱们至多要晓得将来它是否有松软的社区反对。有了这些信息,咱们就能够将 OpenCensus 从候选名单中剔除了。应用 Jaeger 可能也不是一个好主见,因为它是现已正式弃用的 OpenTracing 我的项目的参考实现 — 大部分新奉献将落在 OpenTelemetry 上。

而后咱们查阅了 OpenTelemetry Collector 的网页。

OpenTelemetry Collector 针对如何接管、解决和导出遥测数据提供了的实现,并且不受供应商的限度。此外,它无需运行、操作和保护多个代理 / 收集器,即可反对将开源遥测数据格式(例如 Jaeger、Prometheus 等)发送到多个开源或商用后盾零碎。

OpenTelemetry Collector 充当聚合器,容许咱们应用不同的后端来混搭不同的可观测性收集和检测办法。简略来说,咱们的利用能够应用 Zipkin 收集跟踪信息、应用 Prometheus 获取指标,这些信息都能够被发送到可配置的后端,而后咱们再应用 Grafana 对其进行可视化。这种设计的其余一些排列组合也是可行的,因而咱们能够多尝试几种办法,看看到底哪些技术适宜咱们的用例。

选定 OpenTelemetry 集成作为前进方向

咱们最终将眼光落在了 OpenTelemetry Collector 上,因为实践上它容许咱们切换不同的可观测性技术。只管该我的项目绝对不那么成熟,但咱们决定大胆一试,应用仅具备开源集成的 OpenTelemetry——毕竟货色好不好,用了才晓得。

然而,OpenTelemetry Collector 还是短少一些性能,咱们必须增加其余技术来填补这些缺口。以下大节总结了咱们的抉择及其背地的起因。

  • 施行日志记录
  • 施行分布式跟踪
  • 施行指标收集
  • 施行谬误聚合
  • 施行健康检查和运行时自检
  • 施行堆转储和外围转储

施行日志记录

在抉择可观测性工具时,日志记录这一因素看似简略,实则并不好抉择。说它简略,是因为您只需从容器中获取日志输入即可;说它简单,是因为您须要决定将数据存储在哪里、如何将其传输到该存储库、如何进行索引能力使其施展效用,以及这些数据须要保留多长时间。只有反对依据足够多的不同规范(以满足不同搜寻者的需要)轻松进行搜寻,日志文件能力施展效用。

咱们钻研了 OpenTelemetry Collector 的日志记录反对,在撰写本文时它还处于 Beta 测试阶段。咱们决定短期内应用 ELK 进行日志记录,同时持续考察其余抉择。

在没有更好的抉择之前,咱们默认应用 Elasticsearch 工具,以便将部署分为 ingest、coordinating、master 和 data 节点。为了便于部署,咱们应用了 Bitnami 图表。为了传输数据,咱们将 Filebeat 部署到 Kubernetes DaemonSet 中。通过部署 Kibana 并利用预加载的索引、搜寻、可视化和仪表盘,咱们轻松增加了搜寻性能。

很快咱们便发现,只管这个解决方案可行,但其默认配置十分消耗资源,因而很难在 K3S 或 Microk8s 等资源占用较小的环境中运行。尽管咱们通过调整每个组件的正本数量解决了上述问题,但却呈现了一些故障,这些故障可能是因为资源耗尽或数据量过多所致。

咱们并未因而泄气,而是将借机对采纳不同配置的日志记录零碎进行基准测试,并钻研其余选项,如 Grafana Loki 和 Graylog。咱们很可能会发现轻量级的日志记录解决方案无奈提供某些用户须要的全套性能,而这些性能可能为资源密集型工具所提供。鉴于 MARA 的模块化个性,咱们可能会为这些选项构建额定的模块,从而为用户提供更多的抉择。

施行分布式跟踪

除了须要确定哪种工具可提供咱们所需的跟踪性能之外,咱们还需思考解决方案的施行形式以及须要与之集成的技术。

首先,咱们心愿确保任何工具都不会影响利用自身的服务质量。咱们都有过这样的经验:在导出日志时,零碎性能每小时就会降落一次,因而咱们不想再吃一堑; 长一智。在这方面,OpenTelemetry Collector 的架构引人注目,因为它反对您在每个主机上运行一个实例。每个收集器从主机上运行的所有不同利用(容器化或其余类型)中的客户端和代理中接收数据。收集器会整合,并(可能)会压缩这些数据,而后将其发送到存储后端。这听起来棒极了。

接下来,咱们评估了利用中所用的不同编程语言和框架对 OpenTelemetry 的反对。此时,事件变得有点辣手。只管咱们只应用了两种编程语言和相干框架(如下表所示),但复杂程度之高令人咂舌。

语言框架service 数量
JavaSpring Boot3
PythonFlask3

为了增加语言级跟踪,咱们首先尝试了 OpenTelemetry 的自动检测代理,但却发现其输入数据凌乱不堪。咱们置信,随着自动检测库的日趋成熟,这种状况会有所改善。但目前咱们不思考 OpenTelemetry 代理,并决定将跟踪语句退出咱们的代码。

在开始在代码中间接实现跟踪之前,咱们首先连贯了 OpenTelemetry Collector,以便将所有跟踪数据输入到本地运行的 Jaeger 实例,从而更轻松地从中查看输入后果。这样做有很大帮忙,因为当咱们理解如何全面集成 OpenTelemetry 时,便可应用跟踪数据的可视图像。例如,如果在调用隶属服务时发现 HTTP 客户端库不含跟踪数据,咱们能够立刻将该问题增加到修复列表中。Jaeger 在单个跟踪中清晰出现了所有不同跨度:

Python 分布式跟踪

在咱们的 Python 代码中增加跟踪语句相对来说比较简单。咱们增加了两个咱们所有 service 都援用的 Python 源文件,并更新了各自的 requirements.txt 文件,以增加相干的 opentelemetry-instrumentation-* 依赖项。这意味着咱们不仅能够对所有 Python 服务应用雷同的跟踪配置,而且还可能将每个申请的跟踪 ID 增加到日志音讯中,并将跟踪 ID 嵌入隶属 service 的申请。

Java 分布式跟踪

接下来,咱们将眼帘转向 Java 服务。在“绿地”我的项目中间接应用 OpenTelemetry Java 库绝对简略 —— 您只需导入必要的库并间接应用跟踪 API 即可。然而,如果您也和咱们一样应用 Spring,则需做出其余决定。

Spring 已有一个分布式跟踪 API —— Spring Cloud Sleuth。它为底层分布式跟踪实现提供了一个 façade,并具备以下性能(如文档中所述):

  • 将跟踪和跨度 ID 增加到 Slf4J MDC,以便从日志聚合器中的给定跟踪或跨度中提取所有日志。
  • 检测 Spring 利用的通用进出点(servlet filter、rest template、scheduled actions、message channels、feign client)。
  • 如果 spring-cloud-sleuth-zipkin 可用,……,则通过 HTTP(生成并报告)兼容 Zipkin 格局的跟踪数据。默认状况下,它将这些数据发送到 localhost(端口 9411)上的 Zipkin 收集器服务。您可应用 spring.zipkin.baseUrl 配置服务的地位。

此外,该 API 还反对咱们将跟踪数据增加到 @Scheduled 注解的工作。

换句话说,咱们只应用 Spring Cloud Sleuth 便可从一开始就取得 HTTP 服务端点级的跟踪数据 —— 这堪称一大劣势。因为咱们的我的项目应用了 Spring,因而咱们决定全面拥抱该框架并利用其所提供的性能。但在应用 Maven 将这所有连贯在一起时,咱们发现了一些问题:

  • Spring Cloud Sleuth Autoconfigure 模块依然处于里程碑版本。
  • Spring Cloud Sleuth Autoconfigure 模块依赖于过期的内测版 opentelemetry-instrumentation-api。该库目前没有最新的非内测 1.x 版本。
  • 鉴于 Spring Cloud Sleuth 为里程碑版本编码其依赖项援用的形式,该我的项目必须从 Spring Snapshot 存储库中拉取父我的项目对象模型 (POM)spring-cloud-build。

咱们的 Maven 我的项目定义因而变得有些简单,因为咱们必须从 Spring 存储库和 Maven Central 中拉取 Maven(这充沛表明 Spring Cloud 很早便提供了 OpenTelemetry 反对)。尽管如此,咱们仍继续推动,创立了一个通用遥测模块,以应用 Spring Cloud Sleuth 和 OpenTelemetry 配置分布式跟踪,并开发了多种遥测相干的辅助性能和扩大性能。

在通用遥测模块中,咱们通过提供以下个性扩大了 Spring Cloud Sleuth 和 OpenTelemetry 库的跟踪性能:

  • 反对 Spring 的主动配置类,为我的项目设置跟踪和扩大性能,并加载其余跟踪资源属性。
  • NoOp 接口实现,这样咱们能够将 NoOp 实例注入所有 Spring Cloud Sleuth 接口,以便在启动时禁用跟踪。
  • 跟踪命名拦截器,用于标准跟踪名称。
  • 通过 slf4j 和 Spring Cloud Sleuth 跟踪输入谬误的谬误处理程序。
  • 跟踪属性的加强实现,它将附加信息编码到每个收回的跟踪中,包含 service 的版本、service 实例的 ID、机器 ID、pod 名称、容器 ID、容器名称和命名空间名称。
  • 跟踪语句查看器,它将跟踪 ID 注入 Hibernate 收回的 SQL 语句之前的正文中。显然,这项工作当初能够应用 SQLCommenter 实现,但咱们尚未进行迁徙。

此外,依靠于 Apache HTTP 客户端,咱们还实现了兼容 Spring 的 HTTP 客户端,因为咱们心愿在 service 之间进行 HTTP 调用时取得更多的指标和更高的可定制性。在此实现中,当调用隶属服务时,跟踪和跨度标识符将作为 HTTP 申请头传入,以蕴含在跟踪输入中。此外,这一实现提供了由 OpenTelemetry 聚合的 HTTP 连接池指标。

总而言之,应用 Spring Cloud Sleuth 和 OpenTelemetry 进行跟踪是一段艰巨的历程,但咱们置信所有都值得。心愿本我的项目以及本文可能为做出这一抉择的人们照亮前路。

NGINX 分布式跟踪

为了在申请的整个生命周期中获取连贯所有 service 的跟踪信息,咱们须要将 OpenTelemetry 集成到 NGINX 中。为此,咱们应用了 OpenTelemetry NGINX 模块(仍处于 beta 测试阶段)。思考到可能很难取得实用于所有 NGINX 版本的模块的工作二进制文件,因而咱们创立了一个容器镜像的 GitHub 代码仓库,其中蕴含不受反对的 NGINX 模块。咱们运行夜间构建,并通过易于从中导入的 Docker 镜像散发模块二进制文件。

咱们尚未将此流程整合到 MARA 我的项目的 NGINX Ingress Controller 的构建流程中,但打算尽快施行。

施行指标收集

实现 OpenTelemetry 跟踪集成后,接下来咱们将重点放在指标上。过后,咱们基于 Python 的利用没有现成指标,于是咱们决定临时推延增加相干指标。对于 Java 利用,原始的 Bank of Anthos 源代码(联合应用 Micrometer 与 Google Cloud 的 Stackdriver)为指标提供了反对。但咱们从 Bank of Sirius 中删除了该代码,起因是它不反对配置指标后端。尽管如此,指标钩子的存在阐明须要进行适当的指标集成。

为了制订一个实用的可配置解决方案,咱们首先钻研了 OpenTelemetry Java 库和 Micrometer 中的指标反对。咱们搜寻了这两种技术之间的比拟,许多搜寻后果都列举了 OpenTelemetry 在 JVM 中用作指标 API 的缺点,只管在撰写本文时 OpenTelemetry 指标仍处于内测阶段。Micrometer 是一个成熟的 JVM 指标门面层,相似于 slf4j,提供了一个通用 API 包装器,对接可配置的指标实现,而非本身指标实现。乏味的是,它是 Spring 的默认指标 API。

这时,咱们对以下理论状况进行了衡量:

  • OpenTelemetry Collector 能够应用简直任何起源的指标,包含 Prometheus、StatsD 和原生 OpenTelemetry Protocol (OTLP)
  • Micrometer 反对大量的指标后端,包含 Prometheus 和 StatsD
  • 面向 JVM 的 OpenTelemetry Metrics SDK 反对通过 OTLP 发送指标

通过几次试验后,咱们确定,最实用的办法是搭配应用 Micrometer Façade 和 Prometheus 反对实现,并配置 OpenTelemetry Collector 从而能够应用 Prometheus API 从利用中提取指标。许多文章都曾介绍过,OpenTelemetry 中短少指标类型可能会导致一些问题,但咱们的用例无需这些指标类型,因而能够在这点上退让。

咱们发现 OpenTelemetry Collector 乏味的一点是:即便咱们已将其配置为通过 OTLP 接管跟踪数据和通过 Prometheus API 接管指标,它依然能够配置为应用 OTLP 或任何其余反对协定将这两种类型的数据发送到内部数据接收器。这有助于咱们轻松地应用 LightStep 来试用咱们的利用。

总体而言,应用 Java 编写指标非常简单,因为咱们依照 Micrometer API 规范进行编写,后者有大量示例和教程可供参考。对于指标和跟踪而言,最艰难之处可能是恰好在面向 telemetry-common 指标的 pom.xml 文件中获取 Maven 依赖关系图。

施行 error 聚合

OpenTelemetry 我的项目自身的工作中不蕴含 error 聚合,而且它所提供的 error 标记实现也不像 Sentry 或 Honeybadger.io 等解决方案那样简洁。尽管如此,咱们还是决定在短期内应用 OpenTelemetry 进行 error 聚合,而非增加其余工具。借助 Jaeger 之类的工具,咱们能够搜寻 error=true,以找到所有带有 error 条件的跟踪。这至多可能让咱们理解常见问题之所在。将来,咱们可能会思考增加 Sentry 集成。

施行健康检查和运行时自检

在咱们利用的上下文中,通过健康检查,Kubernetes 可能晓得 service 是否衰弱或是否已实现启动阶段。如果 service 不衰弱,则可将 Kubernetes 配置为终止或重启实例。因为咱们发现文档资料的欠缺,咱们决定不在咱们的利用中应用 OpenTelemetry 健康检查。

而在 JVM 服务中,咱们应用了名为 Spring Boot Actuator 的 Spring 我的项目,它不仅提供健康检查端点,而且还提供运行时自检和堆转储端点。在 Python 服务中,咱们应用 Flask Management Endpoints 模块,该模块提供了 Spring Boot Actuator 性能的子集。目前,它只提供可定制的利用信息和健康检查。

Spring Boot Actuator 可接入 JVM 和 Spring,以提供自检、监控和健康检查端点。此外,它还提供了一个框架,用于将自定义信息增加到其端点上出现的默认数据中。端点可提供对缓存状态、运行时环境、数据库迁徙、健康检查、可定制利用信息、指标、周期作业、HTTP 会话状态和线程转储等因素的运行时自检。

Spring Boot Actuator 实现的健康检查端点采纳了模块化配置,因而 service 的健康状况将包含多个独自的查看(分成“存活”、“就绪”等类别)。此外,它还提供了显示所有查看模块的残缺健康检查。

信息端点在 JSON 文档中被定义为单个高级 JSON 对象和一系列分级密钥和值。通常,文档会指定 service 名称和版本、架构、主机名、操作系统信息、过程 ID、可执行文件名称以及无关主机的详细信息,例如机器 ID 或惟一 service ID。

施行堆转储和外围转储

您可能还记得上述“对照性能清单比拟工具性能”局部的表格,其中没有一个工具反对运行时自检或堆转储 / 外围转储。但作为咱们的底层框架,Spring 提供了对二者的反对 —— 只管将可观测性功能增加到利用中须要花一些功夫。如上一节所述,在运行时自检中,咱们联合应用了 Python 模块与 Spring Boot Actuator。

同样,在堆转储中,咱们应用了 Spring Boot Actuator 提供的线程转储端点来实现所需性能的子集。咱们无奈按需取得外围转储,也无奈以现实的细粒度级别取得 JVM 的堆转储,但咱们能够轻松地取得一些所需的性能。然而,Python 服务的外围转储将须要发展大量额定工作,这有待在前期进行。

总结

在重复尝试和比拟之后,咱们最终抉择应用以下技术来实现 MARA 的可观测性(在下文中,OTEL 代表 OpenTelemetry):

  • 日志记录(实用于所有容器)– Filebeat → Elasticsearch / Kibana
  • 分布式跟踪

    • Java – Spring Cloud Sleuth → 用于 OTEL 的 Spring Cloud Sleuth 导出器 → OTEL Collector → 可插式导出器,如 Jaeger、Lightstep、Splunk 等。
    • Python – OTEL Python 库 → OTEL Collector → 可插式存储
    • NGINX 和 NGINX Plus(尚不反对 NGINX Ingress Controller)– NGINX OTEL 模块 → OTEL Collector → 可插式导出器
  • 指标收集

    • Java – Micrometer(通过 Spring)→ Prometheus 导出器 → OTEL Collector
    • Python – 尚未实现
    • Python WSGI – GUnicorn StatsD → Prometheus(通过 StatsD/ServiceMonitor)
    • NGINX – Prometheus 端点 → Prometheus(通过 ServiceMonitor)
  • 谬误聚合 – OTEL 分布式跟踪 → 可插式导出器 → 导出器的搜寻性能,用于查找表明 error 的跟踪
  • 健康检查

    • Java – Spring Boot Actuator → Kubernetes
    • Python – Flask Management Endpoints 模块 → Kubernetes
  • 运行时自检

    • Java – Spring Boot Actuator
    • Python – Flask Management Endpoints 模块
  • 堆 / 外围存储

    • Java – Spring Boot Actuator 反对线程转储
    • Python – 尚不反对

此实现只是以后停顿状况,必将随着技术的倒退而演进。不久之后,咱们将通过宽泛的负载测试来运行利用。咱们心愿全面理解可观测性办法的不足之处并增加更多可观测性功能。

欢送亲自试用古代利用参考架构和示例利用 (Bank of Sirius)。如果您对帮忙咱们改良服务有任何想法,欢迎您在咱们的 GitHub 仓库中建言献策!


更多资源

想要更及时全面地获取 NGINX 相干的技术干货、互动问答、系列课程、流动资源?

请返回 NGINX 开源社区:

  • 官网:https://www.nginx.org.cn/
  • 微信公众号:https://mp.weixin.qq.com/s/XV…
  • 微信群:https://www.nginx.org.cn/stat…
  • B 站:https://space.bilibili.com/62…
正文完
 0