写点什么

随手记统一监控平台 Focus 设计解析

2018 年 11 月 27 日

随手记统一监控平台Focus设计解析

应用监控是多数互联网公司最重要的基础设施之一,其意义不仅在于可以帮助开发人员应对分布式环境下的 Trouble Shooting 和性能管理难题,更是系统可用性的第一步。Focus 是由随手记研发的统一应用监控平台,承载了随手旗下随手记、卡牛两款产品数百个服务的应用监控任务。本文将对 Focus 的设计思路和关键实现进行剖析。(本文根据 2018 年 10 月张越在 QCon 上海站的演讲整理而成,有一定的补充和删减。)


监控的体系

“监控"是一个宽泛的概念,代表了很大的一块领域,有很多独立的系统在其中发挥作用。在介绍具体内容之前,我想先阐述一下通常互联网公司的监控的体系是什么样的。



一个完整的监控体系通常至少包含以下三个层次的监控:


  1. 系统层监控:用户为基础运维人员,面向机器视角,关注机器的 CPU、磁盘、IO 等。

  2. 应用层监控:用户为开发人员或 DevOps 人员, 面向应用视角,关注应用程序的可用性,不仅要求能够发现故障,还要提供线上故障原因排查和性能调优。

  3. 业务层监控:用户为运营人员,面向业务视角,关注业务的关键指标如下单率,转化率。对可视化有较高要求。


在实际运用中,运营和开发人员都会关注业务指标,如果业务指标异常,则首先 check 应用监控了解是否系统原因导致,如不是则可能是外部原因如营销活动、渠道问题等。开发人员在日常 DevOps 活动中则重度依赖应用监控,任何动作都需要确保对线上的影响是可控的。若发生问题时问题根因指向系统层面,则运维 check 系统监控是否存在系统级问题,如磁盘满,网络抖动。


以上就是一个互联网公司的典型监控体系,本文介绍的 Focus 系统是一个应用层监控系统,专注于为开发人员提供线上应用的故障排查与性能管理能力。


诞生背景

开源社区在监控体系内各方向上均有成熟的产品贡献。和大多数公司一样,随手记最也选择基于开源产品来组建应用监控系统,并摸索实践了 1 年多的时间。直到架构发展到如下阶段:



在这个阶段我们实际搭建了三个子系统作用于日志、调用链和指标的处理,并且通过二次开发的方式对其进行了很多适用性和易用性改造,基本实现了开发人员的常见需求。但我们的问题还没有解决完,当我们想要更进一步的时候我们遇到的问题是:


  1. 接入和使用横跨多个系统,无法互联互通,效率低;

  2. 无法形成统一连贯的排障步骤,信息无法充分利用;

  3. 无法继续演化和扩展,一些问题和需求需要深度整合开源产品;

  4. 架构太复杂,由十几个组件拼装而成,系统很脆弱。团队维护工作繁重。


因此我们在 2017 年决定使用平台化手段解决上述问题,开始着手建设统一监控平台。力求整合资源,统一处理,用一套系统解决应用监控问题。Focus 就是为满足上述目的开发的监控平台,目前承载着“随手记”、“卡牛”两个产品近千个核心服务的应用监控任务。


设计理念

监控系统本质是一个采集和分析系统,设计上则要遵循分析指导采集的思路。应用监控的难点就在于不仅要回答“有没有问题”,还要回答“是什么原因”。我认为要回答好这两个问题,至少需要以下 3 个维度的信息做支持:


  • Transaction 事务 :一个应用系统必然是为了完成某样事务存在的,那么它的事务完成的如何? 例如对请求的响应是否成功,每个环节性能快慢?可以说事务执行情况代表了应用的可用性。

  • Event 事件:应用内部发生了什么事情? 例如是否有异常发生?是否发生过主从切换?事件溯源为解决问题提供重要的细节信息。

  • Stats 状态 :应用内部的状态如何? 例如当前队列的长度? 线程池空闲线程数?一共处理了多少数据? 状态的观测和预测在发现问题方面非常有用。


Focus 不仅要满足对这三种监控信息进行的采集和分析,还要利用它们之间的配合来组成一个完善的故障排查逻辑。通过数据来支撑工程师做出判断,逐步收敛和排除噪声最终过滤出根因,这是 Focus 系统能够高效排障的思路。



实现方面,平台化的核心优势是可以进行多种数据的联合分析与展现。在出报表上做到原先单一系统做不出的报表,提供更有力的决策数据;在报表的规划上则可以做完整排查逻辑并衔接成清晰的排查步骤,提升故障排查能力。



