在上一篇《网站数据统计分析之一:日志收集原理及其实现》中,我们详细的介绍了整个日志采集的原理与流程。可是不是这样在真实的业务环境中就万事大吉了呢?事实每每并不是如此。好比针对前端采集日志,业务的同窗常常会有疑问:大家的数据怎么和后端日志对不上呢?后端比大家多了 N%!技术的同窗也会问:大家怎么不打后端记日志呢?后端比大家效率和准确性更高。带着这些疑问今天我们就来聊聊前端日志采集中的这些是是非非。javascript
这应该算是统计分析同窗最为关注的问题之一了,到底哪一个准咱们应该从技术和业务两个角度来看待这个问题。前端
日志采集从技术架构层面而言就两种,前端与后端。前端日志采集说白了也就是页面部署统计代码,经过java
<img src='/log_xxx.gif?k=v'> 或者 javascript 发送 ajax 请求的方式来发送日志请求。后端通常在 webCGI 中经过日志 API 接口输出日志(好比 java 中 log4j),或者直接 webServer 中打印日志(好比 Tomcat)。那这两种技术方案各有何优劣呢?git
优点:轻量,调试友好,可扩展性维护性好github
劣势:数据不安全,易丢失,客户端环境复杂兼容成本高web
优点:数据完整性有保证,业务数据安全ajax
劣势:对后端业务代码有必定侵入性,容易受爬虫影响,非后台交互行为日志采集不到数据库
经过上面比较咱们能够看到先后端采集方案各有优劣,仅从数据量角度而言,后端日志采集方案能保证日志更为完整准确。编程
从业务架构出发,日志主要分为三大类:后端
行为日志:浏览、点击、各类交互行为等
行为日志通常侧重于用户各类行为交互、用户属性采集,用来评估用户体验、运营效果或者最后数据挖掘。好比漏斗、留存分析。
业务日志:用户、帖子、订单、库存等
业务日志每每和后端数据库、应用服务强关联,而且每每对日志有特别高的安全、性能、稳定、准确性要求,好比计费、支付等。
系统日志
这类日志通常用来衡量监控系统健康情况,好比磁盘、带宽是否满了,机器负载是否很高,或者RD本身经过程序输出的应用日志,用来监控应用服务是否异常,好比接口是否有超时,是否有恶意访问等。
对于行为日志而言,前端 js 采集脚本为了避免影响主体业务逻辑以及取得相应业务参数,通常放在页面底部。假设我们某个页面200个请求,后端日志会在某个请求返回给客户端以前就记录日志,而前端日志此时就比较吃亏了,须要等到浏览器执行完200个请求到页面底部 js 时,才能发出请求,这当中的时间差是日志差距的主要缘由之一。那么问题就来了,若是一个页面用户打开后没加载执行完(由于前置js错误、性能延时、主动关闭等),应该算一个 pv/uv 吗?这种场景下,通常是认为不该该算的,很显而后端“抢跑”了,并且会比前端多很多。这个差别和你的页面复杂程度,用户网络质量密切相关,就实测数据来看,页面顶部到页面底部会有 10%左右差别,前端与后端会有20%以上差别。
这个和公司的业务密切相关,通常都会有竞品或者其它商业、科研目的的爬虫抓取网站信息,低级的爬虫不会触发 js 请求,但会记录服务器日志,高级的爬虫封装了浏览器内核的才会执行 js 代码,这也是先后端日志差别的重要缘由之一。
在移动端前端 js 请求丢失率更高,由于网络情况很是复杂,2G、3G、4G、WiFi 等等,请求从客户端发出来,因为不稳定的网络条件,不必定能到前端JS日志服务器。
M端部分浏览器默认是单标签的浏览方式,任何一个点击、上一页、下一页按钮都会致使下一个页面会覆盖上一个页面,进而致使后端有日志可是前端没法记录到用户日志的状况。
另外一种状况是可能部分老的移动端浏览器甚至都不支持 js,这就彻底丢失了这部分日志。
缓存、以及其它的用户行为也可能致使请求执行到了,可是没有发送成功,好比用户在页面加载完成后,请求还未发送完成时关掉页面,可能致使请求被 cancel 掉,这对一些用户黏性不是很强,跳出率很高的网站而言是另外一个差别来源。
综上所述,到底哪一个准实际上是相对而言的,得分业务场景来看,不可能有一个绝对值,至于用哪一个就看你具体的业务诉求了。
前端 JS 日志只适合用来作全流量分析与统计,更多的是用来反应总体的流量趋势与用户行为,并不能精确到单个的用户行为与单次的访问轨迹。它的优点在于与后端解耦,调试、扩展、采集方便,额外的开发成本很低,适合作成 SAAS 模式。这也是为何百度统计、GA它们采用这套方案能作成一款行业通用,甚至全球化的数据产品。
若是对日志有特别高要求的业务场景好比计费、支付等等,要求日志一条不丢同时日志安全稳定,那就必须依赖数据库或者后端日志,但相应的开发维护成本会大些。
记得几年前流行过一句经典语录:幸福是个比较级,要有东西垫底才感受的到。言外之意也就是说凡事通过比较后,才能区分出优劣。回到我们的话题,早期创业公司通常会选择第三方统计系统,一来成本低,二来投资人每每须要看第三方数据对你公司的业务运营状态做出评估或者估值。但第三方统计只能作通用统计,对个性化的统计与深度数据挖掘无能为力,并且企业的商业机密堪忧。所以业务作大后公司每每会选择本身搭建数据平台和日志采集系统。那么问题立刻接踵而至:本身的日志怎么和 GA、百度统计对不上呢?甚至这几者中任意两个都存在必定差距。
其实缘由大抵都是1.3中提到的缘由,除此以外还有比较细节的技术实现差别,好比请求大小,域名是否被屏蔽(好比去年 5月开始 GA 就被墙了)、第三方 Cookie、埋码是否彻底、统计口径与规则等等。
当你发现其中存在差别时,须要验证各类可能缘由去校验数据,如无特殊缘由,最终应该以本身采集的为准。
在 1.3.1 中提到了一些内部线上测试数据,外界也有一些同窗作过相似的测试,结论都差很少,部分业务场景下丢失率高到难以想象。好比点击前发送日志而后当即跳转,若是不作任何优化处理,这种场景的丢失率巨高,每每超过 50%。
从技术角度能够概括为两点:
用户关闭页面过早,统计脚本还未加载/初始化完成
用户关闭或者跳出页面的时候,请求未发出
针对第一点,几率较小,通常的处理方式就是,不要把统计脚本参合到其余脚本中,单独加载,而且放在前头,让它优先加载。不少公司的作法是,不让开发者关心统计脚本的加载,用户请求页面的时候,Nginx 会在 Body 开始标签位置注入一段脚本。或者把 js 动态请求换成 <img src> 硬编码的方式发送请求。
对于问题二,处理方案就有不少了。
还记得 XMLHttpRequest::open 方法的第三个参数吧,若是设置为 false 就是同步加载,
window.addEventListener('unload', function(event) { var xhr = new XMLHttpRequest(), xhr.setRequestHeader("Content-Type", "text/plain;charset=UTF-8"); xhr.open('post', '/log', false); // 同步请求 xhr.send(data); });
阻塞页面关闭,固然能够在 readState 为 2 的时候就 abort 请求,由于咱们不关心响应的内容,只要请求发出去就好了。
原理跟上面相似,只不过是使用一个空的死循环阻塞页面关闭,
window.addEventListener('unload', function(event) { send(data); var now = +new Date; while(new Date - now >= 10) {} // 阻塞 10ms });
大部分浏览器都会等待图片的加载,趁这个机会把统计数据发送出去
window.addEventListener('unload', function(event) { send(data); (new Image).src = 'http://example.com/s.gif'; });
以上提到的几个方案都是一个原理,让浏览器继续保持阻塞状态,等数据发送出去后再跳转,这里存在的问题是:
少许浏览器下可能不奏效
等待一下子再跳转,用户体验上打了折扣,尤为是移动端上
是否有更好的方案解决这个问题呢,前端同窗秉着「小强精神」也提出了两个可实践的方案。
不就是埋点统计数据嘛,非得在当前页面发送出去?优化方案的思路具备必定的跳跃性,咱们考虑将数据在下跳页中发送,那么问题就转换为,如何将数据传递给下跳页?
对于连接点击量的统计,咱们能够将连接信息经过 url 传递给下跳页,传递思路以下:
经过数组标识一个连接的位置信息,如 [站点id,页面id,模块id,连接index],经过四个参数能够唯一标识连接位置属性,使用 URL param 参数将数组数据传递给下跳页,等待由下跳页将数据发送出去。
这里存在的问题是,下跳页中必须部署一样的统计脚本,但对一个系统来讲,这是很容易作到的。咱们也不会在本身的网页上放其余网站的连接吧,因此整个数据的统计都在一个闭环内。还有就是若是统计业务复杂的状况下,这种方案的维护成本与用户体验不好。
window.name 是浏览器给咱们开放的一个接口,设置该属性的值后,即使页面发生了跳转,这个值依然不会变化,而且能够跨域使用。
这里存在的问题是,该属性可能被开发者用于其余途径。咱们能够限制开发者直接使用 window.name,封装接口,经过接口调用,如 aralejs 提供的 nameStorage,
nameStorage.setItem(key, value); nameStorage.getItem(key); nameStorage.removeItem(key);
储存形式为:
scheme nameStorage datas | | ------------ ------------------------ nameStorage:origin-name?key1=value1&key2=value2 ----------- | window origin name
以上虽然基本解决了数据丢失和体验差的问题,可是这也很大程度依赖于开发者的编程习惯,如不能随便玩耍 window.name ,业务复杂的场景下容易出问题,好比容易被覆盖;也对系统有必定的要求,必须在全部页面上部署一样的埋点脚本。
localstorage 是 HTML5 提供的两种在客户端存储数据的新方法之一,对于丢失率高的场景,我们能够先把请求日志存储在 localstorage 中,失败后在下个页面重发,而且能够添加剧试机制,这样日志的完整性能很大程度上提升。从性能角度讲还能够统一发送,减小链接。
可是针对跳出率高的场景,这种方式实测效果并不明显。
上面提到的各类方案,不乏黑科技,然而存在的问题仍是一大堆,若是团队的开发者执行力不够,中途容易出现各类麻烦。因此真正可以解决这个问题的,必然仍是浏览器自己!
为何不能给用户提供这样一个 API,即便页面跳转了,也可以将上个页面的请求发出去呢?庆幸的是,W3C 工做组也想到了这个问题,提出了 Beacon API 的 草案。
Beacon API 容许开发者发送少许错误分析和上报的信息,它的特色很明显:
在空闲的时候异步发送统计,不影响页面诸如 JS、CSS Animation 等执行
即便页面在 unload 状态下,也会异步发送统计,不影响页面过渡/跳转到下跳页
可以被客户端优化发送,尤为在 Mobile 环境下,能够将 Beacon 请求合并到其余请求上,一同处理
sendBeacon 函数挂在在 navigator 上,在 unload 以前,这个函数必定是被初始化了的。其使用方式为:
window.addEventListener('unload', function(event) { navigator.sendBeacon('/collector', data); });
navigator.sendBeacon(url, data);,第一个参数为数据上报的地址,第二个参数为要发送的数据,支持的数据格式有:ArrayBufferView, Blob, DOMString, 和 FormData。
Beacon 的还有一个很是实用的移动端使用场景,当用户从浏览器切换到其余 app 界面或者 Home 屏的时候,部分浏览器默认会中止页面脚本的执行,若是在这个时候使用了 unload 事件,可能会让你失望,由于 unload 事件并不会触发,此时,Beacon 就派上用途了,它是不会受影响的。
本节是对页面打点丢失问题的简单探讨,枚举了咱们一般会用到的一些解决方案,可能不是很完善,若是你有更好的建议,能够提出来。
不少问题,咱们绞尽脑汁,可能不多会考虑,这个问题是否是应该由咱们来解决,或者说这个问题交给谁处理是最恰当的。本文的探讨能够看到,浏览器自己才是最好的问题解决方,当网站流量变大以后,上面提到的丢失问题就更加明显,这也迫使浏览器自己作了改善,天然也在情理之中。
至此,本文探讨了前端日志采集过程当中的一些常见问题,解释了数据分析以及RD同窗一些常见困惑,并提供了一些相应的优化思路与方案。文中提到的各类问题仍是以 PV 为主,其实还存在另外一个常见的指标差别:UV,这个指标的差别缘由更为复杂,改天有空再详细分享下。总之日志采集与统计分析没有部分同窗想象的那么简单,这里面的坑其实不少,须要你们不断的去探索,从技术和业务角度去不断优化改进,前路漫漫。
说明:本文第四节结合了 Refer [1] 以及本文做者的实际经验整理而成,在此致谢,感谢分享。
[1] 页面跳转时,统计数据丢失问题探讨
http://www.barretlee.com/blog/2016/02/20/navigator-beacon-api/
[2] 网站数据统计分析之一:日志收集原理及其实现
http://my.oschina.net/leejun2005/blog/292709
[3] 站长统计、百度统计、腾讯统计、Google Analytics 哪一统计的数据相对准确些?
https://www.zhihu.com/question/19955915
[4] 网站分析——咱们的数据准确吗?
[5] 为何两个监测工具报告中的数据不一样
[6] JavaScript API 调用说明
http://help.dplus.cnzz.com/?p=62#dplus.track
[7] 数据采集与埋点
http://www.sensorsdata.cn/blog/shu-ju-jie-ru-yu-mai-dian/
[8] Beforeunload打点丢失缘由分析及解决方案:
http://blogread.cn/it/article/6804?f=wb
[9] beforeunload丢失率统计:
http://ued.taobao.org/blog/2012/11/beforeunload%E4%B8%A2%E5%A4%B1%E7%8E%87%E7%BB%9F%E8%AE%A1/
[10] 互联网数据分析的底层应用架构
https://zhuanlan.zhihu.com/p/24018306
[11] 数据处理中的准确性问题