本文首发于 infoQ 及「前端之巅」微信公众号(微信群直播记录),感谢 infoQ 前端之巅尾尾同窗对文章的整理和校对、微信群直播的组织策划前端
一般在一个大型的 Web 项目中有不少监控,好比后端的服务 API 监控,接口存活、调用、延迟等监控,这些通常都用来监控后台接口数据层面的信息。并且对于大型网站系统来讲,从后端服务到前台展现会有不少层:内网 VIP、CDN 等。可是这些监控并不能准确地反应用户看到的前端页面状态,好比:页面第三方系统数据调用失败,模块加载异常,数据不正确,空白开天窗等。这时候就须要从前端 DOM 展现的角度去分析和收集用户真正看到的东西,从而检测出页面是否出现异常问题node
页面一般出现如下问题时须要使用邮件、短信通知相关人员修复问题nginx
状态码返回错误(50x, 40x)没法打开git
模块加载失败github
页面乱码web
数据正确性编程
触发报警时要有现场快照,以便复现问题后端
监控的意义和回归测试的在本质上是一致的,都是对已上线功能进行回归测试,但不一样的是监控须要作长期的可持续可循环的回归测试,而测试仅仅须要在上线以后作一次回归浏览器
既然监控和测试的本质一致,那咱们彻底能够采用测试的方式来作监控系统。在自动化测试技术遍地开花的时代,不乏不少好用的自动化工具,咱们只须要把这些自动化工具进行整合为咱们所用便可缓存
NodeJS - 特别适用于网络密集型任务
PhantomJS - 模拟无界面的浏览器,提供丰富的内核交互 API
NodeJS 是一个 JavaScript 运行环境,非阻塞 I/O 和异步、事件驱动,这几点对于咱们构建基于 DOM 元素的监控是很是重要的
PhantomJS 是一个基于 webkit 的浏览器引擎,可使用 JavaScript API 来模拟浏览器的操做。它使用 QtWebKit 做为它的浏览器核心,使用 webkit 来编译解释执行 JavaScript 代码。也就是说任何你能够在 webkit 浏览器里作的事情,它都能作到
它不只是个隐形的浏览器,提供了诸如 CSS 选择器、支持 Web 标准、DOM 操做、JSON、HTML五、Canvas、SVG 等,同时也提供了处理文件 I/O 的操做等。PhantomJS 的用处可谓很是普遍,诸如网络监测、网页截屏、无浏览器的 Web 测试、页面访问自动化等
为何不是 Selenium
作自动化测试的同窗确定都知道 Selenium。可使用 Selenium 将测试用例在浏览器中执行,并且 Selenium 对各类平台和常见浏览器支持比较好,可是 Selenium 上手难度系数略高,并且使用Selenium 须要在服务器端安装浏览器
考虑到监控主要任务在监控不在测试。系统并不须要太多考虑兼容性,并且监控功能相对单一,主要对页面进行功能上的回归测试,因此选择了 PhantomJS
对于 DOM 监控服务,在应用层面上进行了垂直划分:
规则管理系统
规则队列生成器
长时持续处理器
PhantomJS 服务
服务化 API
在应用层面上进行的垂直划分能够对应用作分布式部署,提升处理能力。后期也方便作性能优化、系统改造扩展等
这是一个独立的 Web 系统,系统主要用来收集用户录入的页面信息、页面对应的规则、展现错误信息。经过调用后端页面抓取服务来完成页面检测的任务,系统能够建立三种类型的检测页面:常规监控、高级监控、可用性监控
录入一个页面地址,和若干检测规则。注意这里的检测规则,咱们把经常使用的一些检测点抽象成了一条相似测试用例的语句。每条规则用来匹配页面上的一个 DOM 元素,用 DOM 元素的属性来和预期作匹配,若是匹配失败系统就会产生一条错误信息,后续交由报警系统处理
匹配类型 通常有这么几种:长度、文本、HTML、属性
处理器 相似编程语言中的操做符:大于、大于等于、小于、小于等于、等于、正则
这样作的处就是,录入规则的人只要了解一点 DOM 选择器的知识就能够上手操做了,在咱们内部一般是交由测试工程师统一完成规则的录入
主要用来提供高级页面测试的功能,通常由有经验的工程师来撰写测试用例。这个测试用例写起来会有一些学习成本,可是能够模拟 Web 页面操做,如:点击、鼠标移动等事件从而作到精确捕捉页面信息
可用性监控侧重于对页面的可访问性、内容正确性等比较 严重的问题 作即时监控。一般这类页面咱们只须要在程序里面启一个 Worker 不断的去获取页面 HTML 就能够对结果进行检测匹配了,因此咱们选择了 NodeJS 来作异步的页面抓取队列,高效快速的完成这种网络密集型任务
页面引入一段监控脚原本收集页面产成 error 事件返回的错误信息,自动上报给后端服务,在系统里面能够汇总全部报错信息,以及对应的客户端浏览器版本、操做系统、IP 地址等
这个功能须要对应的前端工程师在代码中调用错误上报 API,来主动提交错误信息。主要使用的场景有,页面异步服务延时无响应、模块降级兜底主动通知等。监控脚本提供几个简单的 API 来完成这项任务
// error 方法调用后当即上报错误信息并发出邮件、短信通知 errorTracker.error('错误描述') // info 方法调用后当即上报信息,并在单位时间内仅产生一条邮件、短信通知 errorTracker.info('信息描述') // log 方法调用后由报错检测是否达到设置阀值,最终确认是否报错 errorTracker.log('日志信息')
因为京东不少页面内容是异步加载的,像首页、单品等系统有许多第三方异步接口调用,使用后端程序抓取到的页面数据是同步的,并不能取到动态的 JavaScript 渲染的内容,因此就必须使用像 PhantomJS 这种能模拟浏览器的工具
常规监控咱们使用 PhantomJS 模拟浏览器打开页面进行抓取,而后将监控规则解析成 JavaScript 代码片断执行并收集结果
高级监控咱们使用 PhantomJS 打开页面后向页面注入像 jasmine, mocha 等相似的前端 JavaScript 测试框架,而后在页面执行对应的录入测试用例并返回结果
规则队列生成器会将采集的规则转化类成消息队列,而后交由长时持续处理器一次处理
为何采用类消息队列的处理方式?
这和 PhantomJS 的性能是密不可分的,由屡次实践发现,PhantomJS 并不能很好地进行并发处理,当并发过多,会致使 CPU 过载,从而致使机器宕机
在本机环境下的虚拟机中进行并发测试,数据并不理想,极限基本在 ab -n 100 -c 50 左右。 因此为了防止并发致使的问题,就选择了使用类消息队列来避免由于并发太高致使的服务不可用
咱们这里经过调用内部的分布式缓存系统生成类消息队列,队列的生成其实能够参考数据结构--队列。最基本的模型就是在缓存中建立一个 KEY ,而后根据队列数据结构的模式进行数据的插入和读取
固然,类消息队列的中间介质可根据你实际的条件来选择,你也可使用本机内存实现。这可能会致使应用和类消息队列竞争内存
长时持续处理器是要功能就是消费规则队列生成器生成的类消息队列
在长时持续处理器的具体实现中,咱们利用了 JavaScript 的 setInterval 方法来持续获取累消息队列的内容下发给规则转化器,而后转发给负载均衡调度器。以后再对返回的结果进行统一处理,好比邮件或者短信报警
PhantomJS 服务能够作为公共 API 提供给客户端进行测试需求的处理, API 经过 HTTP 方式调用。在 API 的处理上须要提供 HTTP 数据到规则和 PhantomJS 的转换。从而又演化出了 HTTP 数据到规则转换器
PhantomJS 服务是指将 PhantomJS 结合 HTTP 服务和子进程进行服务化的处理
首先、启动 HTTP 服务,而后将长时处理器下发的规则进行进一步转化,转化后启动子进程,HTTP 服务会监听子进程的处理结果,并在处理完毕以后返回
报警系统咱们目前使用的是京东内部本身的统一监控平台 UMP,经过调用平台提供的一些 API 来实现报警邮件与短信通知
用户经过监控管理系统录入规则后,监控系统会根据 UMP 规则针对用户录入的页面生成 UMP 使用的 key。当长时持续处理器发现 PhantomJS 服务返回的结果标示为异常后,就会使用 key 来进行日志记录
报警主要分为了短信和邮件报警。邮件报警是在每条异常以后就会发给指定系统用户。短信则是根据异常次数来进行处理的,当异常次数过大,就会下发短信通知
对于系统部署能够分为两大块进行。由于机器资源数量有限,没有将全部部分都单独部署
规则管理系统以及规则队列生成器和持续处理器整合部署在一台机器上,PhantomJS 服务部署在了其余的机器上。进程管理使用了著名的 NPM 模块 —— PM2
PM2 是一个带有负载均衡功能的 NodeJS 应用的进程管理器。可充分利用 CPU,并保证进程稳定存活
PM2 特性:
内建负载均衡(使用 Node cluster 集群模块)
无缝重启相似 nginx reload
具备 Ubuntu 和 CentOS 的开机启动脚本
控制台检测
不过在目前部署任务中,并无使用内建负载均衡的特性,没用经过集群的方式部署代理。仅使用了后台运行和无缝重启的特性
其实咱们如今开发的这套监控系统并不复杂,只是合理的运用了一些现有的技术框架。抽象出来咱们本身须要的一些功能。但却有效的达到了咱们的预期功能,而且节省了不少以前须要人肉测试的时间成本。系统自己还有不少问题在待解决状态,好比报警系统的规则处理与阀值设定,JavaScript 报错的准确过滤机制等,这些问题咱们都会逐个解决,而且将来的前端监控系统会成为一个平台,核心服务在后端爬取页面服务,应用端能够有多种形式,好比监控、测试工具等
一些能够持续优化点:
监控系统虽然在应用层面进行了垂直划分,可是因为机器资源等限制,并无进行单独功能的部署。这点可能会在后期的使用中进行优化
PhantomJS 服务还须要进一步优化,以承载大并发,大处理量。提供稳定的服务
报警因为依赖于公司内部的 UMP 系统,因此并非特别灵活,后期能够考虑本身实现一套报警机制