跳到主要内容

APO v1.6.0 更新:告警工作流优化;服务列表排序;故障现场数据关联

· 阅读需 3 分钟

cover 图

本次 APO v1.6.0 版本更新带来了以下内容。注意本次更新存在破坏性变更,请参考官网的“安装手册”-“版本升级手册”进行升级。

更新日志

⚠️破坏性变更

  • 使用 PV 替换 HostPath 持久化方式,提高可维护性。如果您创建或修改过工作流,建议备份Postgres后再升级,否则工作流数据会重置。
  • 数据持久化变更:Grafana 和 apo-backend 数据库默认使用 PostgreSQL。请参考官网的“安装手册”-“版本升级手册”进行数据备份和升级。
  • Helm Charts 配置变量变更:工作流对应 baseurl 中的固定端口优化为可编辑端口,升级时请修改 values 文件中对应变量。

新增功能

  • 进一步优化“告警有效性分析”工作流和“告警简单根因分析”工作流,增加识别效果和准确率

  • 服务概览中的服务列表支持按照不同指标排序。现在可以点击表格标题按照该指标进行排序: 1 图

  • 支持根据TraceID从故障现场链路跳转至故障现场日志 2 图

  • 故障现场日志新增TraceID筛选条件 3 图

  • (企业版)新增线程级北极星指标和展示仪表盘 4 图

功能优化

  • 故障现场链路默认展示故障数据,新增既错又慢状态筛选 5 图

  • OneAgent 支持自动监控新建的namespace中的服务

  • 可配置告警有效性检查的执行频率和采样方式

  • 告警列表自动更新最新数据和状态

  • 优化工作流页面展示布局

缺陷修复

  • 修复 apo-backend 中的 polaris-analyzer 内存未及时清理的问题
  • 修复 OneAgent 注入Trace探针时可能覆盖JVM配置的问题
  • 修复链路追踪断链场景时,缺失下游服务的问题
  • 修复服务详情中仪表盘未匹配对应服务的问题

其他

  • apo-otel-collector 新增prometheus-remote-write receiver

6 图

APO v1.7.0 更新:用户角色权限管理;CPU火焰图数据;优化根因分析效果

· 阅读需 2 分钟

cover 图

本次 APO v1.7.0 版本更新带来了以下新功能和问题修复:

更新日志

新增功能

  • (企业版)告警分析:在大模型根因分析过程中展示匹配的真实数据,增强推理的可解释性 1 图

  • (企业版)告警分析:支持采集和展示火焰图数据 2 图

  • 新增基于角色的用户权限控制,现在可以通过给用户分配角色赋予不同的系统权限 3 图

功能优化

  • (企业版)告警分析:优化告警事件的分析速度和展示效果

  • 工作流:大幅提高告警有效性分析和告警根因分析工作流的分析速度,降低token消耗量;改进工作流执行页面的展示效果 4 图

  • 告警事件:新增告警降噪率,新增告警与解决事件总览,优化表格展示 5 图

  • 服务详情:优化页面布局和展示效果

缺陷修复

  • 修复服务详情页中异常项没有自动展开的问题
  • 修复离线部署情况下无法调用大模型问题
  • 修复部分前端组件在离线环境中无法使用的问题

6 图

APO v1.8.0 更新:全新亮色主题;告警详情页;优化告警智能分析

· 阅读需 3 分钟

cover 图

本次 APO v1.8.0 版本更新带来了以下新功能和问题修复:

更新日志

新增功能

  • 主题切换功能:新增暗黑模式与明亮模式切换,用户可根据个人偏好调整界面风格,提升使用体验。

1 图

  • 告警事件详情页:新增告警详情页面,展示告警从触发到恢复的状态变化过程。用户可通过告警通知一键跳转查看详情,快速理解告警上下文。

2 图

  • 告警根因分析能力增强:新增对以下类型告警的自动诊断功能:应用慢延时告警、应用错误告警和资源可用性告警,系统将分析告警原因并提供可执行的优化建议,帮助用户更高效地排查问题。

功能优化

  • apo-otel-collector 稳定性优化:优化队列配置,减少内存占用,防止因内存溢出导致 Collector 异常崩溃。
  • 容器运行时标签支持增强:apo-otel-collector 现已支持采集并补充基于 cri-o 容器运行时的 Pod 标签信息,提升数据维度的完整性与可观测性。

缺陷修复

  • 修复在接入中心添加数据接入时可能出现的报错问题,提升配置稳定性。
  • 修复用户登录认证过期后系统可能频繁报错的问题,改善用户登录体验。

其他

SkyWalking Java 探针支持升级:进一步完善对 SkyWalking 探针的兼容性,trace-sidecar模式支持 SkyWalking 6.1 及以上版本,trace-collector模式支持8.4及以上版本。


3 图

APO v1.9.0 更新:告警事件筛选;优化告警分析准确性;全量日志优化

· 阅读需 2 分钟

cover 图

更新日志

新增功能

  • 新增告警事件筛选功能,帮助用户更高效地定位关键信息,同时优化告警详情的描述内容,使信息表达更清晰

1 图

  • 支持在告警分析中关联数据库和中间件告警,进一步提高在大量告警场景下根因分析准确性

功能优化

  • 优化左侧菜单栏样式,使鼠标移动位置匹配菜单项,提升用户体验

2 图

  • 改进全量日志页面在小窗口中的显示效果,提升可读性与操作体验

3 图

  • 优化日志错误分析工作流中日志的展示格式,使排查更直观
  • 将主题切换和语言切换入口统一移动至右上角的“偏好设置”,界面更整洁

缺陷修复

  • 修复因有效性判断失败导致告警无法发送通知的问题
  • 修复使用“数据接入”方式安装时,无法获取故障链路数据的问题
  • 修复从传统服务器采集日志时,日志中缺失进程信息的问题
  • 修复应用在没有被监控的情况下,会出现数据无访问权限的问题

其他

  • 新增对阿里云 ARMS 4.x 版本探针的支持

4 图

APO 如何快速判断云环境网络质量是否有问题

