云原生下的可观测数据采集实践,看这一篇就够了!

云计算 云原生
“可观测性”最早起源于电气领域,指的是一个系统如果是可观测的,它的状态可以由外部输出来推断。

本文根据余韬老师在 GOPS 2022·上海站演讲整理而成,更多精彩,请关注高效运维公众号。

作者简介:
余韬,阿里巴巴技术专家。
10年工作经验,目前就职于阿里巴巴日志服务可观测平台团队,负责iLogtail开源,主要关注大数据分析、数据采集Agent、海量数据接入治理等领域。
曾负责百度统计、百度分析云产品的研发工作。

一、可观测数据类型与价值

1.1 IT系统的可观测性

“可观测性”最早起源于电气领域,指的是一个系统如果是可观测的,它的状态可以由外部输出来推断。比如一个汽车引擎,普通告警只能知道它的总体状态,如果加入仪表盘,比如水温、气压、转速,我们就可以大致定位它的故障方向,如果要解决这个问题,还是要依赖于组件内每个传感器的详细观测数据。

图片

在IT系统领域,可观测性却是近几年才越来越热的,我觉得和IT系统的发展有一定关系。最初软件系统相对简单,开发工作仅由几个人就能完成,每个人都对整个系统有完整了解。随着业务越来越复杂,涉及到的模块越来越多,很难有一个人了解系统全貌,此时就需要通过将它的可观测性数据展示出来以定位问题。

随着软件的复杂性增加,跨团队合作也会越来越多,团队间的沟通或排障也需要提高效率,防止推诿,因此需要拿数据说话,对可观测性数据的需求也越来越突出。软件运行环境也随着系统的基础组件云化趋势,变得越来越复杂。从单机到容器化,再到现在的云原生。越来越多的组件依赖第三方或者云上的云原生接口,使这个系统越来越像一个黑盒,不利于稳定性运行。

可观测性数据暴露就是希望将这些黑盒的东西白盒化。通常我们会把可观测性数据分为三类:Log,Traces,Metric。

1.2 IT系统可观测性场景与应用演进

这三类数据的定义是比较宽泛的,并不局限于运维领域。例如在线上运营领域,通过在APP上增加埋点数据,可以观测到用户使用中的卡点问题,进行针对性的用户体验改进;在线下运营领域,通过在商场使用 WIFI 或者监控设备来统计人流,可以解决新店选址或人流疏导难题。在交通领域,通过地图数据或者车联网数据,可以解决城市交通治理问题。

可以看到可观测性数据的应用价值和潜力非常巨大。我们回到大会的运维主题,现在很多企业上云,第一件事就是把应用部署到 K8s。下面我们简单介绍一下 K8s 下业务部署特点及数据采集需求。

二、K8s下业务部署特点及数据采集需求

2.1 自动装箱、弹性扩缩容

图片

K8s 具有自动装箱和弹性扩缩容的能力,部署应用只需要进行声明即可实现编排,大大解放了研发人员部署的精力和时间。同时,也因为应用部署效率提高,使得应用的版本迭代变得非常快,应用的混布也会变得频繁,单节点资源利用率大幅提高。为了帮助不同需求的应用进行不同形态的部署K8s提供了非常丰富的控制器并提供扩展能力。有些控制器提供了水平拓展、滚动更新能力,都是非常常见且实用的,这些功能也会使得系统中的容器创建和消亡比较快。

2.2 资源抽象、混合使用

第二个是资源抽象,K8s使得不同软件和硬件的节点都可以在一个集群中统一调度混合使用。为了更好地管理这些异构资源,我们通常将相似的资源节点分配到同一个节点池里,比如说有的节点池是linux系统的主机,有些是windows系统的主机,有些是配备 GPU 的主机。将这些节点统一由一个K8s Master管理时,能使机器资源利用最大化。

