这个方案首先会节省WebView launch的时间,这段时间可以直接网络传输,另外如果本地有offlineCache甚至也不需要网络传输请求,相当于完全加载一个本地页面。但很多时候我们为了保险起见,还是加了页面loading,然后做refresh的操作防止数据的不一致性。 这套机制上线后效果不错,但真的去实施这种H5加载模式会遇到一些坑,例如产品经理配置的banner图片和item数据可能会存在多份数据版本不一致的情况。 产品经理肯定是在dataServer上配置最新数据信息,但CDN上的页面内置的数据有可能仍处于上一版本,更差的情况是离线包服务器和offlineServer生成的HTML又是另外一个版本。当用户本地的缓存和server同步不及时即常见的缓存刷新问题,很有可能存储的数据又是另外一份。 所以这套系统刚开始灰度试用的时候,产品经理很快就找我们吐槽:打开页面时看到的是一份数据,过了一秒页面刷新后看到的内容又不一样,而且每次进入页面都会发生这种情况。 如何统一数据 如何快速把四个版本的数据全部统一?我们针对静态直出这种模式做了小型的自动构建系统,产品经理在管理端配置数据要同步dataServer时,我们会立刻启动我们内部称为vnues的构建系统。 这套系统是基于Node.js搭建的,会把开发所编写的代码文件和UI素材图片等等数据实时生成最新版本的HTML,然后发布到CDN以及同步到offlineServer上,这可以解决CDN的文件与最新数据不一致的问题。 但离线包缓存是放在用户手机上的,我们如何最快速地把用户手机上的离线缓存也更新起来?大家可能会这么做:QQ客户端每次登录上来把offlineServer最新文件下载回来就好了,但这个方案会遇到巨大的流量挑战。 QQ现在每天的活跃用户好几亿,登录峰值差不多十几万每秒,即使一个100KB离线包的更新,发布一次动辄就需要几百GB的带宽,无论从成本还是技术层面都不是我们能接受的事情。 我们offlineServer内部分为流控和offline计算两部分。当一个页面的所有资源需要进行离线包计算打包的时候,offline计算这部分除了把所有的资源打包,内部也会存储之前所有的历史版本,同时根据历史版本和最新版本生成所有的diff,即每个离线包的差样部分。 这个方案也是根据我们业务形态而定的,因为每次产品经理更新的页面数据并不会太多,基本是几KB到10+KB的范围,所以我们没有必要每次离线包的更新都让用户去下载全量的包。 当QQ用户登录后,每次都会询问offline流控server看有没有最新的包可以下载,如果当前流控server统计的带宽在可接受的成本(目前暂定为10GB到20GB的空间),当CDN的带宽撑得住的时候就会把最新的diff下发给客户端,这样就做到离线包一有更新时客户端能以最小的流量代价得到刷新。 数据以及效果 通过这套系统,我们只花了十几GB的带宽,就把整个BG所有H5业务的离线包覆盖率维持在大概80%到90%。从这个工作中我们也发现一个非常反常规的事情,即大家以为离线包预推会非常消耗带宽,但其实只是偶尔预推才消耗大量带宽;如果长年累月不停地推送,实际上对带宽的消耗非常小,因为时时刻刻都保持在差量下发的状态。 做了这个工作后我们采集了现网数据,静态直出和传统页面这两种模式对比非常明显。下图页面耗时部分,由于静态直出页面不需要任何JS执行,只需要WebView渲染,所以页面耗时静态直出相比传统页面降低了大概500毫秒到1秒左右。 这里有趣的现象是离线包的性价比问题,可以看到传统页面使用离线包可以在网络耗时部分节省700多毫秒,但静态直出这种模式使用离线包只能节省300毫秒左右,这是因为使用静态直出在网络过程中所依赖的外部CSS和JS都已经直出到HTML内部了,不需要额外的网络请求,所以其本身网络耗时有所减少,这时使用离线包的收益开始逐渐下降。 这里可能有疑问,为什么静态直出在离线包的情况下网络耗时还需要800多毫秒,本地有缓存不应该是零耗时吗? (责任编辑:本港台直播) |