著做权归做者全部。商业转载请联系 Scott 得到受权,非商业转载请注明出处[务必保留全文,勿作删减]。决策源于数据,而数据源于采集,采集源于规则梳理,让这一切发生源于工程师的创造力和执行力,本文 5000 字,偏科普向,技术深度通常,阅读约 10 分钟,能够先 Mark 后看,文章架构细节图(含最新备注)能够找 Scott 索取(微信: codingdream)。前端
背景:小菜从 2014 年第一款 APP 上线,到现在将近 5 年,5 年风雨 5 年征程,虽然技术部有 80 人,前端有 20 人,咱们依然对本身所研发的 8 款 APP、4 款小程序、6 款 H5 商城系统、10+ 个 PC CRM/IM/ERP/TMS 中台运营系统的用户使用状况、线上异常状况、设备分布状况、营销活动的 PV/UV 转化状况通通一无所知,由于看不见就不清楚现场,这种作法显然很不互联网,也很不符合小菜前端 “工具为王效率至上” 的技术价值观。面试
历史问题和痛点:redis
toB 产品的多端数据未搜集,toC 的产品亦然数据库
- 如同一个业务的 RN APP/PC Web(React 单页/多页应用)/H5/小程序跨端产品
数据埋点散落未作定义及归类小程序
- 如阿里有位置跟踪 SPM、资源位跟踪 SCM、曝光和交互的黄金令牌,咱们通通没有
用户的线上访问异常(B 端用户,可用性稳定性是刚需)无从跟踪后端
- 如整个质量体系监控没有抓手,前端报错后端报错,全靠经验、人肉日志和用户主动反馈
用户的访问行为/设备特征/应用性能信息彻底无感知浏览器
- 如活跃时间点(避开作发布),软硬件系统和设备比例(作兼容),慢页面优化等无从作起
业务数据的效果无从跟踪服务器
- 如营销活动转化效果、支付链路的耗时等都很难服务业务决策
其实痛点还太多太多,为了避免让本身变成瞎子,咱们决定不管是借助社区方案,仍是付费,仍是自研,必定要作出一套前端产品埋点监控的工具产品出来,这几年,咱们也作过一点尝试,总共走过了 3 段历程:微信
直到今年,咱们最终选择社区开源方案 + 彻底自研,也就是阶段三,几乎再也不用任何付费产品,投入了 1 个前端全力攻坚,整个项目从立项到落地,差很少用了 60 人日。网络
另外,本文所介绍的整个监控系统属于小菜前端质量评估与跟踪体系中的一环,至于端质量体系策划了两篇,还没动笔写:
你们能够 关注个人语雀帐号 来跟进这两篇的写做动态,本文咱们不作质量体系的探讨,只聚焦在监控跟踪实现。
为了让你们更直观的感觉到底咱们作了什么,作了多少,也便于你们理解后面更技术性的一些选型判断,先放咱们的数据流向图、产品功能图和系统架构图出来,造成第一观感及疑问。
数据从用户访问页面那一刻开始,到基于这些数据作出必要的决策结束,整个数据流进来一步步处理掉,能够分为 采集、转发、解密、持久化和处理这几个核心流程:
而整个监控跟踪,从采集到跟踪,从产品的视角,能够拆分出来以下几个功能模块:
从实现层面,数据一层层进来,每一层的任务都有对应系统接管处理,整个监控跟踪的技术架构图以下:
从核心系统/模块组成上,能够简单分以下几个:
限于篇幅,咱们只针对每一个系统的设计作介绍,不涉及技术细节,你们想要了解更详细的信息,或者要更详细的高清架构图,能够加我微信索取: codingdream。
图上用到了不少名词,你们能够搜索下作些越热,我先尝试用大白话简述下它们关系,而后咱们就开始进入系统介绍,内部的关系是:
数据源于采集,而采集源于需求梳理和规则梳理,也就是为了达到某某某的目的,而必须采集到端上什么样的数据,以 PC/H5 为例,但愿采集的数据有以下几大类:
用户数据
设备信息
行为数据
性能数据
异常数据
定制数据
对这些数据需求作整理,映射到浏览器宿主环境下,就须要实现以下一些功能:
技术没什么难点,主要是对浏览器的特定事件( onerror 、onunhandledrejection、onpopstate 等)进行监听以及以 AOP 的方式进行包装一些全局对象的某些特定函数(如 XHR 的 send
),在不影响开发者的状况下采集必要的数据。
这个过程当中咱们应该注意的是,在对函数或对象进行 wrap 的时候,必定要避免重复包装,真正花时间的是兼容性的调试,特别是在移动端会遇到一些难点,好比 iOS 设备频繁发生的 script error
、指纹丢失、iOS 的 sendBeacon
上报到达率低一些问题。
由于要集中管理多个端的 SDK,咱们在搭建这个 SDK 工程时,使用了 monorepo 的方式,TypeScript 实现代码,部分 SDK 使用 rollup + tsc 打包。
数据从客户端采集到后,按照必定的策略上报到服务器,先经由 Nginx 拿到 IP 等信息后,直接交由 Transfer,而后将数据发送给 Kafka,让 Kafka 把数据同步给 ELK。下图是 DataTransfer 在整个架构中与其余组件的关系:
这里的数据转发器,就是一个 Node 服务,它扮演数据搬运工的角色,将数据转发给 Kafka 集群,同时它也作了一些额外的事情,好比数据的解密和验证,添加额外的必要字段等。
针对 Kafka 咱们作了降级方案,当转发到 Kafka 失败的时候,就将数据写到本地的日志,而后用 Filebeat 发送给 Logstash,为何作降级呢,由于咱们自建的 ES 和 Kakfa 正在经历阿里云 VPS 从经典到私有网络的切换,过渡期的几个月不稳定,咱们这里就用了两条腿,优先发送给 Kafka,当 Kafka 不稳定的时候,就由 Filebeat 接管,再推送给 Logstash,每一台 transfer 上都对应一个 Filebeat 备胎,属因而过渡性方案。
其实这里的 Nginx + Transfer 用 Openresty 会更合适,性能也不错,咱们之因此没采用,是由于整套设施是前端自行搭建和维护的,用 Eggjs 搭建的 Transfer 服务,不想引入额外的语言栈加大后期的维护成本,就用了 Nginx + Node Transfer(Filebeat)。
至于工程的实现,咱们依然使用了 TS,服务框架用的是 Eggjs,针对 Eggjs 写了一个 egg-kafka 插件用于 kafka 的消息收发,该插件也算是这次项目的收获之一。
数据若是没有介入到团队的决策,那就失去了搜集的价值,既然是决策,无非就是信息的聚合展现以及各类任务的增删改查,而这个角色就有监控后台 Dashboard 承担。
Dashboard 在总体架构中与其余模块的关系如图所示:
ELK 三大件中最好用的莫过因而 Kibana,为何咱们不用呢,其实咱们也不是不用,而是给到部分小场景去灵活使用,之因此没有彻底使用,是由于咱们但愿跟前端团队有更强的关联性,好比用户身份、issue 的推动、任务的跟踪、将来代码仓库分支的异常关联、质量报告的评估等等,这些业务属性太强,而 Kibana 显然不便于咱们作很灵活的扩展,因此就没有以它做为 Dashboard。
Dashboard 的数据来源主要有两个,ES 和 阿里云的 RDS(MySQL)。
ES 扮演的就是日志数据库的角色,他提供查询的能力,而 Dashboard 就是无脑的从 ES 获取实时数据,好比刚刚 15 分钟的异常数量,或者今天到目前为止某个应用的 PU/V ,访问的设备类型分布等等,以下图,某个应用大盘的数据:
或者该应用异常发生状况:
每个特定的异常,咱们能够点击详情查看相应的异常详情,跟踪到用户的 ID、设备及厂商、浏览器版本、页面、发生时间、IP、地理位置甚至角色身份等更细节的数据信息,再结合异常的回溯重放和 Sourcemap,便于咱们第一时间跟进了解和修复。
甚至 API 请求出错的状况也能查看:
MySQL 中存储的数据是咱们经过下节会讲到的 Controller 对存储在 ES 中的错误原始数据进行分类和抽象而获得 issue 信息、以及开发者为了监控某个特殊 issue 而制定的规则和相应的任务信息,
针对每一个 issue ,不管是前端仍是后端,到底哪些被跟进修复了,修复状况如何,均可以跟踪到:
同时,针对用户的某一次的一系列动做咱们会有一个 session 的概念,上报数据时会生成一个 sessionId 而后透出到 issue 详情中,便于开发者在解决错误时查看用户具体操做了什么,而后能更好地解决问题:
目前这个页面还作得比较粗糙,毕竟没有专门设计师
issue 的大体生命周期以下,其中大多数状态变动的操做是开发者在 dashboard 上实现的:
前端和后端结合起来联动查看,能够更快速的解决问题,再配合上异常的识别和断定机制,能够更主动的把异常推到前端和后端的钉钉群里,甚至复发的问题会 @ 当事人,关于 issue 的断定咱们放到后面再来说:
当开发者须要对某个 issue 特别 "关照" 时,能够针对该 issue 设置相应的报警规则,下文提到的 controller 会根据报警规则生成报警任务,下图就是一个简单的报警任务:
咱们还能看到该任务的执行状况:
后台还有不少其余实用的功能,好比 issue 查看分配指派与分类、更新流水、报警任务查看编辑、错误信息回溯、各类质量周报的生成推送等,更多截图在文后。
技术实现上,后端咱们使用的是基于 Eggjs 封装的 Cross 搭建的工程,集成了 Kafka 和钉钉等,其中 kafka 用于和其余模块交流;前端则使用了 AntDesign Pro(umijs/dva/bizcharts),此次考虑到是功能多变且业务性强,就没有使用 TS。
前面提到的 Dashboard 最大的做用是消费、修改以及管理 issue 数据,而从原始数据中抽象出 issue 数据给 dashboard 消费的则是 controller,固然,controller 的做用不止于此,咱们会在下面展开来讲,这里先贴出其在整个架构中的与其余模块的关系图,让你们对其在整个架构中的角色有一个大体的认识:
Controller 在整个架构中的做用相当重要,主要体如今如下几个方面:
任务控制器是一个纯后端项目,它依然经过 kafka 与其余模块进行交流,由于其功能比较明确因此咱们采用 TypeScript 编写,后端框架依然是咱们团队基于 Eggjs 自研的 Cross。而报警任务队列是经过 redis 实现的。
做为任务控制器的小弟,任务执行器 Instpector 作的事情就很纯粹,就是解析从 controller 发送过来的任务,而后对原始进行查询最后返回结果,可是考虑到任务可能会比较多,咱们在设计时是将其设计为多点的,利用 kafka 的消息单播的特色,尽量让任务尽快地执行。
实现执行器也是用 TS 开发,框架为 Eggjs, 比较简单。
这个系统的建设并非一蹴而就的,咱们在过去两年使用过很多社区现有的产品,也自研过不完善的方案,从中积累了很多经验,没有这些沉淀,咱们也没办法作出如今的这个系统。
整个系统麻烦在于设计而不是实现,你们动手以前,能够先考虑清楚本身的应用场景,指望解决的问题是什么,也就是弄清楚 What 和 Why,以后再考虑是否投入人力进行设计和实现,毕竟整个系统建设下来,仍是须要必定的技术实力和很多人力的。
截至目前,这个系统并不是达到最理想的状态:
但即使如此,上线这 3 个月以来,咱们能看到端产品上的行为数据和异常状况了,对产品体验的提高或者降低更有感知,对问题的跟踪修复也更有效率了,用户对于产品的负面反馈也在一每天的减小,我想,这也算是一个不错的开始吧。
再补两张 DashBoard 截图:
Scott 近两年不管是面试仍是线下线上的技术分享,遇到许许多多前端同窗,因为团队缘由,我的缘由,职业成长,技术方向,甚至家庭等等缘由,在理想国与现实之间,在放弃与坚守之间,摇摆不停,心酸硬扛,你们能够找我聊聊南聊聊北,对工程师的宿命有更多的了解,有更多的看见与听见,Scott 微信: codingdream,也能够来 关注 Scott 跟进个人动态。