举例来说,当用户接到一个告警,在系统中的操作路径是:


  1. 检查依赖拓扑报表,确定依赖和被依赖的服务正常,问题是自身问题;

  2. 跳转到状态报表,发现应用平均响应时间异常,划选异常时间段;

  3. 跳转到事务分析报表,通过响应排行发现该时间内 A 接口响应时间严重变慢;

  4. 在 A 接口慢事务 Top 排行中选中一条具体事务,观察该事务的瀑布图,发现是数据库查询方法慢;

  5. 跳转到该处日志,发现是意料外参数导致的全表查询。


整个排查过程思路清晰且每个跳转均提供有力的数据支撑,没有多余噪音。该操作逻辑的背后则是多维数据的相互协作。


数据结构和处理设计

Focus 使用以下三种数据结构来承载对事务、事件和状态的落地:


  • 事务观测:基于 Google Dapper 理念的 Span 数据结构。 包含耗时和失败等事务状态信息,通过 Tracing ID 支持分布式事务。

  • 事件观测 :事件日志,KV 数据结构,可以附加任意多的额外信息。如果是事务内发生的事件则可以通过 Tracing ID 追溯到。

  • 状态观测:支持多维度和多值的时间序列数据结构。


在数据处理流程方面,Focus 设计为一个全量采集系统,但不支持全量数据检索。我认为全量数据检索是导致监控系统臃肿复杂的重要原因。在监控场景中,用户需要有代表性的数据以支持决策,而不是海量原始数据的直接检索。因此 Focus 从一开始就放弃了做全量数据存储的念头,只保留典型样本数据即可。这样的设计还降低了流量敏感性,在 11.11、除夕红包等大型活动下,业务流量突然增大不会导致系统存储压力有明显的变化。不过 Focus 保留了原数据实时供数能力 (Kafka)。在随手记内部,额外的分析需求是由单独的大数据系统负责的。


最终 Focus 的内部数据处理流程设计如下:



对目标的把握和清晰的设计思路让 Focus 面对海量数据流量时可以保持简单,高效,低成本。


架构设计


整体架构设计上,Focus 主要满足几个特点:


  1. 简单。Simple is powerful ,简洁架构让问题变的易于处理。系统一共只有 3 个组件,运行时额外依赖 Kafka 和 ElasticSearch 集群分别作为数据的 Hub 和 Store。原始数据由采集组件搜集并发送给 Hub,由 Hub 聚集后按照分区逻辑分发到对应的计算组件做实时处理或异常检测,处理结果再统一存储到存储组件中,最后由控制组件查询使用。

  2. 高吞吐。监控平台目前每天处理数百亿消息,整个处理过程不能存在瓶颈。数据处理主流程增量运算,能异步的地方都采用异步设计。另外整个架构是可扩展的,服务端以无状态集群的方式工作,可以通过投入机器的方式应对更大的流量。

  3. 实时性。监控数据时效性明显,越实时的消息越富有价值,因此系统应该尽量快的出结果。 Focus 是一个准实时处理系统,数据处理过程可完全不落盘,设计上尽量考虑时间因素,目前大部分告警可在 1 分钟左右发出。

  4. 高可用和自愈。监控平台是用来排查故障的,所以自身必须是高可用的且不易受到故障影响的系统。Focus 架构中没有单点问题,且服务故障时可自动剔除出故障的服务。

  5. 故障容忍。当监控系统出现问题,不能影响业务应用。Focus 存储被设计为次要组件,存储挂掉不影响实时增量统计和告警,服务端全挂掉不影响目标应用。

  6. 部署简单。Focus 设计为可以开箱即用,只需要一个简单的命令就可以启动并在集群中发挥作用,不需要复杂的配置和学习。这样面对多个环境部署时就不那么痛苦。另外开发时也很容易在本机启动起来。

  7. 最后整个架构是演化而来的。2015 年的时候我们只做到了 Version 1.0 当中的组件 (编码为 1 的组件)。 在后续几年的演化中逐步形成了现在的架构,系统也由一个 ELK 型的日志系统演化为了一个完善的 APM 系统。


服务端设计