而节点本身除了可以是物理主机外,也可以是虚拟节点。比如说阿里云的 ECI 服务,其实就是把一个 pod 模拟成一个 Virtual Kubelet,使得它也能当做一个节点接受任务调度。当资源向其调度的时候,它的容器实际跑在云上的 Serverless 资源上,而不是物理的节点上。这种资源抽象能力,使得应用部署的灵活性大大提高。比如说混合云场景,有些客户会在线下自建一个机房,将稳定流量工作负载放在自建机房上,对于一些可能有流量突增的工作负载则放在具备弹性伸缩能力的云节点上。

2.3 存储抽象、灵活编排

K8s 对存储进行了比较好的抽象,可以满足应用不同的数据持久化需求。同时这样的抽象也使得容器再不用关心底层存储的细节,如磁盘从哪里挂载,只需要声明存储的类型、容量和IO需求。这使得部署在 K8s 的应用可以突破单机磁盘限制,一定程度上让所有应用都有了一定的存算分离能力。

三、K8s下可观测数据采集的常见挑战

K8s 给我们提供了一系列灵活和方便的部署能力的同时也给可观测性的数据采集带来一些挑战。下面以这四点进行讲解:

3.1 采集部署运维复杂

K8s 部署方便灵活,导致一个节点上的容器有可能非常多,我们怎么能够部署一个采集端采集这么多异构混布容器,怎么管理这么多采集对象。在 K8s 环境下容器部署变化非常快,比如说进行动态扩缩容的时候,很可能流量上来和下去的时候容器就很快创建和销毁了;而节点资源不足的时候,容器的被驱逐现象也是非常常见的,这就使得容器的生命周期可能非常短暂,需要采集端快速发现容器,同时避免数据采集丢失。

3.2 容器和节点运行环境多样

随着容器技术发展,容器运行的环境越来越多样化。以前都是用 Docker 进行容器运维,随着 K8s 崛起,逐渐地 Docker 运行时边缘化,目前最新的版本都是默认支持 Containerd 运行时,同时还有 CRI-O 等新兴的容器运行时。这些运行时的出现使采集节点上的容器数据不再只有一种格式,同时不同运行时的通信机制也可能不同,对应容器的内容存放路径也各不相同,这就使得采集器需要适配多样的运行时环境。

而容器运行的节点环境,包括物理机、VM、虚拟节点。对于虚拟节点的部署模式和物理机是不同的,特别是容器元信息和数据保存周期和物理机不同,这些都需要采集端和节点具备合理的配合方案,避免数据采集不到。

图片

3.3 单节点日志规模大

多种因素的作用下使得节点的日志规模变大。

  • 混合部署,单机部署比较倾向于部署一个单体结构应用。但在 K8s上,一个节点部署 50 个以上实例也非常常见。
  • 磁盘,传统节点使用的是本机硬盘(HDD/SSD),即使是SSD IO吞吐极限也只有约 500MB/s;K8s 节点(特别是云上节点),可以利用云盘,最高规格速率可以达到 1 GB/s。
  • 存储扩展能力,单机部署通常挂载 NAS,K8s 则支持多种存储种类的挂载,使用 PVC 实现灵活扩展,突破单机的读写速度和容量瓶颈。

在实际应用中也遇见过单节点产生巨量日志的用户,比如某打车APP,在一个节点上同时部署APP埋点定位数据/GPS定位数据/车辆实时后台数据接收等等,使得单节点采集200M/s以上的日志。

3.4 可观测数据异构

图片

K8s 节点本身就有多种媒介,例如有标准输出、PVC日志、容器日志。

同时在 Log/Metric/Traces 上会分别有不同数据输入源:在 Log 方面因为应用混部,同时要收集多种格式日志,像业务应用、MySQL binlog、Nginx Access Log 等数据。在 Metric 方面,通常需要采集 Prometheus 指标。在 Traces 方面,则又有 SkyWalking 等数据需要收集。如此复杂的采集需求使得单节点上采集的客户端需要同时支持采集多种类型的可观测数据才能达到使用要求。

这些情形都对端上采集构成了新的挑战。

四、对应问题处理方案与实践

我们从采集部署、环境、日志规模异构数据四方面来分享。

4.1 采集部署

部署模式

图片

