2011 年底,我加入大众点评网,出于很偶然的机会,决定开发 CAT,为各个业务线打造分布式实时监控系统,CAT 的核心概念源自 eBay 闭源系统 CAL----eBay 的几大法宝之一。
在当今互联网时代,业务需求旺盛,开发团队往往采用 scrum 等敏捷开发流程,加班加点快速迭代以满足业务需求,是常态。采用分布式系统设计和服务化,由多台机器协作来共同完成用户请求,是典型的解决方案。网站故障频发,内部关系错综复杂,故障定位缓慢,甚至找不到问题根源,也是常有的事。虽然已经有很多日志监控工具,或许单个工具功能还不错,但整体服务化水平参差不齐,工具间不能互通互联;另一方面,由于日志数据量大,且分散,使得查找问题根源基本靠人品。
这些也是我们要开发 CAT 的初衷。
CAT 简介
CAT(Central Application Tracking),是基于纯 Java 开发的分布式实时监控系统。开源代码托管在 GitHub(搜索 CAT 即可),作者是吴其敏(qmwu2000)和尤勇(youyong205)。
产品相关分享在网上可以找到:
- 看大众点评如何通过实时监控系统 CAT 打造 7*24 服务 - 尤勇 @QCon 高可用架构群 2015
- 分布式监控系统的设计与实现 - 尤勇 @QCon 上海 2015
- 大众点评网监控系统架构剖析 - 尤勇 @2013 第二届华东架构师大会
- 大众点评网监控平台剖析 - 吴其敏 @QCon 杭州 2012
CAT 现状
CAT 采用非常开放的 Apache License 开源,在国内已经有 100 多家互联网公司在使用和评估,包括大众点评网、携程网、猎聘网、陆金所和找钢网等。截至 2016 年 3 月,CAT 已经获得了 1000 多个 stars。
设计目标
- 可扩展:支持分布式、跨 IDC 部署,横向扩展。
- 高可用:所有应用都可以倒下了,需要监控还站着,告诉它们发生了什么。
- 实时处理:信息的价值会随时间锐减,尤其是事故处理过程中。
- 全量数据:小概率事件是常态,百万分之一的概率,碰到了就是 100%。
- 高吞吐:要想还原真相,需要全方位的监控和度量,必须要有超强的处理吞吐能力。
- 故障容忍:CAT 本身故障不应该影响业务正常运转,CAT 挂了,应用不该受影响,只是监控能力暂时减弱。
- 不保证可靠:允许消息丢失,这是一个很重要的 trade-off,虽然目前 CAT 可以做到 4 个 9 的可靠性。
CAT 架构
架构追求简单**、去中心化、**分工协作,两层结构,除了依赖外部存储如 HDFS 和 MySQL 外,不依赖其他系统,CAT 内部全面采用组件化设计和实现。CAT 每天消息量巨大,一台机器是不能处理全部流量,必须分片处理,均衡负载。
业务应用目前使用 CAT API 进行埋点,后台异步线程采用 TCP 长连接方式,将消息源源不断地传输到后台服务器;CAT 具有 fail-over 机制,在后台服务器不可用时会自动切换到另一台可用服务器。CAT 目前使用 native 协议做序列化和反序列化,将来会考虑支持更多协议,比如 thrift。
消息被送到后台,经反序列化后会被放入队列,实时消费调度器会将消息分发到所有消费者内部队列,每个消费者只需处理自己的消费队列,各消费者之间彼此相对独立,如果消费速度太慢,导致消费队列满,则新来的消息会被丢弃。典型消费者都采用实时增量计算的方式,流式处理消息,产生的报表会在当前小时结束后保存到中央数据库中。
日报表采用后台作业的形式,由 24 个小时报表合并得到。周报表则由 7 个日报表合并得到,以此类推。
CAT 控制台,即 UI 层,负责接收用户请求,从后台存储中将报表信息取出显示。对于实时报表,直接通过 HTTP 请求分发到相应消费机,待结果返回后聚合展示;历史报表则直接取数据库并展示。
所有原始消息会先存储在本地文件系统,然后上传到 HDFS 中保存;而对于报表,因其远比原始日志小,则以 K/V 的方式保存在 MySQL 中。
消息处理
消息处理分五个阶段:收集、传输、分析、存储和展示。
收集阶段:负责业务应用日志的埋点和采集。CAT 目前提供多种语言的客户端供业务应用程序调用,埋点结果以消息树的形式存入传输队列。如果队列满,则会自动丢弃当前消息。
传输阶段:CAT 客户端负责将客户端消息传输到后端,CAT 消费机负责接收消息。传输前 CAT 客户端会与 CAT 消费机建立 TCP 长连接,不断地从客户端队列中取出消息树,序列化后写入网络;CAT 消费机则不断地从网络中取出数据,反序列化后放入消费队列。
分析阶段:负责报表生成。实时消费调度器会将消费队列消息取出,分发给每个消费者内部队列;报表分析器只会从自己的报表队列中取出消息树,逐个消费,更新报表模型。CAT 以小时为单位形成报表,原始日志转储 (raw log dump) 是一个特殊的分析器,它不生产报表,而是将消息存入本地文件系统。
存储阶段:负责报表和原始日志的存储,目前报表会存在 MySQL 中,原始日志压缩后存在 HDFS 中长久保存。保留时长取决于存储容量的大小,一般报表会保存 3 个月以上,原始日志保存一个月。
展示阶段:负责数据的可视化。作为用户服务入口,负责报表和原始日志的输出显示。对于实时报表请求,会向各个消费机分发请求,并将结果聚合后输出 HTML,在浏览器展示;历史报表会直接取自数据库。XML 数据输出是另一种内置的数据展示方式,方便基于 CAT 开放外围工具。
日志埋点
日志埋点是监控活动的最重要环节之一,日志质量决定着监控质量和效率。当前 CAT 的埋点目标是以问题为中心,像程序抛出 exception 就是典型问题。我个人对问题的定义是:不符合预期的就可以算问题。比如请求未完成,响应时间快了慢了,请求 TPS 多了少了,时间分布不均匀等等。
在互联网环境中,最突出的问题场景,我的理解是,跨越边界的行为。包括但不限于,HTTP/REST、RPC/SOA、MQ、Job、Cache、DAL; 搜索 / 查询引擎、业务应用、外包系统、遗留系统 ; 母 / 子公司, 第三方网关 / 银行, 合作伙伴 / 供应商之间;还有各类业务指标,如 PV、用户登录、订单数、支付状态、销售额。
CAT 提供 API 支持的语言有:Java,.NET,将来打算支持 C/C++、NodeJS、Go、PHP、Python 等。
领域建模
此模型可以覆盖大部分业务应用的日常埋点需求。各种类型都有个性化分析和展示。
消息树
CAT 消息树如实记录真实用户请求的处理时序,这些请求可能被分布在多台机器上。消息树可以丰富地表达嵌套关系、先后次序和并行处理,这将有助于开发者清楚的了解用户请求到底是怎么被一步步执行的,尤其在追踪一些疑难杂症时,这会特别有用。
只要遵循 CAT 埋点规范,CAT 会自动地将多台机器上的消息树串起来,可以逐层展示。
当然也有另一种更适合于人的视图,方便识别突出问题,毕竟人对图形识别更加擅长。
CAT API
API 力求精简,将来还有进一步优化空间。大部分 CAT 埋点应该在底层基础架构中完成,一般应用层不需要做大多埋点。有些产品使用如 java-agent 等方式埋点,CAT 埋点也可以采用,埋点质量取决于现有应用代码的规范程度和覆盖范围。
实时分析
CAT 的实时性不是用户要看什么,CAT 就实时计算出结果,呈现给用户;而是根据日志消息的特点 (比如只读特性) 和问题场景,量身定做的。CAT 将所有的报表按消息的创建时间,一小时为单位分片,那么每小时就产生一个报表。当前小时报表的所有计算都是基于内存的,用户每次请求即时报表得到的都是最新结果,给人一种“实时”的感觉。对于历史报表,因为它是不变的,所以就实时不实时也就无所谓了。
对于内存增量计算,它可以分为:计数、计时和关系处理三种。计数又可以分为两类:算术计数和集合计数。典型的算术计数如:总个数(count),总和(sum),均值(avg),最大 / 最小(max/min),吞吐(tps)和标准差(std)等,其他都比较直观,标准差稍微复杂一点,大家自己可以推演一下怎么做增量计算。那集合运算,比如 95 线(表示 95% 请求的完成时间),999 线(表示 99.9% 请求的完成时间),DAU(日活用户数)等,则稍微复杂一些,系统开销也更大一点。关系处理则涉及图的运算,这里不细述。
报表建模
了解增量计算很重要,但最终需要落实到各个不同的报表上。一个报表往往有多个维度,以 transaction 报表为例,它有 5 个维度,分别是应用、机器、大类、小类和分布情况。如果全维度建模,虽然灵活,但开销将会非常之大。CAT 选择固定维度建模,可以理解成将这 5 个维度组织成深度为 5 的树,访问时总是从根开始,逐层往下进行。
CAT 为每个报表单独分配一个线程,所以不会有锁的问题,所有报表模型都是非线程安全的,其数据是可变的。这样带来的好处是简单且低开销。
报表代码是使用自研的 maven plugin 自动生成的。所有报表是可合并和裁剪的,可以轻易地将 2 个或多个报表合并成一个报表。在报表处理代码中,CAT 大量使用访问者模式(visitor pattern)。
消息存储
消息存储是 CAT最有挑战的部分。关键问题是消息数量多且大,像大众点评和携程每天消息数在 300-400 亿左右,大小有 50TB,也就是说每秒消息数在 50-60 万上下,每秒大小在 1GB 左右。如果分 10 台机器处理,则每天每秒需要处理 5-6 万消息,100MB 大小。如果网站流量来点波动的话,挑战就更大了。由于时间关系,这部分今天就不细述了(感兴趣的同学,欢迎加群与吴老师一对一交流)。
总结
CAT 在分布式实时方面,主要归结于以下几点因素:
- 去中心化,数据分区处理;
- 基于日志只读特性,以一个小时为时间窗口,实时报表基于内存建模和分析,历史报表通过聚合完成;
- 基于内存队列,全面异步化,单线程化,无锁设计;
- 全局消息 ID,数据本地化生产,集中式存储;
- 组件化、服务化理念,致力于工具间互通互联。
嘉宾介绍
吴其敏,互联网老兵,软件工匠,开源爱好者,一直深入代码一线,接触 java 近 20 年。现在携程网负责框架研发,曾任大众点评网首席架构师、任 eBay& 易趣资深架构师等。关注分布式系统框架、组件化系统开发,高质量数据建模和代码生成等。
互动问答
问题:业界类似解决方案,以及与 CAT 的异同?
业界有很多开源监控系统,但大多是基于日志行的(如 ELK),CAT 是基于日志树的。其中最主要的差异是监控源数据的质量。
问题:请问吴老师,CAT 与应用间是否做了反馈机制,监控报警后是否会有应用重启,服务降级这种操作?点评内部的 pigeon 是否有这种服务健康检查包括自动降级的功能,能否谈谈您的看法?
监控可以理解为监和控。现阶段 CAT 的侧重点还是在监上,将来会考虑控的一面。要做到控,光 CAT 是不够的。
问题:CAT 如何做到高实时性,又如何避免对应用本身性能,可用性等产生影响的?
CAT 在编码的时候非常的关系性能,每一行代码都经过多次 review。消息发送异步化也是避免对主线程造成性能和可用性干扰的重要手段。另外,CAT 在设计时就要求做到:不保证可靠,如果后台出现可用性问题和性能问题,客户端会主动丢弃消息,确保应用可用。
问题:怎么解决埋点性能问题?特别是访问量大的应用,千万级的,出现问题很多?
这是个好问题。CAT 不会帮你解决业务埋点的问题。监控埋点是一个领域,跟你要解决的问题非常相关,不同应用,不同场合,不同公司的历史阶段,应该采取不同的策略。对于访问量非常大的应用,CAT 埋点要做到小而精,适当的时候可以在客户端做一下聚合。
问题:请问这里的消息树是怎么实现的?是自己规定流程自主研发吗?
只要使用 CAT API 埋点,消息树是自然而然形成的,无需特别处理。CAT 中有示例代码,可以参考一下。
问题:请教吴老师 cat server 端集群部署时,且数据落本地磁盘,报表的统计基于全量数据还是只是开起任务的哪台机器上的数据,如果是全量的,数据是怎么汇总的?
CAT 是主张全量日志分析的,全量数据落到每一台消费机上只是一个分片,CAT 中所有报表都有内置将分片合并的能力,所有的报表在展示时会合并,做数据汇总。
问题:如果客户端上报大量 size 很大的日志,CAT 有没有自保护?
有。CAT 在客户端有保护机制,服务器端一般处理能力很强,有一定的保存措施,如丢弃消息之类的。但如果报表过大,则可能会出现内存问题。
感谢志愿者田光、攀爬的蜗牛、Bendy PAN、qiaoliang、王旭林、cloes 对本文的整理和编辑。本文是老 X 聊架构系列文章的第十篇,聊聊架构社群将会邀请国内顶级的架构师与大家探讨实战中的架构经验,欢迎关注『聊聊架构』公众号并回复『干货』获取入群方式。
号外号外
吴老师提到的由 InfoQ 组织的全球顶级的软件开发大会 QCon 北京将会在 4 月 21 日举行(伦敦站刚刚结束),在大会的第一天就设有架构相关的专题,目前确定分享的主题有 58 到家的实时消息平台架构、魅族的推荐系统实践、艺龙的电商检索系统,还有知乎的反作弊系统。
感谢郭蕾对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ , @丁晓昀),微信(微信号: InfoQChina )关注我们。
评论