Focus 服务端本质上是一个流计算系统。而如何化解流计算系统固有的挑战是主要设计问题。我主要讲以下几个关键问题的决策:


  1. 数据状态问题。分布式服务的状态处理是设计中的重点,我们通过简单的数据分区处理方式,让同一个维度的数据进入同一个 Partition。这样计算服务就可以无状态,无状态的好处是可以任意扩展,且避免了服务间的通信等一系列困难。但是分区模式会带来热点问题,这一块我们目前通过更细粒度的分区来缓解。

  2. 异构数据处理。Focus 的数据处理要支持 3 种不同的数据结构,即需要 3 套 Pipeline 来处理。 而 Focus 的服务端是同构设计的,这样的设计更利于运维的简化,因为同构服务的集群可以被抽象为一个服务去管理。为了做到这一点,每个实例都会同时运行截然不同的计算任务,会导致算力不均。为此我们设计了一个算力调度模块,可以动态或手动调整算力分配。

  3. 故障自愈。流计算也就是实时增量计算,它不像离线计算,Job 出错了大不了再跑一次。增量运算对可靠性提出了更高的要求。在故障处理设计中,Focus 依赖 Kafka Rebalance 机制来实现故障转移。当某个实例出现故障,Kafka 会将原本由其负责运算的数据 Rebalance 到另一个正常的实例从而保证消费不会中断。

  4. 流计算框架选型。在上述约束下,最终我们发现 Kafka Streams 非常适合我们的场景,尤其是 Kafka Streams 作为一个 Library 而不是 Platform 和我们的设计非常匹配。此外它还帮我们做到了 Exactly-Once 语义,以及提供了基本的如 Window 和回填机制等工具,使得开发 Pipeline 的过程非常愉快,代码变的非常简单。

  5. 齐全度。最后关于齐全度的问题,我们的流计算基本机制还是靠 Window。 那么就存在有的数据早到有的数据晚到的情况,如果数据还没到齐全,这个 Window 就关闭了推去计算了,就可能漏算从而造成误告警。 这部分我们目前使用的还是简单粗暴的等待方案,Window 会等待 3-5 个周期,如果超过这个等待周期还不来,则等同于发生了问题。


存储设计

由于 Focus 同时处理 3 种异构数据,并且每一种数据结构的吞吐量都非常大。在早期设计中为了接纳这些数据存储需求,使用了不同的针对性数据库产品。最多的时候平台需要依赖 4 种不同的数据库产品才可以跑起来。这带来了很大的存储方面的复杂性,于是我们开始想办法着手简化。


存储的问题在于:需要用一个数据库支持三种数据结构的高性能存储。考察了一圈,我们决定使用 ElasticSearch 作为低层引擎。理由是 ElasticSearch 可以很好的存储 Span 和 Log 数据,并拥有胜任海量时间序列存储和检索的基础特性:


  • 高效的倒排索引机制。

  • 列存储能力,并且可以对列存储进行压缩。

  • 强大的聚合能力和非物化视图的特性,可塑性高。

  • 扩展非常简单,还支持并行运算。

  • 在合理的优化下,速度很快。



依靠 ElasticSearch 的强大可塑性,我们在其上设计了一个装饰层。 通过装饰层,ElasticSearch 将作为低层存储引擎按需提供以下几种形态的服务:


  • 先进高效的时间序列数据库。

  • 专为 Trace 存储和检索设计的链路数据库。

  • 日志全文检索库和存储库。



以时间序列为例,上图为列举的一些大块的优化点,在装饰服务的针对优化下,最终我们做到了压缩比 10:1 的时序存储,单节点~1w 读和~12w 写的性能,90% 的聚合查询都可以在 2 秒内返回结果, 并且支持复杂聚合查询。 这个结果在我们的场景中相比 InfluxDB 也是毫不逊色的。


客户端设计

Focus 客户端会一次性把全部需要的信息采集到,包括 Span、Log、Metric 和一些 Metadata。是一个一站式采集客户端。


在接入方面提供针对事务、事件、状态的三套埋点 Low-Level API。开发人员可以按需埋点满足个性化需求。在 Low-Level API 的基础上,Focus 提供常见中间件的预埋点包,大多数应用的接入都只需要引包即可,甚至可以不需要配置文件。


在设计上我们让客户端尽量的简单,只做好采集这一件事情就可以了。因此放弃了一些有诱惑力的想法,包括在客户端进行聚合、配置下达、字节码修改等。事实证明这样带来了很多好处:客户端更不易出错且设计稳定不易变化。出错和易变是客户最不愿意接受的;整个客户端的逻辑很少且容易理解,在开发跨语言客户端和用户自行扩展时都非常的容易;另外性能也很容易做到很高。


在实现上客户端的整个处理步骤都是异步的,减轻对业务的影响。 优化方面手段主要是针对队列和序列化的优化、对消费线程唤醒的控制、以及严格控制内存和对象的使用,防止因为监控导致 GC。



总结

