去哪儿网异常统计分析实践——Heimdall
作者介绍
沙丹丹,17 年加入去哪儿,致力于提升研发和测试人员的效率,在 CICD、测试工具领域有一定的经验,目前在基础架构—基础平台团队负责测试工具的开发和维护工作,包括接口自动化测试、全链路压测、异常日志统计等。
一、背景
随着业务发展和微服务架构的普及,企业内微服务拆分粒度越来越细,服务间调用关系错综复杂。对于一些复杂的,比如机票和酒店售卖业务场景,可能动辄涉及上百个应用,当某个系统发生异常时会导致多个服务受到影响。此时 APM 系统就派上了用场,监控(Metrics)、调用链(Tracing)、日志(Logging)帮助业务同学快速定位问题。普通的业务监控报警能起到快速发现问题的作用,但具体 case 的排查还需要研发人员通过异常栈信息来分析,比如数据库连接异常、空指针等等。
去哪儿网很早就有了监控系统 Watcher,能够起到快速提醒业务响应异常的作用,然后开发同学排查是接到报警的系统本身的问题还是下游依赖的系统的问题,如果是下游系统的问题,就要这样一层层地找下去,有时候定位问题时间会比较长。当某个系统出现问题时最根本的表现就是产生异常,如果能直接提示开发同学系统产生了新的异常,或者异常量上涨了,就能够大大缩短开发同学排查问题的时间,做到快速恢复故障。
去哪儿网有一套完整的日志收集和查看体系,首先应用通过日志打印框架将日志打印到本地 log 文件,机器上默认安装日志收集的 agent,将日志内容通过 kafka 上报,再通过 ELK 提供日志存储和查询的能力。如果能够自动地、快速地识别异常,并将日志堆栈内容直接提醒给研发同学,将会大大提高解决问题的效率,甚至防患于未然。因此,异常统计分析系统——Heimdall 应运而生,主要目标如下:
1. 分钟级别的异常统计
2. 发布过程中展示同比环比
3. 支持添加监控报警
4. 支持用户自定义时间范围查询
5. 能够展示异常栈
6. 支持应用和机器级别的异常统计
整体的演进包含两个阶段:
1. 基于实时日志收集的建设
2. 基于基础组件的改造,以在业务服务端直接拦截并上报异常的方式进行了改进
以下分阶段进行阐述。
二、实践框架
1. 阶段一:基于实时日志收集的建设
1.1 技术栈
实时日志收集 kafka+大众点评开源工具 CAT+FLINK+Heimdall 平台
1.2 架构图
图 2-1 架构图
1.3 核心模块介绍
1.3.1 clog 模块
clog 模块主要负责异常栈的接收、存储和查询。消费 kafka 消息接收日志,解析出 ERROR 级别的日志,并将其关联的应用、trace、日志详情、时间戳等相关信息一并存储起来,再将转换成统一格式的日志以 kafka 消息的形式发出,待 flink 任务消费并做进一步解析。clog 的存储结构分为三层:本地磁盘(临时存储)+ES(做文件索引)+HDFS(持久存储)。这样的存储结构保证了热数据的快速查询和冷数据的持久存储。
存储:首先全部的实时日志都会按 bu 发送到 kafka,clog 以二进制流的方式消费此 kafka 消息,然后经过 MessagePackDecoder 进行解析,解析出日志级别、AppCode、traceId 等信息,组装成固定格式的日志内容。再由 BlockProcessor 为每个 DataBlock 构造出索引用于查询,EsIndexManager 将索引保存到 ES 中,数据部分 DataBlock 保存到本地文件,定时转存到 HDFS 做持久存储。
block position 格式定义:ip-保留天数-时间( yyMMddHHmmss )- offset,例如:10.xx.xx.xx-7-20211110185535-4625901837。
每个应用 5s 一个 block,一个 block 最大 8M,当本地磁盘空间利用率达到 75%,就上传到 HDFS。
图 2-2 存储架构图
查询:查询异常详情时先查询 ES,得到索引,根据索引判断本机是否存在相应的 blockPosition,如果是本机 ip 并且本地磁盘中存在,直接从磁盘读取数据返回,若是本机 ip 但磁盘中不存在,根据文件名、position、seconds 等信息查询 HDFS 。如果不是本机 ip ,则向索引中的 ip 发起远程 HTTP 请求,转化成对应 ip 的查询。
图 2-3 查询流程图
1.3.2 flink 任务模块
flink 任务主要用来进行异常信息的解析计算处理,将异常类型、应用、机器等相关信息提取出来,按分钟级别做次数统计,并打印异常指标到监控系统。
1.4 难点分析
(1)容器化后日志收集方式改变—容器化后的应用统计不到数据
近两年去哪儿在进行 KVM 到容器化的迁移,两者技术差异还是比较大的,日志收集的方式也进行了彻底的改变,包括 kafka 消息的形式和格式都变化较大,原有异常日志统计架构已经完全不能满足。因此,我们对异常统计分析的系统架构进行了调整,从源头异常日志收集到统计逻辑都做了重大改进。下面介绍改进后的架构。
(2)实时日志存在延迟—flink 数据统计不准确
由于日志收集属于非核心流程,当应用的日志量较大的时候,实时日志收集存在延迟的情况,有些日志的延迟甚至超过了 1 个小时。在异常日志统计时使用了 flink 的滚动窗口来进行计算,由于日志的乱序和部分日志延迟,导致这些日志被丢弃,造成统计数据不准确,误差将近 10%。
(3)实时日志收集的日志量巨大—消耗资源大
由于实时收集的日志本身是不过滤日志级别的,大量的非 ERROR 日志也会被收集。从使用角度上,这些非 ERROR 的日志并不是用户关心或者期望看到的数据,纳入异常日志统计并没有什么用反而会造成干扰,所以需要从大量日志中过滤掉非 ERROR 日志,这会耗费大量的计算资源。还有一部分是多个系统间传递数据,消耗在了跨系统传递无用信息的宽带上。
(4)非全量应用都有实时日志收集—有些应用不能使用此功能
由于公司内整套实时日志收集是 ELK,成本比较高,所以只有部分核心应用开通了实时日志收集,未开通的应用就没办进行异常日志统计和监控。
(5)未考虑环境隔离—掺杂仿真环境数据
公司内部根据不同使用目的和途径,存在多种不同的环境,包括 beta、仿真、灰度和线上,实时日志收集没有对环境进行区分,仿真、灰度和线上的日志都会被统计,而事实上仿真环境属于测试范畴,会对统计结果造成干扰,尤其是当短时间内进行大量自动化测试且引发异常的情况发生时,干扰会更加显著。
2. 阶段二:基于基础组件的改造
2.1 改进目标
(1)支持容器的异常日志统计。
(2)解决统计不准确问题。
(3)降低资源成本。
(4)应用范围要扩展到全司 java 应用。
(5)可以按照环境类型维度进行过滤。
2.2 改进策略
(1)将数据源从实时日志收集改成在业务服务端的基础组件进行拦截和上报异常。
(2)将从全量级别的日志中筛选异常日志改成直接在源头过滤,只上报带异常栈的日志。
(3)通过基础组件在业务服务端直接做好结构化,并做初步聚合(按异常类型做聚合,同种异常次数聚合,异常栈详情采样),减少冗余数据传输的资源消耗,kafka 集群 partition 从 60 个降低到 14 个,异常日志每秒消息量从 486K 降低到 106K。
(4)废弃 flink 任务(之前使用 flink 主要是做日志文本解析,数据源变更后,就不再需要了),开发新的统计服务。
图 2-4 改进后的架构图
2.3 核心模块介绍
2.3.1 logger-spi
负责在客户端进行日志采集、过滤、聚合、采样、上报。通过 agent 对 logger 进行插桩,并过滤出带异常栈的日志,然后将异常日志按照异常类型进行初步聚合,将 1min 内同一种类型的异常进行累加计数,并且对异常日志详情进行采样,最终将数据通过 kafka 消息上报。同时为了避免对服务造成过多损耗,当占用的内存达到限额时会直接上报到 kafka。我们将异常日志分为了业务异常( BusinessError )和系统异常。业务异常是指没有异常栈的,和业务流程相关的异常,比如:"没有该目的地的航班"等;系统异常是指没有系统业务含义的,带堆栈信息的异常。目前我们只关心系统异常,业务异常是直接过滤掉的。上报的数据结构如下:
模块详细架构图:
图 2-5 logger-spi 模块详细架构图
2.3.2 heimdall-statistic
接收客户端上报上来的异常日志初步聚合结果,在内存中按分钟进行统计并暂存储统计结果,并定时更新到 hbase 中,更新时先从 hbase 中查询出该应用、该分钟原有的异常数据,再与内存中的数据叠加,最后更新到 hbase 中。这种计算、统计方式与 kafka 消息到达的顺序无关,不管消息有没有延迟,只要消息没丢,就都能统计进去,从而保证统计数据和实际不会有偏差。统计数据包含以下四个维度:- 每分钟的异常个数- 每分钟每种类型的异常个数- 每分钟每个机器的异常个数- 每分钟每个机器每种异常类型的异常个数
三、效果展示
1. 指定时间段的异常类型及个数统计环比
图 3-1 某个应用指定时间段内的异常数据示例图
2. 可查看异常栈详情及 trace 信息
图 3-2 某种异常的详细异常栈信息和 trace 信息示例图
四、应用场景
基于我们提供的异常统计、分析和异常详情查看等基本能力,公司内部孵化了一些工具平台自动帮助业务系统定期进行服务治理和实时观测系统健康状态的工具,异常统计分析作为其中的一个重要数据源和评价、分析指标。下面列举了几个比较常用的场景:
1. 服务治理
将 AppCode 和 owner 对应起来,每周发邮件提示 owner 负责的系统的异常量,并制定规范、定义异常级别,比如 P1 的异常必须修复等,便于 owner 持续关注自身系统的健康状况。
图 4-1 发送给业务负责人的异常日志日报示例图
2. 与发布系统集成
在发布过程中,发布系统会调用 Heimdall 接口获取该应用及其上下游系统的异常量变化情况即异常环比,便于在发布过程中有问题及时发现、及时终止。
3. 异常检测报警
不仅是在发布过程中要关注异常量,在平时也会出现各种各样的突发情况,比如硬件故障、中间件故障、数据库故障、攻防演练等。因此基于 Heimdall 的基础数据,开发了实时地根据异常统计数据自动识别新增异常类型和异常数量环比上涨,并及时提醒给研发人员的工具,想要开通的应用可以自定义配置报警规则,比如环比上涨多少要报警等。能够进一步提升系统稳定性和研发人员排查问题的效率。
4. 故障根因分析
在发生故障时,很多情况下系统都会表现出异常,比如下游接口不通、数据库连接异常、空指针等等,如果系统中大量新增了某种异常,或者某种异常的环比突然增高,异常变化和指标变化的时间点相匹配,那么很可能和这些异常相关。故障根因分析效果数据:22 年下半年故障处理超时率 60.9%,23 年 Q1 故障处理超时率降到 38.8%(异常日志分析是其中一个分析项)。
图 4-2 根因分析平台定位问题示例图
五、 总结展望
目前 heimdall 系统已经接入 1300+应用,成为了研发质量中的一个重要指标,研发人员也养成了关注系统异常情况的习惯,为公司业务稳定发展提供技术保障。一个系统在诞生的时候基本上都会有一些没考虑到的点,并且随着周边环境的变化,原有的设计也会不满足,优秀的系统不是一成不变的,而是慢慢打磨、优化、改进、完善才形成的,每个时期和阶段都有它的价值。同时也要敢于突破原有设计的束缚,取其精华去其糟粕。异常量统计数据和异常堆栈的作用远不止于此,未来我们还会将 heimdall 的数据应用于中测试领域,将 heimdall 中已存在的异常作为基准,从 beta 环境的异常中过滤掉线上已有的异常,再将剩余的异常主动提示给开发或 QA 同学,提升联调测试过程中排查问题的效率,未来的使用场景还会更多!
版权声明: 本文为 InfoQ 作者【Qunar技术沙龙】的原创文章。
原文链接:【http://xie.infoq.cn/article/b2ac3bb1e8fd5d19a3eb9057e】。未经作者许可,禁止转载。
评论