通常端上的采集器在 K8s 有两种部署模式:一种是 DaemonSet,一种 Sidecar。DaemonSet 是在一个节点上部署一个采集器让它来采集节点上所有容器的日志,Sidecar 模式是在业务容器中同时起一个并行的采集容器并通过共享存储来采集业务容器的日志。

DaemonSet 模式有几个明显优点:耦合性比较低,每个应用不需要单独为它修改部署,直接可以进行采集;性价比高,只需要使用一份容器的资源就可以采到整个节点数据,和业务部署数量有解耦。

Sidecar 也有它的应用场景,比如日志量特别大的容器,采集需要和其他进行隔离,可以提供比较高的隔离性,同时它的灵活性也有一定好处。

配置分发

采集客户端部署之后,如何管理这些采集对象?涉及到配置分发。比较简单的做法是利用 K8s ConfigMap 分发配置,但它的缺点也比较明显:

  • ConfigMap 有大小限制
  • 分发不灵活,每组采集器需要单独配置

为了解决这些问题,可以用 ConfigServer 进行中心化配置下发,有图形界面支持,对运维人员管控比较方便;在各个 Agent 上有标识,可以灵活实现分组;也不受 ConfigMap 大小限制,可以支持大量的配置,单节点最多能够稳定支持 1000 个配置。

图片

这样的部署方式已经可以满足大规模的应用,但在某些场景下也有些不足:

比如用户在 CI/CD 流水线里部署应用的同时希望下发日志配置将日志采集上来,这时候用 ConfigServer 的 API 就需要定制一个组件来通信,不太方便。

配置自动化

我们也能够通过 CRD 的方式进行配置,这种方式能够获得 ConfigServer 的所有好处,同时能够更好地在自动化流水线中集成采集配置的下发,直接使用 CRD 这一标准 K8s资源对于这些流水线组件没有额外的开发代价

图片

如图所示,绿色的是 log-controller,它会实时监听采集的 CRD,CRD 是由 YAML 文件描述,如果 YAML 文件新增、删除或变更,这些事件会触发 log-controller 将配置同步到 ConfigServer 上,在容器中部署的 iLogtail 则从 ConfigServer 拉取采集配置,这样就实现了采集配置的声明式部署。

这种方法在某些特殊场景下也不是完全适用,比如说配置特别多,而且 K8s 的 APIServer 存储没有改造,对 APIServer 压力也是个需要考虑的。

Job场景支持

我们知道 K8s 场景下容器快速变化,比较典型的是 Job 控制器部署的容器。Job 的特点是跑完就结束了,所以增删 Pod 的频率很高。例如,有些 CI/CD 任务非常短,仅仅几秒,就容易丢数据。还例如,在无人车模拟场景里,会同时起几千个 Pod,瞬时新增容器并发量极大,这都是我们在采集时要考虑的因素。

实践中得出以下经验:

  1. 需要尽快发现容器,锁定文件句柄。
  2. 需要召回探测间隔期间退出的容器,有些容器可能因出错在探测间隔期间刚创建就退出了,这时候在下一次探测时我们不能忽略掉已经退出的容器,需要对退出容器也进行采集,保证数据完整。
  3. 对于一些关键日志,需要打在标准输出中。因为无论如何,容器销毁之后,容器内的文件都是无法访问的,但是标准输出不太一样,标准输出由 Kubelet 单独管理的,有保存的策略,通常不会立刻被删除,这样可以保证在容器快速变化的场景下数据不会丢失。

4.2 运行环境

容器运行时

接下来谈一下运行环境适配的问题,首先我们看一下常见的开源 Agent 对于不同部署模式下的采集支持情况。DaemonSet 下容器内文件采集只有 iLogtail 是支持的,iLogtail 是如何做到这一点的?

图片

我们看右边的图,iLogtail 发现容器的方式和其他开源软件不太一样,不是通过 API Server,它是直接和本地的容器运行时通信来获得容器的运行元信息。这些信息里会有 Overlay 的信息,这就是容器存放容器内文件的数据位置信息,还有 Mount point和对应挂载的路径,我们通过这些信息,通过 DaemonSet 可以直接采集到这些数据,不需要如共享卷的方式来采集数据。

