跳到主要内容

告别ELK,APO提供基于ClickHouse开箱即用的高效日志方案——APO 0.6.0发布

· 阅读需 17 分钟

Cover 图

ELK一直是日志领域的主流产品,但是ElasticSearch的成本很高,查询效果随着数据量的增加越来越慢。业界已经有很多公司,比如滴滴、B站、Uber、Cloudflare都已经使用ClickHose作为ElasticSearch的替代品,都取得了不错的效果,实现了降本增效,费用节约大多在50%以上。但是目前使用ClickHose作为日志方案,存在以下问题。

  • 主流的Vector+ClickHose并未实现开箱即用,有许多的管理配置工作
  • 绝大多数方案不支持近似全文检索的功能(该功能很重要)
  • 使用双数组或者Map的表结构查询效率不高
  • ClickVisual是最接近的开箱即用的日志方案,也存在以下问题:

○强依赖Kafka,对于某些中小用户而言方案不够灵活,不友好

○未引入Vector,原生的ClickHose Kafka引擎在大流量情况下可能导致ClickHose内存爆掉(感谢社区大佬 十四反馈)

主流的Vector+ClickHouse方案并未实现开箱即用

目前业界很多公司都是基于Vector+ClickHouse的方案来实现日志的采集和存储,该方案需要管理维护的工作量相对而言比较高,适用于动手能力强的公司。

维护工作:为每种日志手动维护一张表

每个公司的部门团队可能日志规范都不完全一致,如果需要对日志内容进行快速搜索定位故障,就需要提前想好ClickHouse的表结构,然后调整Vector的配置文件,最终实现Vector根据不同日志格式,parse成不同的日志表字段,写入不同的日志表。

比如每种日志都得建立以下类似的表结构,才能完成日志按照ip、url等字段的索引实现快速搜索。但是另外一个部门的日志也许就不需要IP和url字段,那么该部门得重新设计表结构。

CREATE TABLE log
(
`ip` String,
`time` Datetime,
`url` String,
`status` UInt8,
`size` UInt32,
`agent` String
)
ENGINE = MergeTree
ORDER BY date(time)

使用双数组或者Map的表结构查询效率不高

为了能够规避这些维护工作,所以很多公司对固定日志表结构进行了调整,常见的有两种方案,一种是双数组方案,另外一种就是Map方案。

Uber和Signoz的日志实现方案都是基于双数组

其日志表结构类似于下面这种

CREATE TABLE <table_name>
(
//Common metadata fields.
_namespace String,
_timestamp Int64,
hostname String,
zone String,
...

//Raw log event.
_source String,

//Type-specific field names and field values.
string.names Array(String),
string.values Array(String),
number.names Array(String),
number.values Array(Float64),
bool.names Array(String),
bool.values Array(UInt8),

//Materialized fields
bar.String, String
foo.Number Float64,
...
)
...

滴滴、B站等日志实现是基于Map结构

引入Map结构能够动态实现日志关键字段搜索

CREATE TABLE ck_bamai_stream.cn_bmauto_local
(
`logTime` Int64 DEFAULT 0, --Log打印的时间
`logTimeHour` DateTime MATERIALIZED toStartOfHour(toDateTime(logTime / 1000)),--将Log
`odinLeaf` String DEFAULT '',
`uri` LowCardinality(String) DEFAULT '',
`traceid` string DEFAULT '',
`cspanid` String DEFAULT '',
`dltag` String DEFAULT '',
`spanid` String DEFAULT '',
`message` String DEFAULT '',
`otherColumn` Map<String,String>
`_sys_insert_time` DateTime MATERIALIZED now()
)
ENGINE =MergeTree
PARTITION BY toYYYYMMDD(logTimeHour)
ORDER BY(logTimeHour,odinLeaf,uri,traceid)
TTL _sys_insert_time +toIntervalDay(7),_sys_insert_time + toIntervalDay(3)To VOLUME 'hdfs
SETTINGS index_granularity = 8192,min_bytes_for_wide_part=31457280
Create Table <log_app_name> ON CLUSTER ...
{
_timestamp Datetime64(3),
`log,level` String CODC(ZSTD(1)),
`log.msg` String CODC(ZSTD(1)),
`log.trace_id` String CODC(ZSTD(1)),
...
string_map MapV2(String, Nullable(String))
CODEC(ZSTD(1))
number_map MapV2(String, Nullable(Float64))
CODEC(ZSTD(1))
bool_map MapV2(String, Nullable(UInt8))
}
ENGIN = ReplicatedMergeTree(...)
PARTITION BY toYYYYMMDD(_timestamp)
ORDER BY timestamp
TTL toDateTime(timestamp) + toIntervalDay(...),
toDateTime(timestamp) + toIntervalDay(...) TO VOLUME `cold_volume`

Map的动态字段搜索效率低

https://clickhouse.ac.cn/docs/knowledgebase/improve-map-performance

根据社区反馈,map底层实现为线性数组,map查询效率通常低于列查询3~10倍,特别是日志量规模越大,map查询效率越低。

同时支持Map类型的最低clickhosue版本为21.11

  • 列式存储优势: ClickHouse 的核心优势在于它是列式存储数据库,这意味着当执行查询时,只需要读取查询中涉及的列,而不必加载不相关的列。列式存储还能够通过数据类型特定的压缩技术显著减少 IO 操作,从而加快查询速度

  • 基于 Map 的查询: Map 是一种键值对数据结构,在查询时需要额外的开销来解析嵌套结构,并且无法像列式存储那样直接跳过不相关的数据。虽然 ClickHouse 对 Map 数据类型有一些优化,但它在处理复杂结构时往往会比简单的列查询慢

双数组的搜索效率也不高

虽然 ClickHouse 对Array有一定的优化,但双数组结构仍然比单纯的列查询开销大。

影响性能的因素:

  • 多级解析开销:查询双数组时,需要进行多层嵌套解析。例如,访问数组中的子数组意味着需要遍历父数组,然后进一步解析子数组的结构,这比单纯读取一个列复杂得多
  • 随机存取:双数组的访问模式往往比简单的列查询更加随机化。访问数组中的元素可能导致更多的跳转,影响缓存命中率,从而降低性能
  • 内存使用和数据存储:嵌套数组会使得 ClickHouse 的数据存储和内存管理更加复杂,因为数组中的数据长度不固定,导致压缩效果比单纯列差,数据块的大小也更加难以优化

性能上的差距取决于具体的查询模式和数据结构:

  • 在简单查询场景(例如,读取一个基本的列数据),单纯的列查询会比双数组快得多,特别是在处理大规模数据时。性能差距可能达到 数倍甚至十倍 以上,尤其是当查询不涉及嵌套结构时。
  • 在复杂查询场景(例如,查询涉及嵌套数组、需要频繁地进行数组拆解和操作),双数组的查询性能通常明显低于单纯的列查询。查询双数组的额外解析和处理开销,会使查询时间增加。根据不同的嵌套深度和数据量,性能可能下降 数倍。

ClickHouse的官方文档中日志方案也由于引入了Map效率不高

ClickHouse官方blog :

https://ClickHouse.com/blog/storing-log-data-in-ClickHouse-fluent-bit-vector-open-telemetry

提到有以下几种表结构:

OTEL的日志字段表