· 阅读需 8 分钟
Autopilot Observability
APO 向导式可观测性平台

Cover 图

基于 eBPF 获取网络指标存在局限

eBPF 可以获取到网络 rtt 以及 srtt 等指标,这些指标确实能够反应网络质量,但是其实现是有局限性的,在当前绝大多数客户使用场景是不能反映网络质量的。

eBPF 在网络质量监控中的局限性主要体现在以下几个方面:

  1. TCP 建连时获取 srtt 指标: eBPF 在 BCC 中的实现是通过在 TCP 建连时获取内核维护的 srtt(smoothed round-trip time)指标。但是,TCP 连接建立完成后,内核并不会持续追踪每个网络包的传输时间。这就意味着在长连接场景中,srtt 指标并不能反映当前的网络质量变化。不仅仅是 BCC,我们自己开源的 Kindling 也有同样的局限,同时我们也对比了 datadog 等 eBPF 探针实现,发现都有这个问题。
  2. 长连接场景中的不足: 现代微服务架构中普遍使用长连接来减少连接建立和拆除的开销。然而,在这种场景下,内核并不会持续更新 srtt 指标,从而无法反映长连接期间的网络质量变化。
  3. 实验验证: 通过在 Tomcat 配置数据库连接池连接 MySQL,然后在两者之间注入网络延时故障的实验。在连接建立后,如果在任意一端注入延迟,BCC 的 srtt 指标将不会变化,因为内核不会追踪这些后续包的传输时间。

有没有其他方式判断网络质量

文章《孙英男-B 站大规模计算负载云原生化实践》是 B 站建立容器云过程的分享,他们在判断网络质量抖动的时候使用的 ping 来判断网络是否抖动。

使用 ping 来判断网络质量是大家常用的一个习惯,而对于 ping 的延时大家在实践中已经形成了一些认知,比如如果 ping 的延时超过 100ms,那么在线网络游戏估计玩不成了。

使用 Ping 来判断网络质量的优点

  1. 简单易用: ping 命令几乎可以在所有操作系统中使用,无需复杂的配置。
  2. 实时监控: 可以实时地检测网络延迟和丢包率。
  3. 网络连通性: 可以快速判断两个节点之间的连通性。
  4. 低开销: 相比其他方法,ping 对系统和网络资源的消耗较低。

使用 Ping 来判断网络质量局限性

  1. 误导性结果: 有时网络中的 ICMP 数据包优先级较低,可能导致延迟或丢包率看起来比实际情况更严重。
  2. ICMP 流量限制: 某些网络设备(如防火墙)可能会限制 ICMP 流量,导致 ping 测试结果不准确,甚至 ping 不通
  3. 大规模集群的限制: 高频 ping 造成的网络负载:在大规模集群环境中,对大量节点进行频繁 ping 操作,会产生大量 ICMP 流量,从而增加网络负载,影响正常业务流量。虽然一次 ping 的资源开销很小,但是集群规模大了之后,每个容器两两之间都进行 ping,这种消耗将是非常大的,大量的 ping 操作会消耗系统的 CPU 和内存资源,尤其是在需要同时监控许多节点的情况下。

如何才能低开销的完成网络质量的快速判断

虽然 eBPF 和 ping 包的方式都有一定局限性,但是 eBPF 的局限性受限于内核的实现,该局限没有办法突破的,而 ping 包的局限是可以突破的。

  • 误导性结果的突破:用户认知的突破,如果发现 ping 延时很严重了,那真实的网络流量更加严重,这点突破很容易。
  • ICMP 流量限制:防火墙的配置即可允许 ping 包的发生。
  • 大规模集群的限制:大规模集群中,如果两两相互都需要 ping 这是非常耗资源的做法,但是我们注意到实际场景中容器通过网络与其他容器交互的范围是有限制的,并不会和所有的容器都进行交互,这点是有优化空间的。

大规模集群适用低开销基于 ping 包的网络质量评估方案

开源项目 coroot 有一个非常好的思路,他们使用了一个叫做 pinger 的组件,该组件工作原理如下:

  • 基于 eBPF 获取容器之间的关系图,并不是获取 SRTT 等指标
  • 根据节点关系图来发送 ping 包,上游节点对下游节点进行 ping,这样能够极大的降低任意两两 pod 互相 ping 的开销

但是 coroot 的 eBPF 实现要求内核版本高于 4.14,国内还有很多操作系统停留在 centos7 系列的用户,他们是没有办法用 coroot 的实现。

我们在 coroot 的基础之上,针对国内的环境做了优化,主要优化如下:

  • 通过读取 proc 目录下来获取关系图,而不是通过 eBPF 获取关系图,这样就降低了对内核版本的依赖
  • 沿用了 coroot 原有 pinger 组件的思路,上游节点对下游节点进行 ping,极大降低任意两两 pod 互相 ping 的开销
  • 数据最后通过 exporter 暴露到 prometheus 或者 victoria metrics 中

最终效果图,展示 srcip 到 dstip 的 ping 值

图 1


题外话:我们不去修改 coroot ebpf 代码使其适配低版本内核主要是基于投入产出比,适配低版本内核需要调整代码量较大,我们通过 eBPF 采集的北极星因果指标是适配了低版本内核的。

APO 新发版支持Skywalking Agent接入

· 阅读需 4 分钟
Autopilot Observability
APO 向导式可观测性平台

Cover 图

自APO开源以来,社区成员询问APO是否支持Skywalking Agent,以避免已使用Skywalking的应用在测试发版过程中需要重新部署探针。APO利用OpenTelemetry生态,通过skywalkingreceiver实现Skywalking Trace到OTEL Trace的转换,为已经使用Skywalking的用户提供无缝体验。

有公司通过将Skywalking转换为OpenTelemetry+ClickHouse,成功降低了资源开销三分之一。APO如何实现这一功能?

使用ClickHouse存储Trace

APO迁移了Jaeger-remotestorage至Jaeger 1.58,使用Jaeger-clickhouse项目表结构存储Trace,并集成JaegerUI展示Trace。APO在设计上简化了Trace的细节,使得在Jaeger 2.0改版以更好支持Clickhouse时,APO的集成也变得简单。