但是为了实现这一点,需要对各种运行时进行适配。比如说 Docker 和 Containerd,它们通信的方式就不一样,我们要自动检测,它们的标准输出格式也不一样,它们对容器内文件存放的位置也不一样,这些都需要进行特定的适配。我们适配之后,用户用起来就会比较简单,只需要通过配置容器上的路径就能采集,不需要其他的额外工作。

Serverless 支持

刚才谈到过容器的运行节点环境比较多样,其中 Serverless 这种场景怎么支持?Serverless 没有物理节点,无法部署 DaemonSet,而 Sidecar 采集不了标准输出,都不是完美解决方案。更为复杂的情况是通过 Virtual Kubelet 实现 HPA 的场景,一部分容器已经运行在实体节点上并使用 DaemonSet 在采集日志,但一旦发生弹性扩缩容,容器创建到虚拟节点上,没有 DaemonSet 容器,但日志还要采集上来,怎么办?

图片

来看一下我们是怎么做的。Virtual Kubelet 虚拟节点收到新建容器请求,会通过 ECI 创建一个容器,在 ECI 中同时运行业务容器和 iLogtail 容器。iLogtail 容器用户不感知,这种模式称为 hidecar 模式。

ECI 中业务容器的信息,包括 Mount Point 和容器内文件在主机上的位置等,都通过静态文件发给 iLogtail,这种情况下 iLogtail 的工作模式和 DaemonSet 时非常像,它会通过静态文件发现容器,同时通过挂载在 iLogtail 容器中的 ECI 根目录去采集 ECI 节点上的业务容器日志。

通过这种方式,我们就可以比较平滑地让用户在没有感知情况下只考虑使用 DaemonSet 也能采集 ECI Serverless 的容器日志。为了避免丢失数据,ECI 会保证 iLogtail 收到退出信号晚于业务容器。

4.3 单节点日志规模大

单个采集端

图片

首先,iLogtail 的采集性能在各个开源采集器里是比较领先的,极简模式下可以达到440MB/s,然而默认部署通常会限制 iLogtail 资源,可能达不到极限速度,这时候如果产生日志延时,可以从几个方面判断:

  • 客户端。可以增加资源并且调大 iLogtail 并行处理和发送的参数。
  • 服务端。日志服务具备自动扩容能力,但对于一些特殊场景,如日志积压,自动扩容可能有一些延迟,这时候需要手动调整。
  • 网络链路。发送端和接受端带宽是否足够;中间存在代理则要检查 VIP、SLB 是否达到上限。如果涉及跨境传输,可能需要改进链路,比如启用全球加速或使用企业云网。

多个采集端

如果做了上面优化,仍然有客户端瓶颈导致的日志延时怎么办?可以用借用 Sidecar 部署思路(在一个节点上运行多个采集容器),把吞吐量较大的日志拆分出去,部署到多个容器,这样单节点采集能力不受到一个 DaemonSet 采集器上限限制。

4.4 异构数据的支持

插件框架

iLogtail 诞生之初主要是为了采集文件日志,随着整个服务上云,云上开放生态建设越来越多,需要接入的数据也越来越多。iLogtail 除了写入 SLS,也要支持写入第三方日志库。

为了应对大量输入输出需求,我们为 iLogtail 做了插件化的框架方便扩展,C++部分主要是处理文件、接受采集配置、发送数据等核心功能,插件负责接入一些别的输入源,例如 Binlog、Syslog 都是通过插件实现的;同时对接第三方数据源也是通过插件输入,在改造过程中也是把一些 iLogtail 处理能力进行了插件化,使得处理不局限于 Parse 一种,而是可以利用多个处理插件在端上进行灵活组合,实现端上轻量级处理流水线。

iLogtail可观测性数据生态支持

图片

目前 iLogtail 的生态在 Log 方面,一直是 iLogtail 的强项,除了支持容器数据采集外,还增加了 Windows Event、eBPF 等一些数据源。在 Metric 方面,有 Telegraf、Prometheus 数据源,OpenTelemetry 数据格式接入也在进行中。Trace 方面主要接入 Skywalking 的数据。输出方面除了支持阿里云的 SLS,也支持了 Kafka 的写入,并且支持格式转换可以被 CK、ES 等直接消费。对 CK 和 ES 的直接写入支持,目前也在规划中。

