eBay为何以及如何转向OpenTelemetry

eBay以OpenTelemetry为关键举措,以更好地与行业的可观测性标准保持一致。

header

简介

可观测性为任何组织提供了眼睛和耳朵。可观测性的一个主要好处在于通过有效地披露关键工作流程中的持续问题,以防止收入损失,这些问题可能会对客户体验产生影响。可观测性领域是一个不断变化的领域,OpenTelemetry世界的最新发展迫使我们重新思考我们的策略,以便转向使用它。eBay的可观测性平台Sherlock.io为开发人员和站点可靠性工程师(SRE)提供了一套强大的基于云原生的优势,以观察支持eBay生态系统的各种应用程序。Sherlock.io支持可观测性的三个支柱——指标、日志和跟踪。该平台的指标存储是Prometheus存储引擎的集群和分片实现。我们使用Metricbeat代理程序每分钟抓取大约150万个Prometheus端点,这些端点被摄入到指标存储中。这些端点连同记录规则导致每秒摄入大约4000万个样本。 摄入的样本导致在Prometheus上存储30亿个活跃系列。因此,eBay的可观测平台运营在一个非常庞大的规模上,这带来了新的挑战。

作为一个可观测性平台提供商,eBay是首家使用代理程序来抓取指标端点和尾部日志文件的公司之一。正如我们在先前的博客文章中讨论的那样,我们在接受信号进入平台方面严重依赖Elastic Beats。 Beats是一种轻量级的操作数据(例如指标和日志)传输器。从2016年到2020年的五年时间里,我们在所有的Kubernetes集群上都运行了Filebeat和Metricbeat作为DaemonSets。DaemonSets允许用户在Kubernetes集群的每个节点上部署一个给定的工作负载。然而,在一次内部黑客周期间进行的一次实验得出了一些令人惊讶的结论,并导致我们重新考虑了对DaemonSets的使用。在本博客文章中,我们将讨论我们遇到的一些问题,特别是对于指标抓取,以及我们如何发展我们自己的解决方案。我们还将详细讨论我们在许可方面如何与开放遥测(OpenTelemetry)进行对齐。

指标仪表化

eBay的指标仪表化大部分都是基于Prometheus端点进行标准化的。由于各种仪表化实践(例如,官方的Java、Go、Python等语言的Prometheus客户端、Micrometer、带有Prometheus导出器的OTel SDK和在请求时发出Prometheus端点的自定义代码),各种应用程序的端点被公开。eBay的平台工程组提供的框架内置了一个仪表化客户端,并公开了代表服务器端、客户端和数据库客户端指标的各种端点。根据应用程序的性质,可以公开需要进行抓取的Prometheus端点。应用程序的所有者还可以公开一个专门用于仪表化其业务关键绩效指标的端点。

自动发现

驱动eBay生态系统的大多数应用程序都在Tess上运行,Tess是eBay的内部Kubernetes提供程序。eBay运行着数百个Tess提供的Kubernetes集群,一个应用程序可以在任何数量和组合的集群上运行。应用程序的所有者可以选择在框架级仪表化的指标之外,将其应用程序的指标加入到监控中。我们的代理程序需要精确知道当前运行的Kubernetes Pod正在公开哪些端点。为了向代理程序提供这些信息,我们帮助丰富了Beats平台,执行了一个名为“基于提示的自动发现”的任务。自动发现是一个Beats构造,允许动态源(如Kubernetes API服务器)向代理程序传递信息,例如:

  • 需要抓取的端点是什么?
  • 抓取的端点是什么类型——Dropwizard、Prometheus、Foobar还是其他类型?
  • 应该多久进行一次抓取?
  • 是否还有其他需要代理程序知道的附加信息,比如SSL证书?

随着需求越来越复杂,我们与Beats开源社区合作,增强了自动发现的功能以满足我们的特定需求。我们做出的一些贡献包括:

  • 发现多个配置集:传统的基于注释的抓取配置非常有限,因为它只允许用户为抓取管理器提供简单的配置。鉴于每个端点可以具有不同的处理和抓取间隔等动态需求,我们增强了自动发现以接受多个配置集。
  • 从命名空间注释中发现目标:批注监测目标的推荐方法是在Pod规范中添加批注。然而,在那里添加它们意味着更改将导致Pod重启。如果更改是针对正在部署的应用程序上的在框架上进行仪表化的指标的话,这是不可取的。为了避免重启所有的Pod,我们添加了对自动发现的支持,使其还可以查看命名空间级别的注释。

这些功能使得Beats的自动发现成为识别部署在Kubernetes集群上的目标的最通用和功能丰富的发现机制之一。

DaemonSets中指标抓取的限制