OneAgentBuilder:构建适用已有环境的OneAgent

为了快速接入APO,特别是对于已经使用Skywalking和OpenTelemetry的用户,APO提供了OneAgentBuilder。

使用方法

  1. 下载OneAgentBuilder
  2. 将模板中的skywalking Agent探针或OpenTelemetry探针替换为已使用的版本
  3. 使用docker builder生成APO-OneAgent镜像,该镜像称之为定制化OneAgent镜像
  4. 按照安装文档安装APO-OneAgent,安装过程中替换OneAgent官方镜像为定制化的OneAgent

定制化OneAgent镜像使用

生成APO-OneAgent镜像后,您可以:

  • 将镜像导入至目标机器
  • 或者导入到Harbor中

然后,根据APO 官方文档安装 OneAgent,注意替换 OneAgent 官方镜像为您定制化 OneAagent。

结构示例

以下是OneAgentBuilder中模板的结构示例:

preload-builder
├── opentelemetry-java
│ ├── Dockerfile
│ ├── libapoinstrument.conf
│ └── opentelemetry
│ └── opentelemetry-javaagent.jar
└── skywalking-java
├── Dockerfile
├── libapoinstrument.conf
└── skywalking-agent
├── activations
├── bootstrap-plugins
├── config
├── expired-plugins
├── LICENSE
├── licenses
├── logs
├── NOTICE
├── optional-plugins
├── optional-reporter-plugins
├── plugins
└── skywalking-agent.jar

APO v0.2.0 更新记录

新增功能

  • APO 支持接入 SkyWalking Agent
  • 支持在安装 OneAgent 时替换默认的 Opentelemetry v2.5.0Agent,例如其他版本或SkyWalking 等
  • 新增查看服务的“更多下游依赖”拓扑,加快定位故障原因
  • 新增配置页面,支持修改数据保留周期
  • eBPF 探针适配更多内核版本,支持自动适配内核版本

功能优化

  • 优化安装体验,支持独立部署 APO 服务端,支持监控 Kubernetes 环境以及传统服务器中的应用
  • 优化告警规则页面展示效果
  • 优化 APO 接口查询效率,提高页面响应速度
  • 优化 Java 网关类型服务的监控数据准确度

缺陷修复

  • 修复部分场景下 ebpf-agent
  • 修复部分服务端点无法查询出实例信息的问
  • 修复日志/链路列表中不同实例包含了相同列表的问题
  • 修复日志/链路检索页选择器的问题

其他

  • APO页面汉化

APO 集成生态exporter一键完成指标采集

· 阅读需 8 分钟
Kindling-OriginX
故障根因推理引擎

Cover 图

Metrics 作为可观测性领域的三大支柱之一,Metrics数据采集显得尤为重要。传统的prometheus工具采集指标,需要指定路径抓取,当指标越来越多配置会显得复杂。同时prometheus只能采集指定的指标,当用户需要节点系统相关、中间件等指标还需要引进额外组件。久而久之采集指标配置难以维护。

APO 为了用户更好地一键采集各类指标,选择 Grafana-Alloy 作为APO的指标采集器,兼容OpenTelemtry生态,集成到 APO OneAgent之中,APO OneAgent负责采集所有指标,发送至APO-Server,存储至Victoria-Metrics, APO-front负责展示所有指标。当需要额外采集数据,只需配置OneAgent中Alloy数据采集源,无需更改其他组件,配置灵活,简单易懂。

图 1


APO 指标采集配置步骤

安装APO-Agent之时,已经安装自带安装了grafana-Alloy。APO启动之后 APO Server并对外提供服务,OneAgent抓取指标,然后发送到 Server,可以在APO Front中的Grafana查看数据。

当用户想要修改指标采集配置,修改 apo-grafana-alloy-config ConfigMap即可(虚机环境下修改apo配置文件config/grafana-alloy/config.alloy)

采集的配置步骤如下:

  1. 配置APO-server地址
  2. 配置apo-grafana-alloy-config文件
  3. grafana查询指标

APO server地址配置

首先需要配置APO Server地址,OneAgent采集指标后将数据发送到APO Server

    otelcol.receiver.prometheus "default" {
output {
metrics = [otelcol.exporter.otlp.default.input]
}
}

otelcol.exporter.otlp "default" {
client {
endpoint = "<host-ip>:<port>"
tls {
insecure = true
insecure_skip_verify = true
}
}
}

配置说明:其中 receiver 接收 prometheus 指标,转换成 otel 格式,然后exporter导出发送至APO-Server

APO缺采集配置

以kubernetes环境为例,通常一个集群可能存在如下指标需要采集

  • node metrics 节点机器系统相关指标 (磁盘,cpu等信息)
  • kubelet metrics 提供 node 和 Pod 的基本运行状态和资源使用情况
  • cadvisor metrics container相关的详细资源使用和性能指标数据

机器相关指标采集

    jsprometheus.exporter.unix "local_system" {
}

prometheus.scrape "scrape_metrics" {
targets = prometheus.exporter.unix.local_system.targets
forward_to = [otelcol.receiver.prometheus.default.receiver]
scrape_interval = "10s"
}

该组件会采集机器上的各种资源指标

kubernetes 指标采集

其中 discovery.kubernetes 组件负责获取kubernetes信息, APO 这里选择获取node相关的信息

之后采集 kubelet和 cadvisor相关的指标,由于是k8s集群,还需要配置 scheme, bearer_token_file等权限相关信息

discovery.kubernetes "nodes" {
role = "node"
}

prometheus.scrape "kubelet" {
targets = discovery.kubernetes.nodes.targets
scheme = "https"
scrape_interval = "60s"
bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token"
tls_config {
insecure_skip_verify = true
}
clustering {
enabled = true
}
forward_to = [otelcol.receiver.prometheus.default.receiver]
job_name = "integrations/kubernetes/kubelet"
}

