nodejs抓取动态网页(为什么需要一个前端监控系统解决的问题和解决办法?)
优采云 发布时间: 2021-09-12 11:07nodejs抓取动态网页(为什么需要一个前端监控系统解决的问题和解决办法?)
本文首发于infoQ和“前端之巅”微信公众号,微信群直播记录
感谢infoQ前端顶尖同学对文章的整理校对,以及微信群直播的组织策划
为什么需要前端监控系统
通常大型Web项目中会有很多监控,比如后端服务API监控、接口存活、调用、延迟等监控,这些一般用于监控后台的信息端接口数据层。而对于一个大型的网站系统,从后端服务到前端展示会有很多层:内网VIP、CDN等,但是这些监控并不能准确反映前端页面的状态用户看到,如:页面第三方系统数据调用失败、模块加载异常、数据不正确、天窗空白等。这时候就需要从前端DOM展示的角度分析采集用户真正看到的东西,从而检测页面是否有异常问题
监控系统需要解决的问题
当页面出现以下问题时,您需要通过邮件或短信通知相关人员解决问题
触发报警时需要现场快照,以便重现问题
技术选择
监控的含义与回归测试的含义基本相同。他们都对在线功能进行回归测试,但不同的是监控需要长期的、可持续的、可回收的回归测试,而测试只需要上线后做回归
既然监控和测试的本质是一样的,我们可以把测试作为监控系统。在自动化测试技术遍地开花的时代,有很多好用的自动化工具。我们只需要集成这些自动化工具供我们使用。
NodeJS
NodeJS 是一个 JavaScript 运行环境,非阻塞 I/O 和异步,事件驱动,这几点对于我们构建基于 DOM 元素的监控非常重要
PhantomJS
PhantomJS 是一个基于 webkit 的浏览器引擎,可以使用 JavaScript API 来模拟浏览器操作。它使用 QtWebKit 作为浏览器核心,使用 webkit 来编译、解释和执行 JavaScript 代码。换句话说,任何你在 webkit 浏览器中能做的,它都能做到
它不仅是一个隐形浏览器,还提供CSS选择器,支持Web标准、DOM操作、JSON、HTML5、Canvas、SVG等,还提供处理文件I/O的操作。 PhantomJS 用途广泛,如网络监控、网页截图、无浏览器网页测试、页面访问自动化等。
为什么不用硒
做自动化测试的同学一定知道Selenium。可以使用Selenium在浏览器中执行测试用例,Selenium对各种平台和常用浏览器的支持比较好,但是Selenium上手稍微难一些,需要在服务器端安装浏览器才能使用Selenium。
考虑到监控的主要任务是监控而不是测试。系统不需要过多考虑兼容性,监控功能比较单一,主要是针对页面的功能回归测试,所以选择了PhantomJS
架构设计架构概述
架构简介
对于DOM监控服务,在应用层面垂直划分:
应用层面的垂直划分,可以让应用分布式部署,提升处理能力。也方便后期让性能更优
改造、系统改造扩容等
解决方案前端规则入口
这是一个独立的网络系统。系统主要用于采集用户输入的页面信息、页面对应的规则、显示错误信息。通过调用后端页面抓取服务完成页面检测任务,系统可以创建三种类型的检测页面:定期监控、高级监控和可用性监控
常规监控
输入一个页面地址和几个检测规则。注意这里的检测规则,我们将一些常用的检测点抽象成一个类似于测试用例的语句。每条规则用于匹配页面上的一个DOM元素,DOM元素的属性用于匹配期望。如果匹配失败,系统会产生错误信息,稍后由报警系统处理
匹配一般有几种类型:长度、文本、HTML、属性
处理器类似于编程语言中的运算符:大于、大于或等于、小于、小于或等于、等于、正则
这里的重点是进入规则的人只需要了解一点DOM选择器的知识就可以上手。在我们内部测试工程师通常会统一完成规则的录入。
高级监控
主要用于提供高级页面测试功能,通常由有经验的工程师编写测试用例。本测试用例编写会有一定的学习成本,但可以模拟网页操作,如点击、鼠标移动等事件,准确捕获页面信息
可用性监控
可用性监控侧重于实时监控更严重的问题,例如页面可访问性和内容正确性。通常我们只需要在程序中启动一个Worker就可以获取页面的HTML来检查匹配结果,所以我们选择NodeJS来做异步页面爬取队列来高效快速的完成这种网络密度。输入任务
主动报错页面脚本执行错误监控
页面引入监控脚本,采集页面产生的错误事件返回的错误信息,并自动上报给后端服务。系统中可以汇总所有错误信息,以及对应的客户端浏览器版本、操作系统、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左右。所以为了防止并发问题,我选择使用消息队列,避免高并发导致服务不可用
类消息队列的实现
这里我们通过调用内部分布式缓存系统来生成消息队列。其实队列的产生可以参考数据结构-queue。最基本的模型是在缓存中创建一个KEY,然后按照队列数据结构的方式插入和读取数据
当然,类消息队列的中间介质可以根据自己的实际情况选择,也可以使用原生内存来实现。这可能会导致应用程序和类消息队列争夺内存
长期连续处理器
长期连续处理器是作为消费规则队列*敏*感*词*生成的消息队列
长期连续加工实现
在长期持久化处理器的具体实现中,我们使用了JavaScript的setInterval方法,不断的获取累了的消息队列的内容发送给规则转换器,再转发给负载均衡调度器。然后对返回的结果进行统一处理,如邮件或短信报警
API
PhantomJS 服务可以作为公共 API 向客户端提供测试需求,API 通过 HTTP 调用。在 API 处理中,需要提供 HTTP 数据到规则和 PhantomJS 的转换。从而将 HTTP 数据演化为规则转换器
PhantomJS 服务
PhantomJS 服务是指将 PhantomJS 与 HTTP 服务和子进程结合起来的服务处理