我们第一次尝试在规模上运行Metricbeat时,涉及在每个Kubernetes集群上使用DaemonSets运行它。每个Pod被分配一个CPU和1GB的内存来处理该节点上公开的所有指标。当Metricbeat启动时,它请求API服务器提供该集群上所有命名空间以及运行在其所在节点上的Pod。根据此信息,对于每个Pod,它通过汇总Pod和Pod命名空间上的批注来创建配置。我们观察到的一些情况包括:

  • 资源碎片化:鉴于我们在每个节点集群上运行N个代理程序,如果单个代理程序流水线占用50MB的启动成本,那么我们实际上浪费了50*N MB的资源。在一个3000个节点的Kubernetes集群中,这将累积到150GB!
  • 当轮询大型端点时出现内存溢出问题:我们看到有些客户将端点暴露为一个端点中的150,000个条目。而一些巨大的端点如“kube-state-metrics”则具有三百万个条目,并且每次轮询时会生成600MB的数据。当这些使用案例落在一个节点上时,抓取变得不可靠。

以下图表显示了当Metricbeat、Filebeat和Auditbeat等任何Beats实例在DaemonSet模式下与Sherlock.io平台进行交互时的情况:

daemonset

转向集群本地抓取

在进行与当前项目无关的工作期间,我们采取了将Metricbeat作为整个集群中所有目标的单个实例运行的捷径。当我们观察到运行Metricbeat时的总CPU和内存使用情况时,数字简直令人震惊。在部署过程中,我们观察到以下情况:

  • Kubernetes节点数:2851个
  • CPU使用情况:29核
  • 内存使用情况:57GB
  • 摄入速率:每秒238K个样本
  • 每个节点监视的端点数:4个
  • 每个被监视节点的平均内存使用量:20MB
  • 每个被监视节点的平均CPU使用量:0.01核

一个在DaemonSet模式下监视类似数量端点的单个Metricbeat实例消耗约200MB(增加了10倍)和约0.6个核(增加了60倍)。在整个集群中,这将累积到570GB和约1700个CPU。通过转向集群本地实例,我们的成本大约降低了90%。

这迫使我们重新思考如何处理抓取。运行一个单个实例用于整个集群意味着当该实例进行升级或故障时,100%的抓取将在那个时间点中断。为了减轻故障,我们将Metricbeat部署为一个具有N个副本的有状态集。整个Pod列表根据Metricbeat实例的数量进行了N分片,并且每个实例监视其分配的分片:

xxHash(pod uid) % statefulset_size == instance number

每个实例对API服务器进行全面扫描,但只关注它自己需要监控的内容。这种模型对Metricbeat非常有效,因为它主要是抓取Prometheus端点,该活动可以在Tess节点外执行。一个拥有3000个节点的大型Kubernetes集群有30个以上的实例,这些实例拥有更多的CPU和内存,使其能够抓取明显更大的端点比在节点上的模式下能够实现的。如果一个Metricbeat实例重启,只有该实例监视的端点的抓取会中断,故障百分比减少为总实例数的1/N。

下面的部署模式可以通过以下方式进行可视化:

clusterlocal

解耦自动发现

尽管转向集群本地抓取使我们能够比使用DaemonSets时实现更高的规模,但该模式仍有改进的空间。在更大的集群中,具有更高的Pod密度时,出现了一系列新的问题。鉴于每个Metricbeat实例都必须扫描所有Pod并选择其需要监控的Pod,根据给定集群中有多少Pod,进行初始扫描可能需要很长时间。在新的Metricbeat Pod启动后,当它恢复运行抓取时,这在升级过程中变得极其有问题。在实例数量较多时,此技术还导致对API服务器施加了不必要的压力,因为Metricbeat请求的各种资源需要在API服务器上进行WATCH。

经过进一步的评估,我们决定将自动发现从代理程序中解耦,并将其转移到自己的控制循环中。该控制循环将:

  • 实现类似于Beats自动发现逻辑的解析器;
  • 发现可以执行抓取工作的所有代理程序;
  • 选择其中一个代理程序;
  • 并向所选代理程序传递要监视的目标的配置。

该控制循环将进行重要决策,例如在代理程序崩溃、代理程序过度分配和其他故障情况下调整工作负载。由于解析注释的逻辑已经与代理程序解耦,只要存在Beats暴露的特性与新的代理程序之间存在映射关系,就可以为任何代理程序生成配置。

OpenTelemetry的出现

2019年,Open Tracing和Open Census社区达成了一致,并推出了OpenTelemetry。OpenTelemetry倡议旨在提供供应商无关的API、SDK和工具,以便向任何可观测性后端接收、转换和发送数据。在我们使用Kubernetes并提供供应商无关的API来管理云上容器的选择下,投资这样的倡议似乎是自然而然的。2021年,我们开始尝试分布式跟踪,以找出它在我们的开发人员中可能有何用处。