prometheus.scrape "cadvisor" {
targets = discovery.kubernetes.nodes.targets
scheme = "https"
scrape_interval = "60s"
bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token"
tls_config {
insecure_skip_verify = true
}
clustering {
enabled = true
}
forward_to = [otelcol.receiver.prometheus.default.receiver]
job_name = "integrations/kubernetes/cadvisor"
metrics_path = "/metrics/cadvisor"
}

scrape指标采集

通常用户还会部署一些自定义的探针程序,用于自定义一些监控指标

只需指定 targets 下的 addres 用于指定采集URL, __metrics__path__自定义采集路径,默认为/metircs

prometheus.scrape "agent_metrics" {
targets = [
{
__address__ = "<scrape-path-1>:<port>",
},
{
__address__ = "<scrape-path-2>:<port>",
__metrics__path__ = "/metrics/agent"
},
{
__address__ = "<scrape-path-3>:<port>",
},
]
forward_to = [otelcol.receiver.prometheus.default.receiver]
scrape_interval = "10s"
}

如采集APO node-agent 指标

APO node-agent 用于采集上下游网络指标和进程启动时间指标,路径为 localhost:9500/metrics

prometheus.scrape "agent_metrics" {
targets = [
{
__address__ = "localhost:9408",
}
]
forward_to = [otelcol.receiver.prometheus.default.receiver]
scrape_interval = "10s"
}

一键采集中间件指标

除了采集基本指标外,用户使用APO还可以根据自己的需求额外配置其他指标采集。

如采集各类 中间件指标 (kafka, redis, mysql, elasticsearch等)

图 2

监控 MySQL

1.OneAgent 的 alloy 配置文件添加如下内容,然后重启 OneAgent

# 采集 mysql指标
prometheus.exporter.mysql "example" {
data_source_name = "username:password@(<mysql-url>:3306)/"
enable_collectors = ["heartbeat", "mysql.user"]
}

prometheus.scrape "mysql" {
targets = prometheus.exporter.mysql.example.targets
forward_to = [otelcol.receiver.prometheus.default.receiver]
}

2.APO Front 的 Grafana 中导入 MySQL 模版

图 3

3.验证是否有MySQL指标数据

图 4

监控 ElasticSearch

1.OneAgent 的 alloy 配置文件添加如下内容,然后重启 OneAgent

# 采集 elasticsearch指标
prometheus.exporter.elasticsearch "example" {
address = "http://<elasticsearch-url>:9200"
basic_auth {
username = USERNAME
password = PASSWORD
}
}

prometheus.scrape "elasticsearch" {
targets = prometheus.exporter.elasticsearch.example.targets
forward_to = [otelcol.receiver.prometheus.default.receiver]
}

2.APO Front 的 Grafana 中导入 ElasticSearch 模版

3.验证是否有ElasticSearch指标数据

图 5

监控 Redis

1.OneAgent 的 alloy 配置文件添加如下内容,重启OneAgent

# 采集 redis 指标
prometheus.exporter.redis "example" {
address = "<redis-url>:6379"
}

prometheus.scrape "redis" {
targets = prometheus.exporter.redis.example.targets
forward_to = [otelcol.receiver.prometheus.default.receiver]
}

2.APO Front 的 Grafana 导入 Redis 模版

3.验证是否有 Redis 指标数据

图 6

监控 Kafka

1.OneAgent 的 alloy 配置文件添加如下内容,重启OneAgent

# 采集 kafka 指标
prometheus.exporter.kafka "example" {
address = "<kafka-url>:9092"
}

prometheus.scrape "kafka" {
targets = prometheus.exporter.kafka.example.targets
forward_to = [otelcol.receiver.prometheus.default.receiver]
}

2.APO Front 的 Grafana 导入 Kafka 模版

3.验证是否有Kafka 指标数据

图 7


更多指标的采集可以参考Grafana-Alloy的官方文档或者咨询我们

Alloy已经支持如下中间件指标采集:

图8


参考资料

otel-collector

otlp-configgrpc

victora-metrics

Sending data via OpenTelemetry

alloy

discovery.kubernetes

otel.receiver.prometheus

prometheus

样例配置文件

logging {
level = "info"
format = "logfmt"
}


otelcol.receiver.prometheus "default" {
output {
metrics = [otelcol.processor.transform.default.input]
}
}

otelcol.processor.transform "default" {
error_mode = "ignore"
trace_statements {
context = "resource"
statements = [
`replace_all_patterns(attributes, "key", "service\\.instance\\.id", "service_instance_id")`,
`replace_all_patterns(attributes, "key", "service\\.name", "service_name")`,
`replace_all_patterns(attributes, "key", "net\\.host\\.name", "net_host_name")`,
]
}
output {
metrics = [otelcol.exporter.otlp.default.input]
}
}

otelcol.exporter.otlp "default" {
client {
endpoint = "<host-ip>:<port>"
tls {
insecure = true
insecure_skip_verify = true
}
}
}

prometheus.exporter.unix "local_system" {
}

prometheus.scrape "scrape_metrics" {
targets = prometheus.exporter.unix.local_system.targets
forward_to = [otelcol.receiver.prometheus.default.receiver]
scrape_interval = "10s"
}

prometheus.scrape "agent_metrics" {
targets = [
{
__address__ = "<scrape-path-1>",
},
{
__address__ = "<scrape-path-2>",
},
{
__address__ = "<scrape-path-3>",
},
]
forward_to = [otelcol.receiver.prometheus.default.receiver]
scrape_interval = "10s"
}

discovery.kubernetes "nodes" {
role = "node"
}

prometheus.scrape "kubelet" {
targets = discovery.kubernetes.nodes.targets
scheme = "https"
scrape_interval = "60s"
bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token"
tls_config {
insecure_skip_verify = true
}
clustering {
enabled = true
}
forward_to = [otelcol.receiver.prometheus.default.receiver]
job_name = "integrations/kubernetes/kubelet"
}