基于 eBPF 的无侵入采集

下面介绍 eBPF 的接入和可观测性采集办法。对于端上的 Trace 和 Metric 数据接入,通常来说需要用 SDK 在应用中进行埋点。虽然也有无埋点数据采集,如使用 Java Agent,但受限于特定语言。有没有办法将无侵入采集推广到其他语言?eBPF 技术提供了这样的可能性。

在 ilogtail 的实现中 eBPF 的采集原理分为用户态和内核态。内核态主要是通过 Kprobe 模块用一定规则去抓取系统调用的数据,对它进行解包并关联下发配置、进行过滤,把过滤后的解析数据发送到用户态。

用户态拿到的数据通常只有一些id信息,并不完整,ilogtail 使用一些插件来采集端上的 Process、容器等元信息,将这些信息与内核态采集的数据进行关联/聚合,得到完整的数据后再发送到后端。

图片

端上的情况大概是这样,完整的构建采集方案还需要结合服务端整体的能力。除了采集数据 DaemonSet 的 iLogtail,完整的方案还需要部署 Deployment 的 iLogtail 来拿到更详细的集群和容器信息,有了这个数据已经可以构建完整的主机监控。进一步我们可以从云上拿到云资产信息,再进行一次 join 以得到更加完整的 K8s 链路拓扑。

对于这些数据,可以对它进行聚合和处理从而得到一些指标数据,可以用来制作仪表盘实现图形化展示。如果结合黄金指标或者应用 SLS 智能巡检服务,则可以得到告警事件。如果对这些事件进行处理,我们就能得到完整的运维闭环。

图片

五、开源与未来展望

iLogtail 现在已经开源,大家可以共同参与讨论和开发,后续计划会分成四块共建:

  • 生态拓展:Kafka Flusher 已经支持到2.0,OTLP有1.0的初步支持,ClickHouse Flusher 和 GRPC Input/Output 都在规划中。
  • 框架增强:iLogtail 从日志发展过来,整个数据模型偏向于日志,对时序数据或 Trace 数据,都是通过私有协议和日志服务的 SLS 绑定。对于开源来说,更希望是开放的,有更好的架构支持。
  • eBPF:对于四层协议做了比较完整的解析,可以进行流量观察。对于七层协议,支持 Http/Redis/数据库类型协议,对于常见的 RPC 框架,有待社区共建。
  • 全局管控:配置方案的管控能力,日志服务有商业版的支持,我们也希望把这个能力带到开源上来。目前管控协议和管控服务已经有个初步的版本,后续希望把前端构建好,并且把如 K8s Operator 能力/iLogtail自身的可观测性数据也都能集成进来。

Github:https://github.com/alibaba/ilogtail

责任编辑:武晓燕 来源: 高效运维
相关推荐

2020-02-18 16:20:03

Redis ANSI C语言日志型

2022-06-20 09:01:23

Git插件项目

2022-05-19 08:28:19

索引数据库

2019-05-14 09:31:16

架构整洁软件编程范式

2018-05-22 08:24:50

PythonPyMongoMongoDB

2020-07-03 08:21:57

Java集合框架

2021-04-08 07:37:39

队列数据结构算法

2022-08-01 11:33:09

用户分析标签策略

2019-04-01 10:43:59

Linux问题故障

2020-10-21 14:12:02

Single Sign

2020-10-18 07:32:06

SD-WAN网络传统广域网

2022-07-06 12:07:06

Python函数式编程

2017-03-11 22:19:09

深度学习

2022-04-07 10:39:21

反射Java安全

2021-08-10 10:08:52

NAS网络附加存储存储

2017-11-13 15:16:56

GitHub代码仓库

2022-07-05 09:24:01

Pandas表格样式Python

2018-11-12 08:07:04

Nginx优化并发

2019-12-31 09:56:16

Linux 系统 数据

2019-04-02 10:51:29

浏览器缓存前端
点赞
收藏

51CTO技术栈公众号