当时,我们查看了OpenTelemetry Collector的代码库,发现了其中一些有潜力的功能,包括为指标、日志和跟踪定义类型,以及使用Prometheus抓取管理器从OpenMetrics端点收集指标。我们选择了OpenTelemetry Collector和OpenTelemetry SDK来实现分布式跟踪。接下来,我们需要解决的问题是如何将指标和日志收集迁移到OpenTelemetry Collector中。考虑到我们需要填补所有的功能差距、与一个新的开源社区建立关系并在没有停机的情况下交换庞大的指标收集基础架构,这不是一项容易的努力。2022年初,我们开始了将指标抓取迁移到OpenTelemetry Collector的艰巨任务。

迁移

鉴于我们将发现逻辑与代理程序解耦,实际迁移只意味着我们需要生成OpenTelemetry Collector理解的配置。这些配置需要在每次新的Pod启动时进行推送,并在Pod停止时进行清除。然而,OpenTelemetry Collector存在一个关键漏洞:它不能实现动态重新加载配置。OpenTelemetry Collector有一个定义了如何接收、处理和导出指标的“管道(pipelines)”的概念。为了实现管道的动态重新加载,我们开发了一个“filereloadreceiver”,它可以查看一个包含描述“部分管道(partial pipelines)”的文件的目录,并将其插入到Collector的整体管道中。需要进行指标抓取的每个Pod都有一个部分管道,由自动发现控制器生成并推送到Collector中。在此过程中,另一个复杂的工作是在Beats平台的每个功能与OpenTelemetry Collector之间创建一个映射表。例如,Beats中的字段会转换为OpenTelemetry上的属性处理器。有了这样的映射和filereloadreceiver,我们就能够生成OpenTelemetry Collector的新配置,如下所示。

config

如上所示,我们能够保持Pod/命名空间注释的终端用户合同不变,只是在幕后更换了代理程序。这极大地简化了部署新代理程序的实际任务。最后的障碍涉及弹性Beats、OpenTelemetry甚至Prometheus抓取管理器之间的语义不匹配。在我们最终替换了生产环境中的所有Metricbeat之前,我们花了数个月的时间来解决这些问题。我们在OpenTelemetry Collector项目中发现并协助修复的一些差异包括:

这些问题很难发现,有时只有在我们尝试将一个Kubernetes集群升级到使用OpenTelemetry Collector时才会浮现出来。一旦我们遇到这样的问题,回滚就是唯一的选择,我们不得不重新开始。其中一个部分解决方法是编写一个比较脚本,可以使用Metricbeat和OpenTelemetry Collector同时抓取一个端点,同时将它们传入指标存储,并比较指标名称和标签,以确保抓取是相符的。这大大提高了我们的信心,让我们能够继续前进。

有时继续前进意味着放弃对某些功能的支持。我们对Dropwizard指标的支持就是这样的一个例子,并且已经将用户迁移到其他指标。除了语义不同之外,我们还积极致力于添加我们认为对项目至关重要的功能,比如支持范例

经过数月的努力和社区的支持,我们很高兴地宣布,我们已经完全停用了Metricbeat,并将其替换为OpenTelemetry Collector。目前我们正在忙于对Filebeat进行同样的操作,而早期性能基准测试的结果非常令人兴奋。到目前为止,我们已经对该项目做出了10多个贡献,但这仅仅是与这个富有成果的合作的开始。

结论

在过去的五年中,我们在eBay遇到了几次需求激增,这迫使我们重新思考传统的智慧。我们从DaemonSets开始,发现在大规模时成本过高且不可靠。我们转向了集群本地模型,将代理程序的成本削减了约90%,但是在API服务器和代理程序自身上进行了过多的重复工作。我们解耦了自动发现,将其移入一个控制循环中执行调度,并将代理程序变成了可以接受抓取目标的无状态进程。鉴于OpenTelemetry的不断成熟,我们决定转向使用OpenTelemetry Collector来处理指标,并积极致力于在日志方面做同样的工作。我们将继续从大规模运行代理程序中学习,并根据需要进行转向。我们将继续与OpenTelemetry社区合作,因为它继续为可观测性生态系统的标准化铺平道路。现在我们使用OpenTelemetry,我们可以向开发人员提供业界认可的开放标准,将遥测发送到Sherlock.io。随着社区不断增长,为新特性(如性能分析)提供支持,我们将采纳这些特性,以造福我们的开发人员社区。

致谢

没有参与这些活动的众多思想领袖,许多这些优化/方向变更将不可能被实现:

我们非常感谢过去的Elastic Beats社区和现在的OpenTelemetry社区,他们支持我们并与我们合作,努力为我们的eBay开发人员社区建立世界一流的可观测性产品。

Elastic社区:

OpenTelemetry Collector社区:

本文的一个版本最初发布于 eBay Tech Blog。