事实上监控系统内的设计决策远不止这些,篇幅所限就不全部介绍了。最后我总结了一些在进行监控系统设计时的心得可以供大家参考:


  • Simple is powerful 少就是多。做设计抉择时,只有一个核心评判标准:哪个方案更简单。

  • 不要让客户端做太多事情。我们曾经维护了一个功能强大而智能化的客户端,直到不得不下决心重做。Focus 版本越高的客户端功能反而越少。

  • 考虑全量存储的必要性。存储很容易成为系统的瓶颈,我们尝试在全量存储上做优化,后来发现 90% 的信息都没人看,于是我们转变了思路。

  • 利用开源工具来实现你不感兴趣的部分,只做感兴趣的那部分就行了。 Focus 把很多枯燥困难的工作都甩给 Kafka 和 ES 来解决了:) 。

  • 为目标设计。先了解用户想看什么并为此设计报表,然后为了实现该报表而反推数据处理和采集设计。错误的思路:采集一堆数据再进行数据挖掘最后看看能出什么报表。

  • 不追求完美。勇于把不完美的东西发布给用户用,吐槽是必然的,但有用户才有演化的方向。


最后我想说 Focus 仍然在不断的迭代中,很多设计取舍也和公司规模和具体场景有很大关系,所谓抛砖引玉,欢迎大家和我们交流。


活动推荐:


12 月 7 日北京 ArchSummit 全球架构师峰会上,来自蚂蚁金服、大树网络、北京银行、中邮消费金融 的讲师齐聚一堂,共同分享“金融移动架构”、“关系网络”和“灵活可靠金融系统”等金融技术相关经验与实践。详情点击 https://bj2018.archsummit.com/schedule


2018 年 11 月 27 日 10:583488

评论 1 条评论

发布
暂无评论
发现更多内容

极客时间架构师训练营第一周学习总结

爱码士

课程总结

两个程序员老友的会面

Philips

敏捷开发

作为一名Java程序员,技术栈的广度深度都不够还想要高薪?请先把这些技术掌握再说。

Java架构之路

Java 程序员 架构 面试 编程语言

架构师训练营培训第一周总结

lakers

极客大学架构师训练营

Spring 5.2.7和SpringBoot 2.3.3中文翻译发布啦!!!

青年IT男

spring springboot

网易:Flink + Iceberg 数据湖探索与实践

Apache Flink

flink 数据湖

2020,国产数据库崭露峥嵘的发轫之年

墨天轮

数据库 阿里云 华为云 SQL优化 活动专区

1分钟带你入门 React SCU、memo、pureCom

Leo

react.js 前端 React 前端进阶训练营 前端性能优化

架构师训练营 1 期 - 第五周 - 技术选型

三板斧

极客大学架构师训练营

【API进阶之路】研发需求突增3倍,测试团队集体闹离职

华为云开发者社区

软件开发 开发 开发测试

LeetCode题解:50. Pow(x, n),暴力法,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

USDT承兑商支付系统开发,区块链跨境支付源码

135深圳3055源中瑞8032

合约跟单软件开发,一键跟单系统搭建

135深圳3055源中瑞8032

了解HashMap数据结构,超详细!

程序员的时光

面试 hashmap HashMap底层原理

第五周学习代码技术选型总结

三板斧

极客大学架构师训练营

阿里18道常见的MySQL面试题,含解析

Java架构师迁哥

区块链多币种钱包开发服务商,多币种钱包APP

135深圳3055源中瑞8032

不会java的人能不能读《Head First设计模式》?

Nydia

为什么说容器的崛起预示着云原生时代到来?

华为云开发者社区

容器 云原生 容器云

技术都是相通的

小黄鱼

极客大学架构师训练营

我从高级开发者身上学到的19条编码原则

Java架构师迁哥

开发一个交易所需要多少费用?币币交易系统

135深圳3055源中瑞8032

一周信创舆情观察(10.12~10.18)

统小信uos

架构师训练营第一周作业

爱码士

架构设计

技术体系的构成

异想的芦苇

技术 技术管理 研发体系

Java高并发编程的一本百科全书《Java高并发编程详解:多线程与架构设计》,把Java语言中最为晦涩的知识点都详解出来了!

Java架构之路

Java 程序员 架构 并发编程 编程语言

华为云如何赋能无人车飞驰?从这群AI热血少年谈起

华为云开发者社区

人工智能 无人驾驶

想自己写框架?不会写Java注解可不行

Java架构师迁哥

MyBatis-技术专题-拦截器介绍

李浩宇/Alex

普通人如何站在时代风口学好AI?这是我看过最好的答案

华为云开发者社区

AI 算法

大数据上手实战!训练营“9营齐开”第二季限时免费报名啦

Apache Flink

大数据

「中国技术开放日·长沙站」现场直播

「中国技术开放日·长沙站」现场直播

随手记统一监控平台Focus设计解析-InfoQ