prometheus.scrape "cadvisor" {
targets = discovery.kubernetes.nodes.targets
scheme = "https"
scrape_interval = "60s"
bearer_token_file = "/var/run/secrets/kubernetes.io/serviceaccount/token"
tls_config {
insecure_skip_verify = true
}
clustering {
enabled = true
}
forward_to = [otelcol.receiver.prometheus.default.receiver]
job_name = "integrations/kubernetes/cadvisor"
metrics_path = "/metrics/cadvisor"
}


# 采集 mysql指标
prometheus.exporter.mysql "example" {
data_source_name = "username:password@(<mysql-url>:3306)/"
enable_collectors = ["heartbeat", "mysql.user"]
}

// Configure a prometheus.scrape component to send metrics to.
prometheus.scrape "mysql_metrics" {
targets = prometheus.exporter.mysql.example.targets
forward_to = [otelcol.receiver.prometheus.default.receiver]
}

# 采集 elasticsearch指标
prometheus.exporter.elasticsearch "example" {
address = "http://<elasticsearch-url>:9200"
basic_auth {
username = USERNAME
password = PASSWORD
}
}

prometheus.scrape "demo" {
targets = prometheus.exporter.elasticsearch.example.targets
forward_to = [otelcol.receiver.prometheus.default.receiver]
}

APO与SkyWalking、Signoz等产品的不同设计

· 阅读需 10 分钟
Autopilot Observability
APO 向导式可观测性平台

Cover 图

Skywalking作为国内用户量最大的APM产品,有着众多的优点。Signoz作为OpenTelemetry的发行版也有着一定的名气。我们为什么还要设计APO项目?谨代表APO团队探讨下团队之前的经验,一家之言,欢迎各位大佬一起探讨。

APO团队背景

APO团队最先着力的产品是一款商业化的根因推理引擎产品Originx。该产品目标就是对接Skywalking和OpenTelemetry的探针数据,在SLO违约的时候,快速从原始数据之上分析得到故障根因分析报告。

实现根因分析的前提——完备的关联数据

如果业务入口的延时升高或者错误率升高,对于下游依赖众多的服务调用而言,如何判断哪个接口是最可能的“凶犯”呢?我们认为应该要先对每个微服务接口的关联所有故障可能相关的数据。具体根因分析算法和规则就不在这篇文章讨论了。

接口关联数据故障场景
接口自身的告警信息,应用层、资源层告警告警分析
接口的影响业务入口黄金指标影响面分析
接口的下游依赖告警关联级联告警影响分析
接口的实例和节点的资源指标饱和度分析
接口的网络指标网络质量分析
接口的代码Exception,以及含有Exception的日志错误闭环
接口执行的北极星指标延时闭环
接口执行的日志故障佐证
接口执行的trace故障佐证
接口所依赖的容器环境关键事件环境影响

三者在产品设计思路不同

在APO团队看来,从设计思路来看Skywalking和Signoz是同类型的产品,都是以应用和Trace为核心呈现数据。但是APO团队认为可观测性平台不应该是以应用和Trace为核心呈现数据,而应该是以接口为维度呈现数据,因为以接口呈现数据,就可以关联上个章节提到的所有数据。

在应用中去关联上述的数据准确度会有大降低,比如一个应用提供两个接口,两个接口执行延时偏差较大,一旦以应用维度统计黄金指标数据(错误率、延时、吞吐量),就可能将故障隐藏其中。 从Trace出发呈现问题也是Skywalking和Signoz等产品的一个核心功能,在APO中这块通过集成Jaeger的方式来实现的。

最近有些朋友交流他们在自己实现可观测性平台的时候,也想以接口来关联数据,但是感觉计算量太大,资源消耗太大。APO能够实现该功能,主要基于回溯采样,分析的都是回溯采样中的数据,所以计算量是能承受的。

三者在数据采集上的不同

在具体实现上还有以下的不同:

Skywalking

  • log由Skywalking agent自采
  • metrics由Skywalking agent自采
  • Trace由Skywalking agent自采

Signoz

  • log由Signoz openTelemetry collector采集
  • merics由Signoz openTelemetry collector采集
  • Trace由OpenTelemetry agent采集

APO

  • log由ilogtail采集
  • metrics由Alloy采集
  • Trace由OpenTelemetry agent采集,同时也支持Skywalking agent采集
APOSkywalkingSignoz说明
logilogtailSkywalking agentSignoz openTelemetry collector●Skywalking agent采集日志性能开销可能不如单独的探针●OpenTelemetry Collecotor采集日志是一个不错的选择●ilogtail采集日志不仅仅适合容器环境,同时还可以支持虚拟机等其他环境
metricsAlloySkywalking agentSignoz openTelemetry collector●Skywalking agent采集的指标很多应用层指标,需要额外的指标采集工具覆盖主机、容器的指标 ●Signoz OpenTelemetry Collector能够采集主机指标,但是目前支持采集的种类的指标有限 ●Alloy是一款内置多种Prometheus exeporter的产品基于Alloy采集指标,非常容易扩展采集各种中间件等指标,满足更多用户的需求
TraceOpenTelemetry agent或者Skywalking agentSkywalking agentOpenTelemetry agent●由于Skywalking的协议缺少一些关键ID,比如ContainerID等信息,在容器环境,要关联各种指标和日志带来一些问题●OpenTelemetry的OLTP协议中含有ContainerID,关联起来各种数据更加方便

(建议此表格横屏阅读,内容展示更全面)

APO中需要关联eBPF数据和Trace的数据,Skywalking协议由于缺少ContainerID,导致关联出现以下的问题:

  • eBPF数据来源于主机,能够获取到主机层面的PID和ContainerID信息
  • 容器中Skywalking协议只有PID等信息,而容器环境的PID并不是主机层面的PID,导致两者关联起来非常不方便,需要额外做开发完成

三者在数据分析处理上的不同

APO和Signoz的数据分析处理都有各自的OTEL collector发行版,Skywalking主要基于OAP实现数据的分析与处理。

OpenTelemetry 的Collector非常开放,预设了各种插件

  • processor
  • receiver
  • Exporter

通过各种插件的组合能够很快组合成需要满足自己的数据分析处理流程,自动定义开发比较方便。

