项目背景在使用antdesign文档的过程中,发现antd使用了一个叫logRocket的录屏框架,于是马上在项目中使用logRocket测试其功能。logRocket网站将收集到的数据按照人员和会话进行分类,通过观看每个人员的操作回放,可以发现系统中某些操作的不便之处,可以找出哪些人员是您的重度用户。但是logRocket的数据是存放在他们的服务器上的,从logRocket的回放中可以看到系统中的各种重要数据。如果数据被别有用心的人获取,后果很严重。如果rrweb需要基于一个开源的框架,把数据存储在自己的服务器上,限制人的查看权限,这样就消除了之前的隐患。下面要介绍的就是今天的主角rrweb框架,全称是recordandreplaytheweb。由三个库组成:rrweb-snapshot,将页面中的dom转换为可序列化的数据结构rrweb,提供屏幕录制和播放apirweb-player,提供播放ui页面,支持快进,全屏,拖拽每次通过拖动等操作刷新页面,rrweb会将页面中的所有dom元素转化为文档数据,并为每个dom元素分配一个唯一的id。之后,当页面发生变化时,只有变化的dom元素被序列化。页面回放时,数据会被反序列化插入到页面中,原有的增量dom变化,比如属性或者文本的变化,会根据id进行修改,找到对应的dom元素;而子节点的增减会根据父元素id进行dom变化。发展历程1、直接使用rrweb记录每一个序列化的录屏数据,先保存到localStorage。当数据量超过阈值或超过时间限制时,sendbeacon将数据发送给node并保存在mongo中。2.遇到的第一个问题是sendbeacon发送的数据居然丢了。原因是当数据超过65536时,会发送失败。由于sendbeacon是后台进程单独发送,无法获取失败状态,所以需要降级。当数据太大时,用fetchrequest发送。3、由于公司中后台系统的用户分布在全球各地,海外网络延迟高,需要解决压缩数据量的问题。这里使用lz-string库。一开始是想每次存到localStorage都压缩一下。后来发现压缩后的数据有特殊字符,JSON.parse经常报错。后来改成每次发送到后端前先压缩数据,在节点端执行。解压缩。4、最初的数据库选择是时序数据库influxdb,后来因为一些不可抗拒的原因,改成了mongodb。5、项目上线后,我选择了一个小项目进行测试,发现存储和播放效果都不错。代码如下importrrwebfrom'rrweb';rrweb.record({emit(event){storagePush(event);},});数据库中存储的数据结构为{timestamp:1563418490795,name:'XiaoMing',event:...},方便按用户和时间范围查找数据。内容如下6.但是每次播放一整天的数据,第一次播放界面获取的数据量巨大,第二次播放耗时较长,抓不住重点。一旦数据有误,后面的录屏就无法播放了。查看rrweb源码,发现checkoutEveryNms属性可以根据时间对session进行分段,于是代码变成了这样);},checkoutEveryNms:1000*60*10});每次checkoutEveryNms过期,emit中的第二个参数checkout都会为true,这样就可以知道有一个新的session开始,给session赋一个唯一的值,改变数据库中存储的数据结构,为此{timestamp:1563418490795,name:'小明',session:xxxxxxxxxxx,event:...}有了session的概念,某人可以根据session在某一天的操作来选择玩。页面如下7.小项目测试完毕最后希望介绍一个大项目进行测试,于是开了一个几千uv,几十万pv的大项目。采集了一天数据,发现存储数据正常,但是播放页面没有数据。查看mongo的stats发现每天的存储容量达到了1500万条,每条数据基本都在几十KB到几M之间。首先,将不同的项目存储在单独的表中,并将索引设置为后台处理。使用该方案后,播放页面正常,但是人员列表界面还是很慢。所以每次存储mongo时,都会在redis中存储一份人员和日期数据。目前系统运行正常,所有接口都能在1s内返回所有数据。