CREATE TABLE otel.otel_logs
(
`Timestamp` DateTime64(9) CODEC(Delta(8), ZSTD(1)),
`TraceId` String CODEC(ZSTD(1)),
`SpanId` String CODEC(ZSTD(1)),
`TraceFlags` UInt32 CODEC(ZSTD(1)),
`SeverityText` LowCardinality(String) CODEC(ZSTD(1)),
`SeverityNumber` Int32 CODEC(ZSTD(1)),
`ServiceName` LowCardinality(String) CODEC(ZSTD(1)),
`Body` String CODEC(ZSTD(1)),
`ResourceAttributes` Map(LowCardinality(String), String) CODEC(ZSTD(1)),
`LogAttributes` Map(LowCardinality(String), String) CODEC(ZSTD(1)),
//数据索引
INDEX idx_trace_id TraceId TYPE bloom_filter(0.001) GRANULARITY 1,
INDEX idx_res_attr_key mapKeys(ResourceAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,
INDEX idx_res_attr_value mapValues(ResourceAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,
INDEX idx_log_attr_key mapKeys(LogAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,
INDEX idx_log_attr_value mapValues(LogAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,
INDEX idx_body Body TYPE tokenbf_v1(32768, 3, 0) GRANULARITY 1
)
ENGINE = MergeTree
PARTITION BY toDate(Timestamp)
ORDER BY (ServiceName, SeverityText, toUnixTimestamp(Timestamp), TraceId)
SETTINGS index_granularity = 8192, ttl_only_drop_parts = 1

Vector 字段表

CREATE TABLE vector.vector_logs
(
`file` String,
`timestamp` DateTime64(3),
`kubernetes_container_id` LowCardinality(String),
`kubernetes_container_image` LowCardinality(String),
`kubernetes_container_name` LowCardinality(String),
`kubernetes_namespace_labels` Map(LowCardinality(String), String),
`kubernetes_pod_annotations` Map(LowCardinality(String), String),
`kubernetes_pod_ip` IPv4,
`kubernetes_pod_ips` Array(IPv4),
`kubernetes_pod_labels` Map(LowCardinality(String), String),
`kubernetes_pod_name` LowCardinality(String),
`kubernetes_pod_namespace` LowCardinality(String),
`kubernetes_pod_node_name` LowCardinality(String),
`kubernetes_pod_owner` LowCardinality(String),
`kubernetes_pod_uid` LowCardinality(String),
`message` String,
`source_type` LowCardinality(String),
`stream` Enum('stdout', 'stderr')
)
ENGINE = MergeTree
ORDER BY (`kubernetes_container_name`, timestamp)

fluent字段表

CREATE TABLE fluent.fluent_logs
(
`timestamp` DateTime64(9),
`log` String,
`kubernetes` Map(LowCardinality(String), String),
`host` LowCardinality(String),
`pod_name` LowCardinality(String),
`stream` LowCardinality(String),
`labels` Map(LowCardinality(String), String),
`annotations` Map(LowCardinality(String), String)
)
ENGINE = MergeTree
ORDER BY (host, pod_name, timestamp)

日志需要近似全文检索

基于ElasticSearch的日志方案,由于可以基于ElasticSearch实现的日志内容分词,所以很容易实现全文检索,但是基于ClickHouse就很难实现该功能。

那是不是基于ClickHouse的方案就完全没有办法呢?

ClickHouse的索引介绍

  • tokenbf_v1 按非字母数字字符(non-alphanumeric)拆分。相当于按符号分词,而通常日志中会有大量符号

在大牛的文章中,

https://juejin.cn/post/7130514546069864456

详细介绍了全文检索的实现,有兴趣的可以仔细看下大牛的文章。

最理想的日志方案应该满足什么条件?

我们认为理想的基于ClickHouse的日志方案应该满足以下几条:

  • 使用列来进行检索,而不是map或者双array,保证高效的查询效率
  • 用户不需要为了不同部门的日志内容,进行维护单独的表结构
  • 支持对原始日志内容进行近似的全文检索

我们调研了国内外几乎所有基于ClickHouse的日志方案,最后发现国内开源项目ClickVisual项目的思路最相近,ClickVisual几乎可以做到开箱即用。


ClickVisual的方案不足

ClickVisual工作原理:

  • 针对每种日志格式定义不同的parse规则,ClickVisual为每种规则生成一张新的日志表。该日志表存的就是解析之后的日志,之后的日志查询都是针对该日志表。因为解析之后的日志已经按照ClickHouse列存储了,所以关键字段查询是非常快的
  • 基于Kafka表引擎,读取Kafka原始日志,落库至临时表中
  • 魔术开始的地方: 基于ClickHouse的物化视图,将原始日志中的新增日志_raw_log_内容按照日志解析规则parse成日志列格式,并将解析好的日志存入该规则对应的日志表中

临时表

CREATE TABLE default.test_stream
(
`status` String,
`timestamp` Float64,
`message` String CODEC(ZSTD(1))
)
ENGINE = Kafka
SETTINGS kafka_broker_list = '127.0.0.1:9092',
kafka_topic_list = 'test',
kafka_group_name = 'default_test',
kafka_format = 'JSONEachRow',
kafka_num_consumers = 1,
kafka_skip_broken_messages = 0

物化视图

CREATE MATERIALIZED VIEW default.test_view TO default.test
(
`status` String,
`_time_second_` DateTime,
`_time_nanosecond_` DateTime64(9),
`_raw_log_` String,
// 日志表的列
`level` Nullable(String)
//根据需要调整列
...
) AS
SELECT
status,
toDateTime(toInt64(timestamp)) AS _time_second_,
fromUnixTimestamp64Nano(toInt64(timestamp * 1000000000)) AS _time_nanosecond_,
message AS _raw_log_,
// 物化视图处理成列
toNullable(toString(replaceAll(JSONExtractRaw(message, 'level'), '"', ''))) AS level
// 根据需要添加更多解析规则
...
FROM default.test_stream
WHERE 1 = 1

按照日志解析规则将_raw_log_parse成新的真实日志表

CREATE TABLE default.test
(
`status` String,
`_time_second_` DateTime,
`_time_nanosecond_` DateTime64(9),
`_raw_log_` String CODEC(ZSTD(1)),
// 该列通过物化视图解析得到
`level` Nullable(String),
// 根据需要添加更多列
...
INDEX idx_raw_log _raw_log_ TYPE tokenbf_v1(30720, 2, 0) GRANULARITY 1
)
ENGINE = MergeTree
PARTITION BY toYYYYMMDD(_time_second_)
ORDER BY _time_second_
TTL toDateTime(_time_second_) + toIntervalDay(1)
SETTINGS index_granularity = 8192

每当需要分析新的索引字段,clickvisual会执行Add Colum为日志表添加新的列,同时更新物化视图添加新的解析处理规则。

ClickVisual的不足:

根据上述的原理:

  • 不支持高效的近似全文检索,工作原理可以看出由于ClickVisual并未对_raw_log_进行跳数索引,所以也就导致ClickVisual不能高效的支持近似的对原始日志全文检索
  • 由于ClickVisual完全依赖Kafka表引擎来实现日志的摄入,虽然ClickVisual也支持引入ClickHouse的已有日志表结构进行查询,但是很可能并不是直接针对列查询,而是针对map数据查询,只有通过Kafka引擎来摄入的日志才能生成新日志表结构,最终查询才是针对列式查询,才能有较高的查询效率
  • Kafka表引擎读写日志速度无法控制,如果日志量非常多,导致ClickHouse物化视图工作过程中内存爆掉

APO 日志设计方案

ClickVisual已经非常接近理想日志方案了,只是我们需要对ClickVisual的逻辑进行调整。

  1. 不使用ClickHouse的Kafka表引擎来完成日志的摄取工作,而是改成Vector的方式完成日志的摄取工作。这样就不再依赖Kafka,对于中小用户日志规模没有那么大的用户,可以直接使用,而不需要维护Kafka。虽然去掉了Kakfa,同时增加了Vector,但是Vector的运维工作相比kafka而言,Vector几乎不需要运维
  2. 引入了Vector之后,可以通过配置Vector来调整参数,确保在大量日志洪锋的时候,也不至于将ClickHouse内存打爆
  3. 用户如果真的需要引入Kafka,也有已经维护好的Kafka,完全可以使用Vector先将原始日志写入Kafka,然后使用Vector从Kafka读取出来,继续实现后续的日志处理
  4. APO引入了ClickHouse null表引擎,来实现原始日志(从Vector写入的) 转换成按照日志解析格式解析之后的真实日志表。
  5. 所有的查询都是针对真实日志表的列查询,所以性能比较高
  6. 在真实日志表中,额外存储了_raw_log_,配合跳数索引完成 近似日志全文检索。

欢迎使用APO全量日志功能 1图


APO v0.6.0更新日志:

新增功能

  • 支持全量日志的采集、处理与展示功能

缺陷修复

  • 修复服务端点存在特殊字符时,无法获取到依赖延时曲线的问题
  • 修复无故障场景下频繁采集故障现场数据的问题
  • 修复部分场景下数据库调用无指标的问题
  • 修复传统服务器场景下,网络质量状态无法关联到告警的问题
  • 修复传统服务器场景下,OneAgent配置注入失败的问题

其他

  • 允许在创建 ClickHouse 表时选择是否创建副本
  • 向下兼容 ClickHouse 版本,当前支持最低版本为 22.8.x

APO介绍:

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

apo.kindlingx.com

https://github.com/CloudDetail/apo

在线业务的常见全栈故障种类与定位手段

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

在线系统的稳定性和可靠性是企业数字化转型成功的关键。然而,由于云环境和系统演进的复杂性,故障的发生几乎不可避免。本系列文章将对在线系统可能遇到的全栈故障进行分类,并结合网上的案例分析,对比常规分析诊断手段与Originx推理引擎是如何能够轻松找到全栈故障的根因。

本文为该系列的第一篇,主要介绍常见故障以及全栈故障定位的难点,后续系列文章将重点介绍如何使用Orginx高效定位故障。

常见故障分类与常规的分析定位手段

应用程序故障

代码缺陷导致应用崩溃或错误

○ 案例:2023年双11期间,某汽车在线订单平台的Tomcat服务节点出现了严重的线程池耗尽问题。事发当天上午10点多,随着大促活动的用户流量激增,结算服务的响应时间明显下降。到中午时,大量来自北京地区的用户反馈在提交订单结算时,页面卡顿严重,部分直接超时失败。经过一天的紧张排查,最终发现是Java结算模块存在循环等待的死锁问题。该模块中存在太多的锁粒度,再加上连接池等配置不合理,并发压力下更容易发生死锁。临时解决方案是扩容结算服务的资源,并重启Tomcat释放线程。次日即行修复死锁代码,并持续优化相关模块的并发能力。这次事故虽然只持续了一天,但给用户造成了极差的下订体验。

○ 定位方法:人为分析日志,分析代码,对线程池进行监控,对代码定制化锁的监控(很难实现,没有办法覆盖所有场景

资源不足(CPU、内存、磁盘)

○ 案例:2023年5月12日,一家大型商业银行的新版网上银行系统在上线后不久遭遇了某些业务场景执行超时的错误。由于代码中存在一个未被发现的逻辑错误,导致在特定参数组合场景下,系统会重复执行某项业务逻辑,造成CPU使用率异常飙升。这种情况在测试环境中难以复现,因此未被及时发现。故障发生后,客户在进行转账和查询等操作时遇到了明显的延迟,严重时甚至导致服务不可用。银行紧急协调开发团队进行排查,在生产环境中利用jstack等工具查找CPU飙升的原因,最终在4小时内定位到了问题源头。通过快速发布补丁修复了BUG,并重新部署了服务。此次事件导致银行损失了大量客户交易,并对其声誉造成了一定影响。

○ 定位方法:借助java分析工具,在故障能复现的时机,人为分析问题

应用配置问题

○ 案例: 2023年3月15日,一家领先的金融支付服务公司遭遇了支付处理延迟的问题。由于对高峰时段的实例数扩缩容配置人为操作错误,导致在线支付服务的实例数量未能满足既定需求。在随后的高峰交易时段,支付系统出现了严重的延迟,部分交易无法完成,影响了客户的支付体验,并导致公司损失了数百万的潜在交易额。经过紧急扩展服务实例并重新配置负载均衡策略,服务在2小时内逐步恢复。此次事件突显了容量规划在金融服务中的重要性,并促使公司加强了对服务容量和性能监控的投资。

○ 定位方法:人为分析日志,分析代码,结合资源使用指标(单纯依赖CPU、内存、磁盘指标很难发现实例不够)


数据库故障

数据库连接问题

○ 案例:2022年春节假期前最后一个工作日,某大型在线商城的数据库连接池曾出现被耗尽的严重故障。当天上午10点前后,随着流量的激增,商城首页以及各大类目页的查询请求突然出现大量超时和失败。SRE在慌乱中排查了30分钟,最终确定是数据库连接池的问题,由于促销引起了流量波动,而数据库连接池配置仍是原来配置并不足以支撑大流量,可用连接资源在高峰时段几乎被同时耗尽所致。

○ 定位方法:建立数据库连接池监控关键指标

性能瓶颈(锁、查询等)

○ 2022年8月20日,某知名在线旅游预订平台出现数据库死锁导致机票预订业务中断数小时。高峰期时大量并发订单涌入,引发系统内部事务互相等待访问同一资源,造成死锁并耗尽连接池。经过大面积业务重启,瘫痪2小时之后才恢复。事后,该平台对业务代码进行重构优化, 从根本解决死锁风险。此次事故造成约2000万元订单收入损失。

○ 定位方法:建立数据库监控,建立死锁监控找到初始SQL语句的应用实例

网络故障

网络连接中断、延迟或丢包

○ 案例:2023年4月,某互联网金融云平台因内部容器云平台的COREDNS服务器群集发生异常,导致整个私有云内的核心交易系统无法正常解析内部服务地址。在接下来的3个小时内,平台的放贷、风控等多个交易系统出现大面积延迟和连接中断,账户查询、委托下单等关键业务无法正常使用。据初步统计,这次故障给金融机构带来的直接经济损失高达数亿元人民币。最终通过手动配置绕过DNS解析,临时恢复关键系统连接,但整体恢复所需时间超过10个小时。事后分析发现,DNS集群全军覆没是由于COREDNS升级之后的bug导致,但是没有完善的监控导致故障发现严重滞后。

○ 定位方法:对应用日志和网络流量做监控,单独定制DNS解析关键指标

网络配置错误

○ 案例:2022年12月,世界杯决赛期间,某大型视频直播平台由于网络设备配置问题,导致导致网络丢包比例较大,数百万在线用户观看比赛直播受到严重影响,画面频频卡顿中断。该故障持续近2小时,给平台带来了广告收益损失,也影响了品牌声誉。经过紧急处理和优化,网络质量逐步恢复,但已错过了决赛最关键时段。

○ 定位方法:网络流量监控,对网络交换机、路由器建立监控体系


缓存故障

缓存命中率下降

○ 案例:2023年6月8日早高峰,某知名新闻平台首页及文章详情页出现加载延迟、频繁超时。原因是缓存服务配置错误导致数据过早过期,高流量下未能及时刷新,与数据库产生数据不一致。经紧急调整缓存策略,禁用部分过期机制并扩容缓存集群,系统逐步恢复。但此次事故影响约200万访问,广告收益损失近百万元。

○ 定位方法:建立APM监控体系,检查Trace的缓存访问次数和延时数据

消息队列故障

消息堆积或消费者延迟

○案例:2023年5月15日,某知名电商平台消息中间件所在一台服务器磁盘出现坏道,导致消息写入延迟超10秒。高峰期部分订单消息阻塞,下游服务处理速度骤降80%,造成大量订单挤压及库存操作失败。由于该故障出现较少,SRE专家没有经验,排查期很长,长达1小时才排查出有问题的消息中间件实例,最后经磁盘热插拔修复坏道、调大消息队列容量等应急措施,系统逐步恢复。

○ 定位方法:建立APM监控体系 队列监控、人为分析日志

外部依赖故障

下游第三方服务调用延迟或失败

○案例:2023年7月6日,某金融科技公司接入第三方支付平台时,遭遇DNS故障导致解析异常,支付请求被调度至香港远程服务节点,网络延时高达200毫秒。当日下午2点开始,订单高峰期大量请求超时失败,支付接入率仅30%。经过一天的排查,终于确定了是第三方支付的DNS解析出现问题,临时固定域名,调用国内支付接口。但仍损失千万元订单手续费收入。

○ 定位方法: 建立APM监控体系,同时在日志中建立关键指标

基础架构故障

硬件故障(服务器、存储、网络设备)

○案例:2022年6月18日,618购物节期间, 某电商北京西单数据中心两台机架服务器主板同时发生故障,导致一个重要的订单系统服务中断。受影响的约6000名用户在下单支付环节遭遇失败,由于这个服务与商品库存管理直接相连,错过这个高峰期将可能导致损失数亿元营收。经过5小时的故障排查和系统切换,终于恢复正常。此次事故再次凸显了硬件冗余以及容灾能力对于电商业务的重要性。

○ 定位方法:硬件监控体系的建设

系统软件故障(操作系统、虚拟化层、软负载)

○案例:2023年3月,某热门视频直播平台在一场体育赛事直播过程中,由于负载均衡器组件发生故障,无法正确分发流量至下游转码服务器集群,导致部分转码节点超负荷宕机。此次事故造成大量用户无法观看直播画面,持续约2小时。经过现场工程师的快速响应和临时调度,负载得以重新分配,服务逐步恢复。但由于高峰期直播中断,给平台带来了可观经济损失和品牌声誉影响。事后分析发现,除了流量突发之外,负载均衡器在高压力下表现异常也是导致故障的重要原因。

○ 定位方法:研究中间件负载均衡器的指标体系,构建软负载的监控指标体系


覆盖全栈的监控体系建设和使用难度都很高

假设我们有能力建设一套统一的全栈监控体系和运维大数据平台,但对使用者而言,全栈系统仍存在以下两个主要难点:

使用难度高

数据量与信息过载: 在云环境下,监控系统的数据生成速度和体量是巨大的。这不仅涉及到数据的海量收集,更在于如何从这些数据中迅速提取出真正有价值的信息。用户面临的挑战是,要在不断涌入的数据流中,识别哪些是关键性能指标的异常,哪些是日常波动的“噪声”。信息过载不仅仅是技术问题,它还可能导致决策迟滞,增加操作复杂性,甚至可能掩盖真正的系统问题。

人员技能与知识要求: 全栈监控体系要求使用者不仅要对单一技术有深入了解,还要对整个技术栈有全面的认识。在技术迭代迅速的今天,要求团队成员不断学习新技术、新工具,并能够将这些知识应用于问题的诊断和解决中。这种跨领域的知识要求对人才的选拔和培养提出了更高的标准,同时也增加了团队管理的难度。

团队协作难: 在故障排查的时候,全栈的监控体系不同模块可能由不同团队或个人管理维护,比如网络团队、硬件团队、应用团队等。但是,由于噪声的存在,不同人对故障可能有不同理解,容易出现相互推诿的情况,导致故障排查难以找到真凶。

建设难度高

实际上,建设统一的全栈监控体系也是很难的,主要难点体现在:

数据存储与管理的现实性: 期望一个单一的存储系统能够无缝地处理所有类型的可观测性数据(如日志、指标、追踪等)是不现实的。每种数据类型都有其特定的存储需求和访问模式,这就要求存储解决方案必须具备高度的可扩展性和灵活性。同时,数据的生命周期管理、安全性和合规性也是需要重点考虑的因素。

技术整合的持续性: 技术的不断演进要求监控系统能够适应新的工具和服务。这不仅仅是一个技术问题,更涉及到组织的战略规划和资源分配。随着新组件的引入,现有的监控架构可能需要不断地调整和优化,以保持其有效性和相关性。这个过程需要持续的投入,包括时间、资金以及专业知识。

基于APO四步实现炫酷的NGINX请求分析看板

· 阅读需 5 分钟

Cover 图

APO 充分利用 Vector + ClickHouse 实现的日志方案,做到了开箱即用、高效、低成本。利用 APO 的日志功能,不仅可以检索日志内容本身,还可以实现很多有意思的功能。本次为大家介绍使用 APO 的日志功能实现炫酷的 NGINX 请求分析看板,只需简单几步即可实现!

先上效果图:

  • 请求与耗时分析总览

1 图

  • 异常请求分析

2 图

  • URI请求分析

3 图

  • 请求日志明细

4 图


配置步骤

第一步 修改NGINX日志格式

打开 NGINX 配置文件(一般在/etc/nginx/nginx.conf路径下),按照下面的示例修改log_format部分,该部分要完全一样:

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '{"@timestamp":"$time_iso8601",'
'"client_ip":"$remote_addr",'
'"server_ip":"$server_addr",'
'"domain":"$server_name",'
'"request_method":"$request_method",'
'"path":"$uri",'
'"top_path":"$uri",'
'"query":"$args",'
'"request_length":$request_length,'
'"responsetime":$request_time,'
'"response_length":$body_bytes_sent,'
'"referer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"status":$status,'
'"upstreamhost":"$upstream_addr",'
'"upstreamtime":"$upstream_response_time"'
'}';
access_log /var/log/nginx/access.log main;

sendfile on;
#tcp_nopush on;

keepalive_timeout 65;

#gzip on;

include /etc/nginx/conf.d/*.conf;
}

修改完成后,重启NGINX或者执行命令nginx -s reload使配置生效。

第二步 采集NGINX日志

在安装 apo-one-agent 的 Kubernetes 集群中,编辑名为apo-ilogtail-user-config的ConfigMap,添加采集NGINX日志的配置,注意修改其中LogPath为 NGINX 日志的路径,下面是示例:

data:
pod_stdout_all.yaml: |
...
pod_stdout_file.yaml: |
...
# 以下为新增配置内容
pod_log_file.yaml: |
enable: true
inputs:
- Type: file_log
LogPath: /var/log/nginx/
FilePattern: "*.log"
ContainerFile: true
processors:
- Type: processor_wait_for_signal
DisableSignalSampler: true
ContentsRename:
"__tag__:_container_id_": "_container_id_"
"__tag__:__path__": "_source_"
flushers:
- Type: flusher_http
RemoteURL: http://apo-vector-svc:4310

第三步 在 APO 平台上配置日志库

打开 APO 平台的全量日志页面,在“日志库”部分点击 +,添加新的日志库:

5 图

在弹出的配置页面中,按照以下步骤进行配置:

  1. “日志库名”填写nginx_access_log
  2. 在“匹配规则”中配置能够匹配到NGINX日志的规则,例如通过 _source_=/var/log/nginx/access.log 进行匹配
  3. “日志格式配置”中选择“结构化日志”,并在文本框中输入以下内容:
{
"@timestamp": "2024-12-06T06:44:17+00:00",
"client_ip": "10.244.0.46",
"client_region": "",
"client_city": "",
"client_latitude": 0.1,
"client_longitude": 0.1,
"server_ip": "10.244.167.148",
"domain": "localhost",
"request_method": "GET",
"path": "/grafana/api/live/ws",
"top_path": "/grafana/api/live/ws",
"query": "-",
"request_length": 1259,
"responsetime": 0.010,
"response_length": 10,
"referer": "-",
"http_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
"status": 403,
"upstreamhost": "10.96.2.121:80",
"upstreamtime": 0.009
}
  1. 最后点击“保存”。

第四步 导入NGINX看板并查看数据

打开 APO 平台的“中间件大盘”,在右侧点击“新建”->“导入”:

6 图

在导入页面,输入仪表板ID“22037”,点击加载:

7 图

然后在页面中选择数据源为“ClickHouse”(如果没有该数据源需要手动配置),点击“Import”即可导入成功。在该看板的“项目”筛选框中手动输入

apo.logs_nginx_access_log

(与配置日志库时的日志库名称保持一致):

8 图

到这里就完成了所有步骤,尽情享受炫酷的NGINX请求分析看板吧!


鸣谢

文中使用的 Nginx 日志分析看板StarsL 设计并发布在 Grafana 中,感谢大佬的分享。文中给出的方案简化了配置流程,因此看板中部分数据可能存在缺失,您可以检查看板中的查询条件,根据需求调整 NGINX 日志格式解锁完整看板。


APO介绍:

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

apo.kindlingx.com

https://github.com/CloudDetail/apo

基于DeepSeek的可观测性智能体实践

· 阅读需 14 分钟

cover 图

背景

云观秋毫是一家在可观测性领域帮助用户落地IT故障根因分析的初创企业。产品最开始使用传统的规则引擎来实现分析规则的执行,但是存在可解释性和定制化差等问题,所以2024年我们探索引入了大语言模型,不仅取得了效果上的提升,同时也获得了更好的解释性和可扩展性。2025年,云观秋毫将会把实践经验融入到平台中,研发可观测性智能体编排平台,让用户也能够快速构建可观测性领域的智能体,覆盖更多可观测性数据分析垂直场景。

早在2024年11月,通过多方位实验和测试,团队就已经选型DeepSeek作为智能体背后默认的大语言模型,当时我们已经发现DeepSeek在性能和成本上的优势,但没有料到DeepSeek会如此火爆,下图是我们在社区中介绍功能的聊天记录:

1 图


实践效果

先上结论,我们基于大语言模型实现了一个可持续演进的故障定位智能体,该智能体能够执行告警分析和故障定位的能力,该智能体在使用DeepSeek时综合表现优于其他模型(2025年2月结论)。DeepSeek在理解和处理可观测性的各类数据上有着较高的准确率,能够较好地理解专家规则并按照规则分析数据,且具有高性价比的价格,尽管偶尔出现数据幻觉,但经过设计能够达到较高的准确率。

该智能体分析问题的整体流程为:以告警通知作为智能体分析的入口,以告警和异常检测事件作为数据基础,让大模型利用预设的思维链规则分析拓扑和事件数据,以此识别疑似根因节点,最终通过北极星指标确认根因。

使用该智能体,能够显著提高用户在复杂服务依赖场景中进行故障定位的效率,同时智能体在分析问题时提供了更好的解释性和可扩展性。

下图是该智能体分析问题的真实案例:

2 图

这里不再赘述细节,如果大家对该智能体感兴趣,欢迎关注和试用“云观秋毫”的“APO”产品,我们在官网提供了更多详细信息。此外,我们正在研发可观测性智能体编排平台,未来用户能够方便地在平台上构建自己的智能体,覆盖除了根因分析以外的更多场景。


为什么选择DeepSeek

大模型选型的考量

在当今的可观测性领域中,运维人员在处理异常问题时,常常需要处理海量的数据进行查询、分析和处理任务。排障过程通常具有流程化、规范化以及经验化的特性,这意味着对于经验不足的运维人员而言,这一过程既耗时又费力。因此,利用大模型的推理能力来简化这一过程显得尤为重要——只需提供自然语言描述的规则和数据,大模型便能像专家一样快速识别问题所在。

1.JSON格式数据的理解

由于大模型存在上下文Token限制,为了确保其能够有效理解可观测性数据,首先必须解决的是数据输入格式的问题。

JSON作为一种结构化数据格式,因其便于从原始数据中提取信息,并结合提示工程(描述JSON数据格式键值对含义)易于被大模型解析而成为首选。

如微服务场景下,服务调用的上下游关系复杂且数据量庞大,通过精简数据并使用嵌套的JSON格式记录这些关系,可以大大简化层级结构,帮助大模型更好地理解和分析数据。

然而,并非所有大模型都能完美解析这种数据形式。经过实际验证发现,如文言一心和参数低于14b的模型等在理解JSON数据时存在障碍,容易出现逻辑错误,如无法正确理解上下游调用关系,或着将调用关系弄反。而豆包、智谱GLM-4 Plus、Qwen2.5-32B及以上版本和DeepSeek则表现出了良好的理解能力。

模型理解JSON数据
文言一心
参数14b以下的模型
豆包1.5-Pro-256K
智谱GLM-4-Plus
Qwen2.5-32b及以上
DeepSeek

2.自然语言规则执行效果

当大模型能够准确理解可观测性数据后,其还需要具备根据用户提供的自然语言规则进行推理的能力,以定位可能的故障点。然而,部分大模型在执行规则时可能会出现偏离指令的情况。

例如,在APO平台节点中,业务拓扑需通过服务名和端点组合唯一标识,但某些模型在处理过程中会忽略端点数据,造成业务拓扑服务名称不完整导致结果偏差。推理结果中,不同的模型对规则的执行准确率也不同。

对比不同模型的表现,DeepSeek在规则执行准确性方面达到了100%,显著优于其他选项如豆包1.5-Pro-256k(70%)、智谱GLM-4 Plus(90%)以及Qwen的不同版本。

模型规则执行准确率
豆包1.5-Pro-256K70%
智谱GLM-4-Plus90%
Qwen2.5-32b70%
Qwen2.5-72b90%
DeepSeek100%

3.大模型使用成本

除了考虑模型的推理能力和准确性外,实际业务场景中的使用成本也是不可忽视的因素之一。

尽管像Qwen2.5-72B和智谱GLM-4 Plus这样的模型在推理效果上表现出色,但它们的调用费用相对较高。相比之下,DeepSeek不仅在性能上领先,而且其调用成本相比其他旗舰级模型低至十分之一乃至百分之一(尤其是当命中缓存时),提供了更高的性价比。

虽然像豆包1.5-Pro-256k这样的低价替代品看似经济实惠,但其较低的推理准确率也意味着潜在的效率损失。

每千 Token价格 (输入)每千 Token价格 (输出)
Qwen2.5-32b0.0020.006
Qwen2.5-72b0.0040.012
智普GLM-4-Plus0.050.05
豆包1.5-Pro-256k0.0050.009
DeepSeek0.0005(命中缓存)/0.002(未命中缓存)0.008

大模型选型的结论

  1. 从准确率的角度考虑,需要大模型能正确识别JSON数据,同时按照用户指令来执行自然语言的规则。国内符合条件且效果较好的大模型有DeepSeek, Qwen2.5-72b, GLM4-Plus等。
  2. 同时还需要考虑调用成本DeepSeek费用远低于其他大模型且缓存机制使得成本进一步下降。

DeepSeek存在的缺陷

尽管DeepSeek在处理可观测性数据、执行自然语言规则方面展现了极高的准确率和卓越的性价比,但它也并非毫无瑕疵。与所有大模型一样,DeepSeek面临着一个较为突出的问题——模型幻觉现象(hallucination)。

这种现象在分析微服务拓扑结构时尤为明显,例如在基于“train-ticket”场景的测试中,简化了复杂的微服务调用关系,仅保留最基本的业务节点进行测试,DeepSeek有时仍会输出一些如“ts-payment-service”这样实际上并不存在于真实数据中的服务名,但这些名称又似乎与“train-ticket”有关。

如何克服这些缺陷

  1. 调整大模型参数:通过精细调节DeepSeek的生成参数,比如top_p(核采样)和temperature(温度),可以有效控制输出内容的多样性和稳定性。降低temperature值可以让模型倾向于选择概率更高的词汇,从而减少输出的随机性;而适当调整top_p值,则有助于限制词汇的选择范围,进一步确保输出内容的精确度和一致性。
  2. 优化数据组织方式:为了避免大模型由于数据相似性而产生联想,导致出现不准确的服务名,可以通过改进数据的组织形式来缓解这一问题。具体而言,APO平台使用服务名加端点的方式代替单纯使用服务名标识节点的方法,不仅可以增加数据的独特性,还能显著降低模型因混淆不同数据而产生错误的可能性。

采取上述措施,可以在一定程度上缓解DeepSeek及其他大模型中存在的幻觉问题,提升其在实际应用中的可靠性和准确性。不过值得注意的是,完全消除此类问题可能需要持续的技术进步和对模型架构的深入优化。


展望未来

目前我们实现的智能体主要解决基于拓扑的故障定位场景,在该场景下已经取得了不错的效果。在实践过程中,我们积累了大量开发大语言模型应用的经验,特别是在可观测性领域中如何分析大量异构数据。我们希望这些经验不止停留在团队内部,而是能够与业界一起讨论交流,一同推动大语言模型在可观测性领域的落地。

基于上述实践和经验,我们已经意识到AI Agent可能给可观测性领域带来的颠覆性改变,为了能够让这些经验能够惠及更多人和企业,我们正在研发可观测性智能体编排平台,并将会作为开源项目开源。在该平台中,所有人都能够方便地构建自己的可观测性智能体,覆盖可观测性领域中的更多场景,最终释放人的时间,让智能体替人工作。


3 图

大语言模型需要的可观测性数据的关联方式

· 阅读需 28 分钟

cover 图

可观测性数据的关联方式及其优缺点

随着现代分布式架构和微服务的普及,可观测性(Observability)已经成为确保系统健康、排查故障、优化性能的重要组成部分。有效的可观测性数据关联方式不仅能够帮助我们实时监控系统的运行状态,还能在故障发生时迅速定位问题根源。本文将探讨不同的可观测性数据关联方式,重点梳理什么样的关联方式才能更好的与大模型结合。

可观测性数据与大模型结合的矛盾点在于:

  • 可观测性数据属于海量
  • 大模型的上下文有限制无法直接分析海量的可观测性数据

什么是可观测性数据关联?

可观测性数据关联是指将系统中不同来源和维度的可观测性数据(如日志、指标、Trace)关联起来,形成一个完整的监控视图。通过这种关联,我们能够更全面地理解系统的行为和性能,尤其在故障排查时,能够实现更加精准的定位。数据关联方式的选择直接影响故障排查的效率、准确性以及可视化效果。

可观测性数据关联的目的

在讨论具体的可观测性数据关联方式之前,我们首先需要明确为什么要进行数据关联。数据关联的目的是为了优化故障排查过程、提高系统监控的效率,并帮助用户从多维度获取对系统健康的全面理解。具体来说,数据关联的目的包括:

1.提高故障诊断的准确性和效率

系统中的各个组件和服务彼此依赖,问题往往是多因素、多维度的。单纯依赖某一维度的数据(如单一的日志或单一的指标)难以全面展现问题的全貌,容易导致诊断错误或延误。通过关联不同的数据源(如日志、Trace、指标等),我们可以更准确地定位问题所在,并缩短故障排查的时间。

2.减少数据噪音

系统运行中产生的数据量巨大,尤其是在大规模分布式系统中。没有合理的数据关联,可能会导致用户面对大量的无关数据,从而被“信息过载”淹没。数据关联有助于筛选出关键的、相关的事件或行为,帮助用户专注于最重要的信息,减少不必要的噪音。

3.提高系统的可理解性

对于复杂的分布式系统,理解每个组件和服务的行为变得异常困难。通过数据关联,用户可以跨多个维度(如服务、接口、业务等)对系统的状态进行统一视图的展示,从而增强系统的可理解性。这使得开发人员、运维人员和其他利益相关者可以更加直观地看到系统的工作情况以及潜在的问题。

4.支持根因分析与问题追溯

一旦发生故障或性能问题,快速准确地进行根因分析是至关重要的。数据关联能够帮助用户从多个层次上回溯问题的发生过程,从而帮助确定故障的根本原因。这是特别重要的,尤其是在微服务架构中,问题可能是由多个服务交互引发的,而不仅仅是某个服务本身的问题。

大语言模型与可观测性数据关联

大语言模型具备智能推理能力,在可观测性领域的根因分析和智能诊断等功能中,自然而然地引发了将大模型应用于故障根因定位的想法。然而,考虑到大模型的上下文限制(通常为128K),无法将一段时间内所有的 Trace、Metrics、Logs 等数据完整提交给模型进行分析。因此,大模型无法直接从所有数据中提取故障特征。

在可观测性数据中,Trace、Metrics、Logs 和 Events 各自具有独特的价值。在实际应用中,我们不能仅依赖单一数据源,而忽视其他数据,否则可能会遗漏关键的故障线索。

因此,合理组织和关联这些可观测性数据,并进行综合分析,以提取出有价值的故障特征,是实现大模型故障分析的前提。


常见的可观测性数据关联方式

1.链路级别(Trace)数据关联

链路数据关联是目前最常见的关联方式之一。它通过跟踪请求在微服务架构中的全过程,捕获每个服务的调用链路信息。每个请求会生成一个 Trace,每个 Trace 包含多个 Span(即单个服务的调用记录),这些 Span 按顺序构成完整的调用链。在日志中,通过记录 traceId 和 spanId,实现 trace 与日志的关联,同时通过 timestamp 和主机、容器的标签(label)实现 trace、日志、指标(metrics)和事件(event)的关联。

  • 优点: ■ 精准定位: 通过完整的调用链路,能够清晰展示服务之间的调用关系,有助于快速定位性能瓶颈和故障源。 ■ 端到端可视化: 提供全链路视图,帮助用户了解跨多个服务的调用流,尤其是在微服务架构中,能够直观呈现各服务的健康状况。 ■ 支持跨服务分析: Trace 数据能够跨多个服务,具备跨系统、跨平台的故障排查能力。

  • 缺点: ■ 高资源消耗: 生成和存储 Trace 数据需要较高的资源消耗,尤其是在大量并发请求时,可能会对数据存储和处理造成较大压力。 ■ 复杂性: 在服务间调用关系复杂的情况下,Trace 数据可能包含过多信息,导致分析难度增加。很多运维人员也反馈看不懂Trace的具体span数据,特别是慢方法,不知道如何根据Trace信息指导接下来的运维动作。 ■ 数据噪声: 某些不相关的调用链可能增加数据噪声,影响故障定位的准确性。

大模型的针对链路级别trace用法

通过关联 Trace、日志、指标(metrics)和事件(event),异常相关信息可以提交给大模型进行分析。大模型能够对这些异常数据进行深入分析,例如,针对一段错误日志,提供日志的分析总结;对于异常的 Trace,分析出具体异常的 Span 等信息。

尽管大模型在分析异常数据方面已经对用户提供了极大的帮助,但它并未完全解决用户的排障难题。在如此大量的 Trace 和日志数据中,用户为何要分析某一条异常的 Trace 或日志,这一选择的过程往往充满了随机性。而被分析的 Trace 或日志是否具有代表性呢?

如果连续分析的几条 Trace 或日志都揭示了相同的故障原因,这是否就足以说明问题?在日常工作中,许多用户可能会直接根据这些分析结果进行后续的运维动作。

这种排障方法在没有统计信息支持的情况下,确实有一定的成功概率,但我们认为,这并不是最佳的方案。

此种大模型的用法适合在故障已经定界到具体的服务或者接口之后,再进一步结合此种数据重点分析根因。

2.服务级别数据关联

服务级别关联主要关注服务本身的健康状况和性能,服务的定义可以类比为 Kubernetes 中的 Service。它通过聚合同一实例中不同接口的指标、日志和 Trace 信息,形成以服务为单位的可观测性视图。这种方式将系统中的每个服务视为独立实体,帮助用户全面了解服务的整体健康状况。

  • 优点
    简洁直观:用户可以通过服务级别的指标(如 CPU 使用率、内存占用率、错误率等)快速了解各个服务的状态。
    高效监控:与链路级数据相比,服务级数据聚合简洁,减少了数据存储和处理负担。它是很多可观测性平台的入口,帮助用户快速识别故障范围,从而确定故障分析的切入点。
    易于扩展:随着服务数量的增加,可以方便地扩展和整合新的服务监控。

  • 缺点
    噪音和关键信息丢失:在实际开发中,一个服务可能会提供多个接口,且接口作用不一。若按照服务的不同接口进行统计,可能会引入噪音或导致关键信息被淹没。例如,某个接口的调用量很少,而另一个接口调用量很大。当调用量少的接口发生故障时,由于大接口占据统计数据的主要部分,调用量少的接口故障可能会被忽略。

大模型的针对服务级别数据关联的用法

服务级别的统计数据可以直接提交给大模型进行分析,大模型能够基于这些数据识别疑似故障的服务节点。然而,这一过程中通过提示词引导大模型存在尺度把握的问题,即如何引导大模型判断服务节点存在疑似故障。

如果阈值设置过于严格,例如只要错误率不为零或 CPU 使用超过某一阈值即认为存在潜在问题,可能会导致大量服务被判定为疑似故障节点,尤其是在没有后续数据进一步支持的情况下,这样的结果难以继续深入分析。

相反,如果阈值设置过于宽松,大模型可能会错误地得出“系统正常”的结论,从而忽略实际的故障。

为了解决这一问题,我们认为可以采取更高层次的策略。首先,将阈值设置得相对严格,尽可能暴露所有潜在问题;然后,在具有因果关系的拓扑结构上进一步分析。所谓因果关系拓扑,指的是明确的上下游调用关系:当下游出现故障时,由于因果关系,故障会传递至上游。

然而,构建服务级别的因果关系拓扑图存在挑战,因为同一实例的不同接口可能出现在不同的业务链路中,同时,拓扑中可能会出现环路,所以APO并没有选择服务级别的数据关联做法。

目前在可观测性领域很少看到将服务级别数据交由大模型分析,因为大模型分析出服务级别的故障概览和人直接看服务级别的故障概览效果基本一致,没有额外的信息补充。

3.接口层级数据关联

接口URL层级数据关联是一种较为新颖的关联方式,类似于服务级别的数据关联,但它专注于具体的URL。对于同一实例的不同URL,它会根据不同的数据源(如 Trace、日志和指标)进行单独聚合。由于日志和指标通常属于实例级别,因此在聚合后,可能会出现误报的情况。然而,这种方法简化了用户的认知负担,更有利于帮助用户聚焦于业务接口层面的性能和故障排查。

  • 优点
    简洁直观: 用户无需过多关注 Trace、日志、指标或事件等具体数据,可以通过接口层面的抽象来理解接口的健康状态。
    服务级别聚合的优势:与服务级别聚合数据类似,接口层级聚合也具有简化监控和排查的优点。

  • 缺点
    难以完全避免数据噪音: 由于日志和指标依然是基于服务级别的数据,划分到接口级别后,仍只能将其视为疑似问题,无法完全避免数据噪音的干扰。

APO最后使用的接口级别的关联方式,形成如下图的状态信息汇总。

1 图

  • 应用接口异常:数据主要来自于trace,主要是对TPS、latency、error rate 指标进行异常判定之后的汇总状态
  • 容器异常类型:主要来自与k8s事件,实现对k8s event的状态汇总
  • 基础设施异常:来自于容器的CPU、内存、网络和主机CPU、内存、网络等基础指标的异常判定之后的汇总状态(同主机的CPU告警可能产生对被关联的接口而言,存在误告警可能,需要在业务调用拓扑中用专家经验分析判定 )
  • 网络异常:来自于对网络丢包、延时的状态判定之后的汇总状态
  • java exception:来自于对日志的error、exception的异常判定之后的汇总状态
  • 应用实例异常:来自与应用探测的事件状态判定之后的汇总状态

近期还会增加,该接口调用的中间件的异常状态判定,比如kafka的指标状态异常了,会影响调用kafka接口的指标状态异常。

大模型的针对服务级别数据关联的用法

接口级别的统计数据可以直接提交给大模型进行分析,大模型可以基于这些数据判断哪些接口所在的服务可能是故障的疑似节点。然而,与服务级别的数据分析一样,接口级别的数据也面临阀值设定的问题。如果阀值设置过于严格,可能会导致大量接口被标记为疑似故障根因;如果设置过于宽松,可能会错过一些潜在的问题。

尽管存在阀值设置的问题,但我们可以通过更高层次的分析来解决这些挑战。具体来说,所有接口异常的数据都可以通过业务调用链路进一步追踪。在这个链路中,接口之间的调用关系是明确的,并且可以从 Trace 数据中构建出接口维度的因果关系拓扑图。下游接口的延迟、错误等问题,往往会传递到上游接口,影响其性能和错误率。

 最后通过自然语言描述的“专家经验”的指导,大模型可以帮助理清业务调用链路中的接口关系,并结合上下游接口的故障情况,从而更准确地判断出疑似故障的根因节点。这样的分析方式,能够让大模型模仿人类专家进行故障定位,有效地提升故障定位的准确性。

APO就是如此设计的,根据这些状态汇总信息结合业务级别的数据关联,快速进行故障定界。最后在根据链路数据进行根因定位,所有的数据关联都被思维链聚合在一个对话中,最终可以用户快速实现故障定界定因。暂时还未见同类型的可观测性产品如此操作。

4.业务级别数据关联

业务级别数据关联将可观测性数据按照业务场景进行聚合。例如,电商平台的“下单”过程可以视为一个完整的业务流程,涉及到多个接口。在这种方式中,所有与“下单”相关的请求数据会被聚合在一张业务调用拓扑中,帮助用户从业务视角进行故障排查和优化。

  • 优点: ■ 直观的业务视角:将可观测性数据从业务角度进行聚合,可以帮助用户更好地理解业务流程中的瓶颈和问题。 ■ 增强的用户体验:用户可以直接看到与业务相关的数据和故障,而无需关心底层的服务和技术实现。 ■ 业务优先的故障排查:这种方式能够帮助用户从业务层面进行高效的故障诊断,尤其适用于大型电商、金融等对业务流畅度要求高的行业。

  • 缺点: ■ 数据聚合复杂度高:将业务流程与系统架构紧密结合,需要对系统和业务流程有深刻的理解,聚合的复杂度较高。 ■ 节点过多带来的拓扑复杂的问题:节点过多,拓扑实在太大,上百个节点也会导致大模型上下文打满的问题,同时也存在拓扑仍然成环的可能性。

大模型的针对业务级别数据关联的用法

大模型能够接受业务调用拓扑的前提是业务调用拓扑结构不会过于复杂,也要没有环状结构。

  • 拓扑结构过大,可能导致大模型上下文限制突破,从而大模型分析失效
  • 环状结构的出现,导致专家也很难有好的手段分析因果关系

所以需要提前对业务拓扑结构进行处理,可以利用业务调用链路的不同接口的延时、错误率曲线的相似性,从而快速得到更精简的业务拓扑结构,实现按照故障的贡献度来聚合业务调用拓扑,从而能够让大模型能够在此精简的业务拓扑数据之上分析问题。

未处理的业务调用拓扑:

2 图

按照相似度算法处理过之后的业务调用拓扑:

3 图

最后按照专家经验可以引导大模型模拟专家在业务调用拓扑之上分析故障。


总结

随着分布式系统的复杂性增加,合理的数据关联方式在可观测性中变得尤为重要。通过将不同来源和维度的可观测性数据(如日志、指标、链路等)进行有效关联,我们能够更全面地诊断系统故障、提高问题定位的准确性,并减少噪声带来的干扰。然而,随着数据量的剧增,传统的数据关联方法也面临着一些挑战,如高资源消耗、信息过载等问题。

通过业务关联和接口关联进行数据定界是故障排查中至关重要的一步。我们可以首先确定业务层面的关键接口,聚焦于用户交互最直接的入口点,利用专家经验,引导大模型模仿专家迅速定位潜在故障源。这一层次的定界有助于将可疑问题限定在业务逻辑的关键路径中,从而减少需要分析的数据范围,提高排查效率。

在此疑似故障节点确定的基础上,通过引入链路的详细关联数据,我们可以进一步深挖每一个相关节点的状态,追踪程序执行过程,从而理解故障根因。通过这种逐层深入的方式,我们能够准确判断出故障的根因。尤其是在复杂的系统中,链路数据能够帮助我们精确地还原请求的完整路径,识别出具体的故障节点。

受限于大模型的上下文限制,直接对所有可观测性数据进行分析并不可行,因此,合理的预处理和数据筛选成为成功应用大模型的前提。大语言模型在这一过程中提供了推理能力,能够按照自然语言描述专家规则操作,这样先比传统AIOPS而言具有很好的可解释性。相比运维数据的预训练的专有大模型,实现成本也相对较低。

总体而言,将可观测性数据按照不同层级(如链路、服务、接口、业务等)进行关联,并结合大模型的智能分析,可以大大提高故障排查的效率和准确性。在此过程中,通过业务和接口层的定界,快速锁定问题范围,再通过链路详细数据的关联逐层深入分析,最终实现精确的根因定位。合理的策略是通过精简和优化拓扑结构、聚合数据并利用专家经验,帮助大模型准确判断故障根因,最终实现高效的故障定位和问题解决。


4 图

如何找到并发请求中的锁

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

如何找到并发请求中的锁

经常听大家讲到在业务平峰期间一切正常,但当并发上升时用户端延时上升,体验急剧下降,往往这时候是由于应用锁导致。例如用户端访问时延是3s,数据库访问耗时500ms,而数据库索引和慢请求也都已优化,那么其他的2.5s到底是消耗在哪里?如果这其中的体验差距是由锁导致,那么又该如何快速定位这些锁,并将他们消除呢?

一方面受制于现有可观测性工具能力的限制,我们并不能有效地发现然后将其解决,另一方面传统的压测方法也并不能完美复刻生产环境的全部真实情。对于这些并发上升导致的问题,以及应用中看不见的锁,Kindling-OriginX 提出新的解决方法。

历史经验不准

实际工作中往往习惯于使用个人历史经验判断是哪些服务出现故障,哪些应用容易出现锁,微服务架构下,应用缩容扩容,应用实例数的不同,相同的问题常常表现出不同的现象。这就导致使用历史经验判断并不能有效的找到问题。

Kindling-OriginX 能够快速给出全部异常节点的根因报告,同时报告已给出分析结论,不论问题表现的现象如何,用户都能够快速简单的进行统一分析。例如下图的拓扑结构中,同样的性能问题,因为每个节点的实例数的不同,都会导致表现出不同的现象。Kindling-OriginX 已经分别对报告做了聚合,对数据做了分析,用户只需要简单查阅报告即可。 如何找到并发请求中的锁-历史经验不准

无法找到锁在哪里

实际生产环境中,一方面不可能事无巨细将应用所有变化都记录在日志中,另一方面很多数据也无法直接进行观测得到。往往知道应用里有锁,但是根本没有有效手段去找到锁在哪里。

Kindling-OriginX 通过实时监控和深度分析,快速识别性能瓶颈的同时,对每一个慢请求从系统调用级别进行拆解分析,究竟是GC、CPU等待、或是代码质量问题一目了然。

例如在下图示例中,futex耗时远大于历史基线值(futex是一种用于用户空间应用程序的通用同步机制,这里简单起见可以将其理解为一种锁机制),再结合自动化GC关联分析,得出故障根因是有锁,且该锁是由于系统发生GC导致 如何找到并发请求中的锁-无法找到锁在哪里1 如何找到并发请求中的锁-无法找到锁在哪里2

人工分析不可行

实际生产环境中,时时刻刻产生大量的 Trace 数据,要从这些大量的低价值数据中找出问题的根源,需要耗费大量时间进行人工分析,几乎不可能通过人工的方式找到关键数据。这不仅增加了工作负担,而且没有任何时效性可言。

Kindling-OriginX 通过异常占比与报告收敛的方式进行数据聚合,即使在大量 Trace 数据的情况下,也能对数据情况一目了然,快速找到所关心的数据。

如何找到并发请求中的锁-无法找到锁在哪里2 如何找到并发请求中的锁-无法找到锁在哪里2

干扰数据导致无法找到锁

系统整体性能急剧下降时,所有机器往往都处于高负载状态,越多的连接也会导致CPU需要处理的上下文切换越多,内存对象频繁的创建和释放也可能会导致出现因垃圾收集(GC)造成的延迟。这些干扰信号都可能会导致真正的问题被掩盖。

Kindling-OriginX 针对干扰数据多的问题,一方面将报告数据收敛聚合,避免数据过多造成的干扰,另一方面报告中直接给出根因结论,只需快速查阅就能得到结论,无需再进行人工分析和有效性判别。 如何找到并发请求中的锁-干扰数据导��致无法找到锁

传统的可观测性工具在面对并发请求中的锁时无法提供有效的定位方式和解决方案,个人历史经验的误判,海量数据的分析、噪声信号的干扰,以及在动态复杂环境下的有效诊断,都要求更先进的技术和方法。Kindling-OriginX 提供全新的自动化、智能化关联分析 Log、Metrics、Trace 数据解决方案,通过 eBPF 和TraceProfiling 技术还原每一次请求过程,精准定位分析并发上升时应用中的各类问题。

如何让程序员过一个没有烦恼的假日

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

如何让程序员过一个没有烦恼的假日

每逢假期、周末,总是被各种排障会和线上问题折磨,做什么都做不进去,也没法好好休息……

常听身边的同行们这样描述自己的假期。说实话,这感觉我可太熟悉不过了,因为这状态困扰了我好几年……

不管你是正吃着火锅还是唱着歌,只要服务器有故障,百米冲刺回到电脑前。“我曾经跨过山河大海...”满大街找网吧,只为轻敲那几个命令。格子衫、双肩包,出门时刻背电脑,这样还怎么好好玩耍。

刚刚过去的春节假期是一个难得的休息和充电的机会,然而,由于程序员的工作性质,我们常常会面临一些不一样的挑战,常常由于线上业务稳定性要求和担心出现bug,很难真正度过一个没有烦恼的假日。

经常是好不容易到了假期,工作项目也暂时有所舒缓,想回趟家或者出去走走,一想还要带电脑回,临时都可能要处理报警,买票的欲望就会随理智渐渐消退,依旧选择原环境待上几天。


如何让程序员过一个没有烦恼的假日

以前和朋友闲聊常常互相调侃到:只要你是名程序员,那么,你的电脑就比女朋友重要。你可以出去玩不带女朋友,但是你不能抛弃电脑!

“男友是程序员,和我出去约会拿着电脑,有紧急情况处理就带我去咖啡馆,他方便处理问题。还有一次,我们去内蒙古旅游,进沙漠他都背电脑,他说你不懂,带着电脑有安全感,长剑在手,谁与争锋!”


北上广深通勤时间普遍都要很久,在地铁上写代码这事已经算是比较常见了,尤其是线上如果出了问题,有时候直接在马路上、垃圾桶上开始处理问题。

如何让程序员过一个没有烦恼的假日


地铁上一大哥正在改bug

如何让程序员过一个没有烦恼的假日


为了马上处理问题,采取了面向红绿灯编程

如何让程序员过一个没有烦恼的假日


婚礼上,一样可以加班扩容改bug

如何让程序员过一个没有烦恼的假日


夜晚的街头,一样可以改bug

如何让程序员过一个没有烦恼的假日


如何让程序员过一个没有烦恼的假日

我想各位同行们看完这些段子在内心哈哈无奈自嘲一笑的同时,回想自己吃着火锅改bug,爬着山被紧急拉进故障处置群里的种种场景,也是有着些许的无奈。每一个项目的上线及平稳运行,是所有人员起早贪黑、披星戴月、夙兴夜寐、通宵达旦、夜以继日、废寝忘食的工作换来的,但这也让大家想到假期总会忐忑不安,难以好好休息,过一个没有烦恼的假期。

随着技术的发展和各种工具的完善,Kindling-OriginX 故障推理引擎通过专家智慧经验精准梳理各类分散监控指标与日志,自动化 Tracing 关联分析生成可解释的故障根因报告,为故障排查提供标准化、可行动、可解释的自动化排障流程。让bug修复、根因定位、团队故障定界、协作排障都将变得简单清晰,不用被休息日的OnCall骚扰,不再为无尽的排障协调小组群而烦恼。希望借此能够将大家解放出来,让之后的每一个假日都没有烦恼,好好恋爱,享受美食,全身心的体验运动后酣畅淋漓。

如何集成 DeepFlow 的数据增强网络故障的解释力

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

如何集成 DeepFlow 的数据增强网络故障的解释力

DeepFlow 是基于 eBPF 的可观测性开源项目,旨在为复杂的云基础设施及云原生应用提供深度可观测性。DeepFlow 基于 eBPF 采集了精细的链路追踪数据和网络、应用性能指标,其在网络路径上的全链路覆盖能力和丰富的 TCP 性能指标能够为专业用户和网络领域专家提供充足的排障定界支撑。

Kindling-OriginX 是一款故障根因推导产品,目标是提供给用户一个可解释的故障根因报告,让用户能够直接了解故障根因,并附有根因的推理过程以便验证根因的准确性。网络故障是故障当中比较难以简单解释的,仅仅告知用户哪段网络有问题是不够的,用户需要更多指标以及图解,才能帮助用户更好的理解网络到底发生了什么故障,以及发生在哪个环节。

本文介绍 Kindling-OriginX 通过结合 DeepFlow 完备的网络数据能力,自动化生成可解释的故障根因报告。

soma-chaos模拟网络故障

如何集成 DeepFlow 的数据增强网络故障的解释力

  • 针对seat-service注入200ms延时的网络模拟故障。
  • 接下来我们先使用 DeepFlow 来识别200ms的网络故障,并做出相应的action。

人工最简化排障过程

步骤一:利用Trace系统缩小范围

在微服务场景中,某个接口突然慢了,排障的第一步骤应该是看Tracing系统,找到Trace慢在哪个环节,以及慢的具体表现是什么。

用户通过Tracing系统能够找到具体的Trace,通过分析Trace能够发现seat-service执行时间很长,同时出现了一条非常长的config-service调用,但是config-service执行不慢。这个时候需要联动网络指标,来定位网络问题。

步骤二:利用DeepFlow火焰图确定故障发生在哪段网络

将故障代表traceid的输入DeepFlow在火焰图中,找到Trace在网络层面上的表现,然后深入分析这个火焰图,如果对火焰图比较了解,同时有具备网络知识的专家经验,是能够根据火焰图人为分析出:这个故障应该是发生在调用者也就是seat-service上,而且问题是发生了syscall到网卡的时间段,也就是容器网络时段出了问题(和故障注入是吻合的)。

如何集成 DeepFlow 的数据增强网络故障的解释力

步骤三:确定容器网络到底什么网络指标异常

根据故障排查经验,用户需要查看seat-service与config-service的pod的网络指标。这个时候用户需要跳转至DeepFlow的Pod级别的网络指标页面。通过该页面,用户能够查看出建连有200ms的延时突变以及RTT指标有突变。

如何集成 DeepFlow 的数据增强网络故障的解释力 如何集成 DeepFlow 的数据增强网络故障的解释力

步骤四:排除可能的干扰因素

根据经验,宿主机的CPU被打满和带宽被占满之时,虚拟网络也会出现丢包和时延,所以要排查当时seat-service与config-service所在node的CPU以及node级别的带宽,确保Node级别资源没有饱和。

通过k8s命令确认了两个pod所在的node节点,然后去DeepFlow的node指标监控页面查看相应指标,发现node的bps,pps等指标均在合理范围内。

如何集成 DeepFlow 的数据增强网络故障的解释力 如何集成 DeepFlow 的数据增强网络故障的解释力 如何集成 DeepFlow 的数据增强网络故障的解释力 由于node级别的网络指标没有出现明显异常,最终确定是seat-service的pod级别rtt指标异常。

人工排障总结

经过一系列的排查过程,最终用户是能够排查出故障的,但是对用户有以下要求:

  • 网络知识非常丰富
  • 深入理解网络火焰图
  • 熟练使用相关工具

Kindling-OriginX 如何结合 DeepFlow 指标,生产可解释的故障报告

Kindling-OriginX 针对不同的用户需求和使用场景,Kindling-OriginX 对 DeepFlow 的数据进行了加工呈现。

类比人工最简化排障过程,利用 Kindling-OriginX 的排障过程如下:

针对每一条 Tracing 自动化分析

针对此时的故障,自动化分析每条Trace,并按照故障节点对所列的Trace进行归集。Travel-service是由于级联故障导致的,本文不重点论述级联故障,如果有兴趣可以参考微服务级联故障该如何处理。 如何集成 DeepFlow 的数据增强网络故障的解释力

Review故障节点为seat-service的故障根报告

故障根因结论:对于子请求10.244.1.254:50332->10.244.5.79:15679 rtt指标出现200ms左右的延时

如何集成 DeepFlow 的数据增强网络故障的解释力

故障的推理验证

由于Kindling-OriginX 已经识别出是seat-service调用config-service的网络有问题,所以不用完全把 DeepFlow 的火焰图所有数据呈现给用户,只需要与 DeepFlow 对接,仅仅拿到seat-service调用config-service那段网络调用的相关数据即可。

利用 DeepFlow 的seat-service调用config-service数据自动分析出了客户端pod的容器网络出现了201ms的延时

如何集成 DeepFlow 的数据增强网络故障的解释力

Kindling-OriginX 会模拟专家分析经验,进一步关联DeepFlow的重传指标与RTT指标,从而确定到底是什么原因导致了seat-service调用config-service出现了延时的现象。

如何集成 DeepFlow 的数据增强网络故障的解释力

Kindling-OriginX 还会集成node的CPU利用率以及带宽指标,排除干扰因素。

如何集成 DeepFlow 的数据增强网络故障的解释力 Kindling-OriginX 将整个故障推理都在一页报告中完成,并且每个数据来源都是可信可查的。


总结

Kindling-OriginX 与 DeepFlow 都使用了 eBPF 技术,立求在不同的场景中为不同需求的用户提供灵活高效解决方案,也期待未来能看到国内有更多能力互补产品的出现。

DeepFlow 能提供非常完备的全链路网络基础数据,能够让云原生应用具有深度可观测性,对于排查网络问题非常有用。

Kindling-OriginX 是利用eBPF采集排障北极星指标、AI算法和专家经验构建故障推理引擎,给用户提供可解释的根因报告。

排障指标革命性新突破,北极星指标让故障无所遁形--北极星因果指标产品正式发布

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

传统排障方法的局限性

传统故障排查的痛点

在复杂的分布式系统中,故障排查一直是一个让人头疼的问题,其中机器宕机、进程存活、程序异常报错等故障相对而言比较好排查,有直接的指标能够反应出问题,难排查的问题是流量突增,时延变化等故障,特别是在分布式系统中,这类故障更难排查。传统的方法往往需要工程师逐一排查各种可能性,耗费大量时间和精力,效率低下且盲目。

传统故障排查方法的低效性主要源于以下几点:

  • 时间消耗巨大: 需要逐一检查系统中的各个组件和指标,排查流程繁琐,耗时长。
  • 盲目性: 没有明确的线索指引,排查过程中往往需要凭借经验和直觉,试错成本高。
  • 数据分散: 各类监控指标彼此独立,缺乏统一的视图,导致难以全面了解系统状态。

这些痛点的根源在于我们所使用的指标大多是结果性指标,指向性不明确。例如,CPU利用率、内存使用率等指标只能反映系统的当前状态,却无法直接指出问题的根源,给故障排查带来了巨大的挑战。

常规的指标局限

在实际应用中,工程师们常常依赖于各种常规的性能指标,例如:

  • CPU指标: 反映系统的计算资源使用情况。高CPU使用率可能是由于多个原因导致的,例如某个服务在进行高计算密集型操作。但是,CPU指标并不能告诉我们具体是哪个请求导致了高CPU使用率,通过人为分析才能知道是哪个进程的CPU使用率高,然后借助更多的工具才能知道可能是哪一段代码导致的,但是业界还缺少业务视角关联,没有办法知道哪个URL导致了CPU升高。
  • 网络指标: 反映网络传输的性能。无法明确是哪一个具体请求导致的带宽占用,例如一个文件服务器在处理多个文件上传和下载请求。网络指标只能显示整体的网络带宽使用情况上升,却不能确定是哪个具体请求导致的带宽占用增加,也缺少业务视角关联。
  • 文件指标: 反映磁盘I/O操作的效率。高磁盘IO使用可能是因为某些请求涉及大量的文件读写操作。然而无法具体指明是哪一个请求导致的磁盘IO高使用,缺少业务关联视角。
  • 内存指标: 反映系统的内存使用情况,同理缺少业务关联视角。
  • GC指标: 反映垃圾回收的频率和时间,同理缺少业务关联视角。

虽然这些指标在一定程度上帮助我们了解系统的运行状态,但它们彼此独立,无法构建出一个完整的故障图景。这种独立性导致了以下问题:

  • 无法关联: 各个指标之间缺乏关联,难以看出它们之间的因果关系。
  • 片面视角: 只能看到单个指标的表现,无法形成整体视图。
  • 低效排查: 无法通过单一指标判断问题的根源,需要逐一排除各种可能性,效率低下。

常规指标的这种局限性导致在排障过程中,我们常常需要逐一排查每一个可能的原因,耗费大量时间和精力,难以快速定位问题。


北极星指标带来的革命性变化

业界提供因果性的工具

为了应对复杂系统中的故障排查问题,业界提出了一些具有间接因果性的工具。然而,这些工具和方法也有其局限性:

  • 分布式追踪(Distributed Tracing):

优点: 提供请求的完整路径信息,详细展示每个服务调用的耗时,帮助识别系统中的延迟和瓶颈。

局限性: 在稍微复杂的场景下,因噪音和故障级联的存在,瓶颈点经常会被误判。需要结合业务逻辑和经验分析,才能推断因果关系,找到真正的瓶颈点。

  • 依赖图(Dependency Graph):

优点: 展示系统组件之间的依赖关系,便于理解系统架构,帮助识别关键路径和潜在的瓶颈。

局限性: 依赖图是静态分析工具,无法实时反映系统运行状态。随着系统规模的增加,依赖图的复杂性也增加,难以管理和维护。

  • 日志(Logging):

优点: 详细记录系统运行状态和事件,便于追踪和分析,具有高度的定制性,可以记录各种所需的信息。

局限性: 需要精心设计和管理日志记录策略,否则会产生大量无用数据。分析日志数据需要强大的工具和技术,如ELK栈。日志数据分散,难以直接构建因果关系,需要结合其他数据进行综合分析。

  • 事件监控(Event Monitoring):

优点: 可以实时监控系统中的各种事件,如错误、警告等,帮助快速响应和处理异常事件。

局限性: 事件监控通常是离散的,难以直接构建事件之间的因果关系。需要结合历史数据和上下文信息进行分析和推断。

利用eBPF技术获取北极星指标

北极星因果指标的获取依赖于先进的分布式追踪技术和内核级数据关联。具体过程如下:

  1. 分布式追踪: 首先,通过分布式追踪技术,捕获每个请求的完整路径信息。这包括请求在不同服务节点之间的传递和处理时间。
  2. eBPF在内核追踪线程信号: 在系统内核中,追踪执行请求的线程信号。这些信号反映了线程在处理请求过程中的各个状态变化和资源使用情况。
  3. eBPF在内核实现系统调用信号关联: 将分布式追踪数据与系统调用信号关联起来,形成对请求处理全过程的详细分解。这一步骤涉及将应用层的请求数据与内核层的系统调用数据进行关联,确保每个请求的所有资源使用情况都被捕获和分析。

通过这种方法,我们能够生成北极星因果指标。该指标不仅提供了各个性能指标的详细数据,还展示了它们之间的因果关系,从而帮助工程师快速定位故障根源,提升排障效率。

北极星因果指标的组成: 一次业务视角的请求耗时被完美且完整拆解成以下指标

CPU耗时

  • 定义和意义

○指请求在CPU上消耗的时间。

  • 如何影响请求处理

○高CPU耗时可能指向计算密集型任务比如循环和递归。

网络耗时

  • 定义和意义

○指请求在网络传输中消耗的时间。

  • 如何影响请求处理

○高网络耗时可能指向网络延迟、带宽不足或下游节点代码执行异常,典型的就是SQL语句执行慢。

文件读写耗时

  • 定义和意义

○指请求在文件系统读写操作中消耗的时间。

  • 如何影响请求处理

○高文件读写耗时可能指向磁盘I/O瓶颈或文件系统问题。

内存消耗耗时

  • 定义和意义

○指请求在内存分配和管理中消耗的时间。

  • 如何影响请求处理

○高内存耗时可能指向内存泄漏、内存分配不当或频繁触发Pagefault。

锁耗时

  • 定义和意义

○指请求在等待锁资源中消耗的时间。

  • 如何影响请求处理

○高锁耗时可能指向锁争用、死锁或锁机制设计不合理, 绝大多数都是代码类库使用了隐藏锁而开发人员不自知,比如数据库连接池锁等。

GC耗时

  • 定义和意义

○指请求在垃圾回收过程中消耗的时间。

  • 如何影响请求处理

○高GC耗时可能指向内存管理不当或垃圾回收频繁触发。

CPU调度耗时

  • 定义和意义

○指请求在执行过程中,由于CPU调度而产生的延时

  • 如何影响请求处理

○高CPU调度耗时,意味着容器的CPU资源不充分。

为什么北极星因果指标是排障的最关键指标

基于北极星因果指标排障,立刻获得了多个性能指标的关联分析结果,有了系统的整体视图。

北极星因果指标具有以下独特优势:

  • 因果性:

○北极星指标通过数据关联和因果关系分析,提供了请求处理过程中的详细分解。各个指标之间的因果关系明确,能够帮助工程师快速定位问题根源。

  • 全面性且无盲区遗漏:

○北极星指标覆盖了请求处理的全过程,从CPU耗时、网络耗时、文件读写耗时,到内存消耗耗时、锁耗时和GC耗时,确保了指标的全面性并且没有盲区。

  • 高效性:

○通过提供因果关系视图,北极星指标可以快速定位故障根源,减少排障时间和降低排障复杂性。工程师无需逐一排查每一个可能的原因,而是能够通过整体视图快速确定问题所在。

  • 一体化视图:

○北极星指标将多个独立的性能指标整合为一体化视图,便于综合分析和决策。这样,工程师在查看指标时,不再需要切换不同的监控工具,而是可以在一个视图中看到所有关键性能指标及其关联关系。


总结

北极星因果指标的引入,彻底改变了故障排查的方式。通过提供因果关系和全面视图,它不仅提升了排障效率,还显著减少了排障过程中的盲目性和试错成本,真正实现了高效、精准的故障排查。

●永久免费

●多语言支持:Java、Python、Nodejs、一键安装

●标准PQL语句查询数据

故障推理引擎加持下的告警理念转变

· 阅读需 10 分钟

在故障推理引擎加持下如何实现减少告警,做到精准告警

在 Kindling-OriginX 中只有业务请求受到故障影响才会告警,其他时候指标异常、故障都不会告警。为什么要这样设计呢?主要有以下几个主要原因:

  • 传统基于指标的告警:误报与漏报的告警非常多,信噪比非常高,会导致运维人员疲劳而忽略了真实的告警,而延误了告警的处理时间,导致严重的故障后果。
  • 基于指标的告警的本质是基于经验的设计告警的大杂烩,每个运维团队的告警都是在不断采坑中,不断完善指标告警,但是这个告警处理依赖于设计这个规则的人。但是人员是流动的,这些经验往往不会及时调整,而是不断累积,形成一个庞大而复杂告警体系。
  • 庞大而复杂的告警体系中,多指标是在技术上其实关联的,但是由于指标告警的时候是没有理解其内在关联性,一旦真实故障产生,各种误告警会不断产生,引发告警风暴。
  • 告警还有一个作用,就是当业务发生真实告警之时,期望指标告警能够为故障定位提供指导,但是没有专家经验治理的情况下,会产生告警太多的困惑,到底哪个是因,哪个是果不清楚,该往哪里排查也不清楚。

在Kindling-Originx中不需要传统告警提示排查方向

Kindling-Originx的核心能力就是故障根因推导,能够分钟级甚至秒级出故障报告,直接给出故障定位的初因。在这种情况下,无需配置指标告警来提示根因了,用户直接在故障根因推导的报告中能够得到定位的初因,同时也能够完整查看故障根因推导的过程,看出在整个推导过程中,有哪些指标是异于平常,同时可以通过Grafana大盘去观测更多的相关指标,进一步确认故障根因推导的正确与否。

基于API的SLO告警是Kindling-OriginX的使用入口

为了能够在生产环境中真正完成“1-5-10”,即1 分钟发现-5 分钟处置-10 分钟恢复的目标,通过 Kindling-OriginX 用户只需要设定和关注 API的SLO,并通过 SLO 关注系统状态结合 Kindling-OriginX 精准高效的故障根因分析技术,就能够使用户在极短的时间内响应并解决问题,发现各种隐患。这意味着即使是没有深厚技术背景和强大专家团队的用户也能够利用 Kindling-OriginX 来达成“1-5-10”目标,大大降低了技术门槛,提升了效率和可靠性。

推荐步骤

  1. 定义 API SLO (系统默认以历史数据设定)
  2. 当 SLO 违反时,查看对应时间段所生成的故障报告
  3. 根据故障报告内的根因分析数据,定位并解决问题,或根据推荐操作启动对应处置方案。
  4. 针对存疑根因分析结果,查看其详细推导数据与过程。

推荐流程

flow2.png

通过 Kindling-OriginX 只需要简单几步就能在不改变组织内原有应急策略和响应流程的情况下,快速提高故障发现速度与故障处理时长,帮助用户找到切实有效的方法落地实践“1-5-10”。

直接使用 Kindling-OriginX 基于SLO业务级别的告警,是否会有滞后性,是否会导致早期潜在故障发展成严重故障?

例子:传统运维视角,配置了JVM内存使用量告警,一旦JVM内存使用量达到一定阀值意味着内存可能存在泄露的可能,JVM内存使用量告警可以及早的请相关人员介入,避免潜在的风险演变成严重的内存OOM问题导致用户在业务接口上延时和错误率上升。

对于所有存在潜在问题发展成严重事故的故障,都会遵循以下的演变规律:

  1. 初始阶段(无明显影响)
  • 比如CPU使用率高:一开始,系统可能有足够的资源来处理增加的负载,所以高CPU使用率不会立即影响业务性能。
  • 比如内存泄露:同样,内存泄露在早期可能不会立即耗尽可用内存,因此不会直接影响业务请求的处理。
  1. 渐进阶段(轻微影响)
  • 随着时间的推移,如果CPU持续高负载运行,可能会导致处理能力下降,开始影响到处理请求的速度,出现轻微的延时增加。
  • 内存泄露逐渐消耗更多内存,开始影响系统的性能。这可能首先体现为偶尔的性能下降或轻微的延时增加。
  1. 加速阶段(逐渐增加的影响)
  • CPU使用率高:随着系统负载的继续增加,CPU可能无法有效地处理所有请求,导致响应时间显著增加,甚至影响到其他并行运行的服务或应用。
  • 内存泄露:内存消耗接近或达到系统上限时,可能导致内存不足,影响到新的请求处理,甚至引发系统的虚拟内存使用,进一步降低系统性能。
  1. 临界阶段(严重影响)
  • 此时,系统可能变得过载,无法有效响应请求,导致大量请求延时显著增加,错误率上升。
  • 在极端情况下,系统可能完全无响应或崩溃,需要重启或其他紧急措施来恢复服务。
  1. 恢复和分析
  • 一旦问题被识别并解决(如优化资源使用、修复内存泄露问题),系统性能会逐渐恢复正常。
  • 通过分析导致问题的根本原因和过程,可以采取措施预防未来类似问题的发生。

传统的指标阀值告警模式也许能够在初始阶段就告警,从而为潜在风险提供更多的处理时间,如果告警能够做到精而准确实能够帮助用户争取更多的时间来处理潜在的风险。但是实际情况往往是告警误报过多,从而导致疲劳忽略了告警,别说争取时间了,就是故障已经发展到3或者4阶段的告警都可能被忽略,反而影响了告警的高效处理。

目前 Kindling-OriginX 基于SLO围绕业务告警,针对慢性问题发展成严重故障,基本上做到在3阶段-加速阶段实现告警,这个时候告警完全有时间进行快速处理。未来 Kindling-OriginX 争取发展到2阶段,在早期尽量给用户争取更多的时间来处理潜在的风险。