Skywalking的OAP相对而言比较封闭,没有这套插件体系导致自定义数据分析处理流程相对而言比较困难。所以现在很多公司的Skywalking的使用场景都需要自己构建flink完成数据的分析处理。

三者在数据存储的逻辑不同

Skywalking的Trace是完全插入存储之后,再计算RED值。

Signoz的RED指标在中心侧Collector计算完成,Trace是尾采样存储。

APO的RED指标在探针侧Collector计算完成。Trace是全量存储,处理不过来就丢弃,但是分析的是回溯采样中的逻辑Trace,回溯采样中的逻辑Trace优先级最高,保证存储。

APOSkywalkingSignoz说明
Trace处理时机探针侧Collector存储侧中心侧collector●Skywalking 对存储中间件的计算资源和存储资源要求高,计算都在存储侧计算●Signoz在中心侧collector计算RED指标并执行尾采样,当TPS流量很大之时,尾采样的限制导致其很难支持大流量的Trace计算●APO在探针边缘侧计算RED,计算量分散,能更好支持大流量的场景。采用回溯采样,优先保障回溯采样中的逻辑Trace存储,全量Trace如果超出缓存扔掉
存储中间件ClickHouse VictorioMetricsElasticSearchClickHouse●Skywalking 采用ElasticSearch 需要比较多的机器成本●Signoz 的指标是存储在ClickHouse中,一些现成的PQL查询指标语句用不了●APO的指标存储在VM中,兼容PQL语句,很多已经基于Prometheus的大屏可以直接使用,指标压缩比也更高

(建议此表格横屏阅读,内容展示更全面)

APO使用场景之:统一的指标采集展示

· 阅读需 11 分钟
Autopilot Observability
APO 向导式可观测性平台

Cover 图

可观测性领域中的指标一直都占有非常重要的地位。Prometheus生态目前已经是事实上的标准,但是实际用户在落地Prometheus的时候可能存在以下的问题:

  • 虽然生态中有各种成熟的Exporter,但是各种Exporter的安装配置相对而言比较繁琐,管理比较麻烦
  • 跨集群的指标数据汇聚相对而言比较麻烦,很多时候需要二次开发,没有简单配置即可工作的工具
  • Prometheus 原生数据存储在大数据量时不稳定,业界有着很好的类似VictorioMetrics方案,但是很多人还未尝试使用
  • 业界也存在过万好评的大屏,能够更好体现指标价值,对于很多用户而言可能并不了解

在APO中能够很好的解决以上的问题,已经将指标生态的各种产品进行很好的整合。

Grafana Alloy介绍

Alloy是Grafana 发布替代之前Grafana Agent的开源产品。

简单的官方介绍:

“Grafana Alloy 是一个开源的 OpenTelemetry Collector 发行版,内置 Prometheus 管道,并支持度量、日志、追踪和性能剖析。”

更为详细的官方介绍:

“Alloy 为 OTel、Prometheus、Pyroscope、Loki 以及许多其他指标、日志、追踪和分析工具提供了原生管道。此外,您可以使用 Alloy 管道执行各种任务,例如在 Loki 和 Mimir 中配置警报规则。Alloy 完全兼容 OTel Collector、Prometheus Agent 和 Promtail。您可以将 Alloy 作为这些解决方案的替代方案,或将其与多个收集器和代理结合成混合系统。您可以在 IT 基础设施的任何地方部署 Alloy,并将其与 Grafana LGTM 堆栈、Grafana Cloud 的遥测后端或任何其他供应商的兼容后端配对。Alloy 灵活多变,您可以轻松配置以满足本地部署、仅云部署或两者结合的需求。”

APO是如何使用Grafana Alloy

从Grafana Alloy的官方介绍中可以看出Alloy很强大,但APO并未使用Alloy所有的功能,主要使用以下两个功能:

  • 集成管理各种Prometheus的exporter的功能,有兴趣的朋友可以翻之前文章介绍了如何使用Alloy一键配置完成exporter的指标采集
  • 管道功能:跨云,跨集群,跨网段的指标采集之后要传输到统一可观测性后台展示

集成管理Prometheus各种exporter功能

通过简单配置即可完成exporter的配置、安装部署:比如通过以下的配置,即可实现ElasticSearch 的exporter的部署和采集

# 采集 elasticsearch指标
prometheus.exporter.elasticsearch "example" {
address = "http://<elasticsearch-url>:9200"
basic_auth {
username = USERNAME
password = PASSWORD
}
}

prometheus.scrape "mysql" {
targets = prometheus.exporter.elasticsearch.example.targets
forward_to = [otelcol.receiver.prometheus.default.receiver]
}

数据的管道功能

管道功能,数据可以通过OpenTelemetry的collector完成数据的跨集群、跨网络、跨云的传输。

数据流向:

Alloy(采集指标)-> Otel Collector (网络边界)->(网络边界) Otel Collector -> VictoriaMetric

管道功能核心的逻辑在于通过简单配置OTEL collector

  • recievier
  • exporter

配置示例:

边缘侧 Collector 配置(负责接收指标并发送到中心 Collector):

边缘侧 Collector 将通过 OTLP 接收指标数据,并通过 OTLP 发送到中心侧 Collector。

配置示例(边缘侧 Collector):

receivers:
otlp:
protocols:
grpc: # 支持 gRPC 和 HTTP 协议
http:

exporters:
otlp:
endpoint: "http://center-collector:4317" # 中心 Collector 的接收地址
metrics:
resource_to_telemetry_conversion:
enabled: true # 将资源级信息转换为 Telemetry 数据

service:
pipelines:
metrics:
receivers: [otlp] # 从应用接收 OTLP 格式的指标数据
exporters: [otlp] # 导出到中心 Collector

中心侧 Collector 配置(负责从边缘侧 Collector 接收指标并写入存储系统):

中心侧 Collector 将通过 OTLP 接收边缘侧 Collector 发来的指标数据,并将其导出到最终的存储后端。

配置示例(中心侧 Collector):

yaml


Copy code
receivers:
otlp:
protocols:
grpc:
http:

