在使用ant design文檔的過程當中發現,antd使用了一個叫作logRocket的錄屏框架,因而立馬將logRocket用在本身的項目當中,測試它的功能。node
logRocket網站將採集到的數據,按照人員和session進行分類,觀看各人員的操做回放,能夠發現系統中某些操做的不便之處,而且能夠發現哪些人員是你的重度用戶。git
可是logRocket的數據存儲在他們的服務器,而且從logRocket回放裏,能看到系統中的各類重要數據。若是數據被別有用心之人獲取,後果將很嚴重。github
若是咱們須要基於一個開源框架,並將數據存在本身的服務器中,限制人員查看的權限,這樣就尅消除以前的隱患。web
下面我要介紹的就是今天的主角rrweb框架,全稱record and replay the web。它由三個庫組成:redis
每次刷新頁面時,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:... }
方便按照用戶和時間範圍進行查找數據,內容以下
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進行選擇
播放頁面以下
7.小項目測試完畢後,但願引入一個大項目進行測試,因而開放了一個uv上千、pv幾十萬的大項目,採集一天的數據後,發現存儲數據正常,而播放頁面已經獲取不到數據,查看mongo的stats發現一天存儲量達到了1500萬條,每一條數據基本在幾十KB到幾M之間。
首先對不一樣的項目進行分表存儲,並將索引設置爲後臺處理,這個方案使用後播放頁面變得正常,但人員列表接口仍是很慢。
因而在每次存儲mongo時,存一份人員和日期的數據到redis中,目前系統已經正常運行,全部接口能在1s內返回全部數據。