基于rrweb录屏与重放页面

项目背景

在使用ant design文档的过程当中发现,antd使用了一个叫作logRocket的录屏框架,因而立马将logRocket用在本身的项目当中,测试它的功能。node

logRocket网站将采集到的数据,按照人员和session进行分类,观看各人员的操做回放,能够发现系统中某些操做的不便之处,而且能够发现哪些人员是你的重度用户。git

可是logRocket的数据存储在他们的服务器,而且从logRocket回放里,能看到系统中的各类重要数据。若是数据被别有用心之人获取,后果将很严重。github

rrweb

若是咱们须要基于一个开源框架,并将数据存在本身的服务器中,限制人员查看的权限,这样就尅消除以前的隐患。web

下面我要介绍的就是今天的主角rrweb框架,全称record and replay the web。它由三个库组成:redis

  1. rrweb-snapshot,将页面中的dom转化为可序列化的数据结构
  2. rrweb,提供录屏和重放的api
  3. rrweb-player,提供播放的ui页面,支持快进、全屏、拖拽等操做

每次刷新页面时,rrweb会将页面中的dom元素所有转换成文档数据,并给每一个dom元素分配一个惟一id。后面当页面发生变化时,只对变化的dom元素进行序列化。当重放页面时,会将数据反序列化并插入到页面中,而原先增量的dom变化,如属性或者文本变化,则根据id找到对应dom元素修改;而子节点的增长或减小,根据父元素id进行dom变动。mongodb

开发历程

1.直接使用rrweb记录每次的序列化录屏数据,首先保存到localStorage中,当数据量超过阈值或者超过期间限制,再由sendbeacon发送数据到node,并保存到mongo中。数据库

2.首先遇到的问题是sendbeacon发送数据竟然出现了丢失,缘由是数据超过65536时,将会发送失败,因为sendbeacon是由后台进程单独发送,没法获取失败状态,因此要进行降级处理,当数据过大时,使用fetch请求发送。后端

3.因为公司中后台系统的用户分布在世界各地,海外的网络延迟较高,须要解决压缩数据大小的问题,这里使用的是lz-string库。一开始想要在每次存储在localStorage时进行压缩,后来发现压缩后的数据有特殊字符,JSON.parse高频率出错,后改成在每次发送数据到后端以前压缩,并在node端进行解压。api

4.一开始的数据库选型为时序数据库influxdb,因为某些不可抗拒缘由改成了mongodb。服务器

5.在项目上线后选择了一个小项目进行测试,发现存储和播放效果良好,代码以下

import rrweb from 'rrweb';

rrweb.record({
  emit(event) {
    storagePush(event);
  },
});

存进数据库中的数据结构为

{
timestamp: 1563418490795,
name:'小明',
event:...
}

方便按照用户和时间范围进行查找数据,内容以下

clipboard.png

6.可是每次都要播放一成天的数据,第一播放接口获取的数据量巨大,第二播放时间漫长,抓不住重点,一旦数据有误致使后续录屏都播放不了。

查看rrweb源码发现checkoutEveryNms属性能够按照时间进行session切分,因而代码变成了这样

rrweb.record({
  emit(event, checkout) {
    if(checkout)rrwebSessionSet();
    storagePush(event);
  },
  checkoutEveryNms: 1000 * 60 * 10
});

每一次checkoutEveryNms到期时,emit里的第二个参数checkout都会为true,这样就能够知道新的session开始,给session分配一个惟一值,存到数据库中的数据结构改成这样

{
timestamp: 1563418490795,
name:'小明',
session:xxxxxxxxxxx,
event:...
}

有了session概念以后,某我的某一天的操做就能够按照session进行选择

clipboard.png
播放页面以下

clipboard.png

7.小项目测试完毕后,但愿引入一个大项目进行测试,因而开放了一个uv上千、pv几十万的大项目,采集一天的数据后,发现存储数据正常,而播放页面已经获取不到数据,查看mongo的stats发现一天存储量达到了1500万条,每一条数据基本在几十KB到几M之间。

首先对不一样的项目进行分表存储,并将索引设置为后台处理,这个方案使用后播放页面变得正常,但人员列表接口仍是很慢。

因而在每次存储mongo时,存一份人员和日期的数据到redis中,目前系统已经正常运行,全部接口能在1s内返回全部数据。

相关文章
相关标签/搜索