exporters:
prometheus:
endpoint: "http://prometheus:9090/metrics" # Prometheus 的接收地址
namespace: "otel_metrics"

service:
pipelines:
metrics:
receivers: [otlp] # 从边缘侧 Collector 接收 OTLP 格式的指标数据
exporters: [prometheus] # 导出到 Prometheus

配置说明:

1.边缘侧 Collector:

  • receivers: 使用 otlp 接收应用程序发送的指标数据,支持 gRPC 和 HTTP 协议。
  • exporters: 使用 otlp 导出数据,endpoint 是中心侧 Collector 的接收地址。

2.中心侧 Collector:

  • receivers: 使用 otlp 从边缘侧 Collector 接收指标数据。
  • xporters: 使用 prometheus 将数据导出到VictorioMetrics。

APO如何看待Alloy其它功能

  • Alloy集成Loki而来的日志能力,在实际使用日志场景中可能不够用,实际日志都要完成非结构化转化成结构化这一步骤,但是Loki在此方向并不擅长
  • Pyroscope等Continues Profiling的数据目前在OpenTelemetry生态并未完全成熟,即便能够使用Alloy完成数据的采集,但是如何传输,存储,展示都成为问题,还有很多问题等着解决

Alloy的exporter集成能力是经过grafana agent项目能力沉淀而来,坑相对而言比较少。APO在实际使用Alloy也踩了些坑,通过不断调整配置,相信未来也会越来越稳定。

VictorioMetrics的使用

VM已经成为很多公司存储指标的首选,主要是相比prometheus其它生态产品而言

架构简洁性:

  • VictoriaMetrics: VictoriaMetrics 集群版的架构较为简单,支持单一二进制文件启动,减少了复杂的集群管理工作。它既可以用作单机部署,也可以扩展为分布式集群,支持水平扩展,且维护相对简单。

  • Thanos/Cortex: 这两者的架构相对复杂,通常需要多个组件(如 Querier、Store Gateway、Compactor 等)协同工作,且往往涉及到对象存储(如 S3、GCS 等)来进行长期存储。因此,它们的配置、部署和维护难度较高,适合需要长时间数据保留的大规模集群。

高效存储和压缩:

  • VictoriaMetrics: 其高效的数据压缩和存储引擎使其在处理大量数据时更加节省存储空间。它采用自定义的存储格式和时间序列压缩算法,特别擅长处理大规模高频率的时间序列数据。

  • Thanos/Cortex: 这两者依赖于 Prometheus 的存储块和外部对象存储来处理长时间的数据保留,并通过外部系统进行压缩。虽然通过对象存储解决了长期存储问题,但这种方式带来的延迟和复杂性较高,尤其是在查询大量历史数据时,可能会受到网络和存储系统性能的影响。

性能和查询速度:

  • VictoriaMetrics: 由于其优化的存储引擎和索引机制,VictoriaMetrics 在长时间范围的查询场景中通常表现更好。它可以处理大规模数据的高性能写入和快速查询,即使在单节点场景下也能保持良好的表现。

  • Thanos/Cortex: 这两者的查询性能取决于集群的规模和外部存储的读写性能,尤其在跨多个 Prometheus 实例进行查询时,由于依赖对象存储,查询速度相对较慢。此外,Cortex 使用分区和多租户设计,虽然增强了灵活性,但在某些场景下也会引入查询延迟。

完全兼容 Prometheus API:

VictoriaMetrics 完全兼容 Prometheus 的查询语言(PromQL)和数据采集接口,能够无缝替代 Prometheus,且支持从 Prometheus、Thanos、InfluxDB 等系统中直接导入数据,迁移成本低。

指标的统一展示

当各种prometheus exporter的数据存储在VictorioMetrics之中,可以利用生态已有的Grafana大屏直接展示,感谢StarsLiao的贡献,在其贡献的大屏中,有很多已经成为众多公司的选择,很多大屏有着上万的好评。APO中很多大屏都引入了大佬的作品。

1 图

2 图


总结

APO利用Prometheus和OpenTelemetry的成熟生态成果,快速完成指标的采集、传输和统一展示。虽然这些能力并不是APO的核心价值,但也是可观测性平台的核心支柱能力,也欢迎用户先将APO当成指标的采集、传输和统一展示的工具,当系统越来越复杂,需要集成Trace、日志等能力之时,用户可以不用迁移平台。

APO介绍:

国内开源首个 OpenTelemetry 结合 eBPF 的向导式可观测性产品

apo.kindlingx.com

https://github.com/CloudDetail/apo

APO全量日志对接logstash和fluent日志采集生态

· 阅读需 7 分钟

Cover 图

APO 日志介绍

采集流程图

1 图

APO 使用 ilogtail 作为日志采集组件并改造支持额外功能, 在 vector 中进行日志结构化处理。

APO 日志功能

  • 日志指标

     统计日志数并生成日志数指标。出现错误日志时,计算日志错误指标

  • 故障现场日志

     应用程序出现慢或者错误trace时,将这段时间内的日志收集并写入clickhouse中。使用 k8s 信息或 pid 信息关联故障链路和故障现场日志

  • 全量日志

     1.APO日志界面中提供了为不同应用配置不同的日志解析规则,vector 根据解析规则将日志结构化,解析规则中提取的日志字段会单独成列加快查询

     2.日志库支持全文检索和查看日志上下文

APO 日志中使用logstash或fluent

用户如果已经使用 logstash 或者 fluent 生态的日志采集组件,可直接与APO日志进行对接。但需要注意的是,使用对接日志采集组件可能会导致某些信息的缺失或功能无法使用。

APO 日志仅全量日志功能可用

APO 日志不可用功能

  • 故障现场日志:APO 使用改造后的 ilogtail 添加 K8S 信息或 PID 信息,使用 logstash 或 fluent 替换 ilogtail 会导致在 K8S 和虚机环境中均无法关联链路和日志信息,导致功能缺失
  • 日志指标:APO 使用 ilogtail 统计日志指标,使用 logstash 或 fluent 替换 ilogtail 导致该功能缺失

logstash 或 fluent 需填充 K8S 相关信息

确保在 Kubernetes 环境中部署日志采集组件,同时日志需要填充以下标签信息,同时这些标签信息需要适当的重命名。重命名具体实现可以参考后续提供的 vector 配置示例。

  • container.name -> 容器名
  • container_id -> 容器ID
  • k8s.namespace.name -> Kubernetes 命名空间
  • k8s.pod.name -> Pod 名称
  • host.ip -> 节点 IP
  • host.name -> 节点名称
  • source -> 文件路径
  • content -> 日志内容
  • timestamp -> 日志采集时间

APO 接入日志采集组件示例

当用户在 K8S环境中使用 Logstash 生态(如 filebeat, logstash)或 Fluent 生态(如 fluentd, fluent-bit),可参考如下示例接入 APO 日志。

Logstash 生态示例 - 使用 Filebeat

1.设置 NODE_IPNODE_NAME 环境变量

    env:
- name: NODE_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
- name: NODE_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.hostIP

2.配置 Filebeat 

日志采集组件如果和 APO Server 不在同一集群,output.logstash 中的 hosts URL 设置为 Server 所在节点IP,Port 改为 30310

    filebeat.inputs:
- type: filestream
id: kubernetes-container-logs
fields:
host.ip: ${NODE_IP}
fields_under_root: true
paths:
- /var/log/containers/*.log
parsers:
- container: ~
prospector:
scanner:
fingerprint.enabled: true
symlinks: true
file_identity.fingerprint: ~

processors:
- add_kubernetes_metadata:
host: ${NODE_NAME}
matchers:
- logs_path:
logs_path: "/var/log/containers/"


output.logstash:
hosts: ["apo-vector-svc.apo:4310"]

3.更新 apo-vector 的 ConfigMap

    # 替换sources内容
sources:
logstash_log:
type: logstash
address: 0.0.0.0:4310


# 替换 transforms 的 flatten_logs 内容
transforms:
flatten_logs:
type: remap
inputs:
- logstash_log
source: |
."host.name" = .host.name
."host.ip" = .host.ip
.content = .message
."_source_" = .stream
."_container_id_" = .container.id
."k8s.namespace.name" = .kubernetes.namespace
."k8s.pod.name" = .kubernetes.pod.name
."container.name" = .kubernetes.container.name
del(.agent)
del(.log)
del(.message)
del(.kubernetes)
del(.container)
del(.input)
del(.orchestrator)
del(.ecs)
del(.host)
del(.@metadata)
del(.stream)

# 调试日志信息,日志采集对接成功后可移除
sinks:
to_print:
type: console
inputs:
- flatten_logs
encoding:
codec: json
json:
pretty: true

Fluent 生态示例 - 使用 Fluent Bit

1.设置 NODE_IPNODE_NAME 环境变量

    env:
- name: NODE_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
- name: NODE_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.hostIP

2.配置 Fluent Bit 的解析、 输入、过滤器和输出配置。日志采集组件如果和 APO Server 不在同一集群,OUTPUT 中的 Host 设置为 Server 所在节点IP,Port 改为 30310

    [Input]
Name tail
Path /var/log/containers/*.log
Refresh_Interval 10
Skip_Long_Lines true
Parser cri
Tag kube.*

[Filter]
Name kubernetes
Match kube.*
Kube_URL https://kubernetes.default.svc:443
Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token
Labels false
Annotations false

[FILTER]
Name modify
Match *
Add host_ip ${NODE_IP}

[OUTPUT]
Name forward
Match *
Host apo-vector-svc.apo
Port 4310

3.修改 apo-vector 的 ConfigMap 以匹配 Fluent Bit 输出格式

    # 替换sources内容
sources:
fluent_log:
type: fluent
address: 0.0.0.0:4310

# 替换 transforms 的 flatten_logs 内容
transforms:
flatten_logs:
type: remap
inputs:
- fluent_log
source: |
."host.name" = .kubernetes.host
."host.ip" = .host_ip
."_source_" = .stream
.content = .message
."_container_id_" = .kubernetes.docker_id
."k8s.namespace.name" = .kubernetes.namespace_name
."k8s.pod.name" = .kubernetes.pod_name
."container.name" = .kubernetes.container_name
del(.kubernetes)
del(.stream)
del(.message)
del(.host)
del(.host_ip)

# 调试日志信息,日志采集对接成功后可移除
sinks:
to_print:
type: console
inputs:
- flatten_logs
encoding:
codec: json
json:
pretty: true

APO 日志对接问题排查

配置修改后,如果 APO 日志界面仍未出现日志,需要进行排查

问题1 vector中有日志事件,但APO 界面无日志

需要通过vector日志查看日志事件格式是否正确

vector 配置中添加调试日志信息配置。观察vector日志中事件,通常正确的日志信息包含如下信息。

    {
"_container_id_": "852a7484f030",
"_source_": "stdout",
"container.name": "java-demo-1",
"content": "{\"level\":\"ERROR\",\"method\":\"org.apache.juli.logging.DirectJDKLog.log\",\"msg\":\"Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.client.ResourceAccessException: I/O error on GET request for \\\"http://localhost:8082/api/jpa-demo/sleep\\\": Read timed out; nested exception is java.net.SocketTimeoutException: Read timed out] with root cause\",\"thread\":\"http-nio-8081-exec-2\"}",
"host.ip": "192.168.1.69",
"host.name": "node-69",
"k8s.namespace.name": "default",
"k8s.pod.name": "apo-java-demo-b7994cc54-ss58f",
"timestamp": "2024-09-25T07:46:38.146950792Z"
}

如果发现信息缺失,请参考填充 K8S 相关信息确保所有信息填充

问题2 vector日志中未收到任何日志事件

需要排查一下对接采集组件是否可以正常写入vector

请查看filebeat,fluent-bit等采集组件等日志信息


APO介绍:

国内开源首个 OpenTelemetry 结合 eBPF 的向导式可观测性产品

apo.kindlingx.com

https://github.com/CloudDetail/apo