@pockry
2017-07-17T19:40:54.000000Z
字数 2516
阅读 3118
移动
随着移动互联网和大数据技术的发展,智能手机的普及,几乎所有工作、学习、生活中的所有场景都离不开手机,手机APP已经取代了传统的生活方式,让人们可以体验便捷高效的服务,当然它也承载着大量丰富的信息,收集这些APP的数据,集中对数据进行清洗和分析,就能将这些海量数据变为有价值的数据能源。数据采集是开发数据能源的第一步,如何采集数据,什么样的技术架构能够支持海量数据的采集、甄别和传输,这是本文需要讨论的问题。
与PC端不同,对于手机、iPad、智能手表、电视盒子等移动设备,我们触达它们的载体就是APP。原生SDK在多语言上支持上需要投入很多的开发资源,跨平台应用开发渐成趋势,但JS SDK在各框架上的实现也各有差异,因此,目前移动采集SDK在对多平台、多语言的支持上难度较大。
难度更大的是对Android设备的机型适配问题。由于Android系统的开源特性,各厂商为了在各家机型上有更好的用户体验,都有针对性的做了ROM改良,尤其近些年Android在虚拟机、编译器上的改动较大,这就给机型适配带来更大的难度。为了不给App带来卡顿、闪退、黑屏、崩溃、加载速度慢等差的体验,还需要支持开发者各种异常方式的接口调用,需要有极强的容错性。
移动端的流量在持续的增长,“友盟+”SDK在移动端覆盖的APP超过135万款,覆盖全球移动设备日活跃数超过14亿个,每天处理的数据量达280亿,庞大的数据每天都在考验着我们的采集SDK和服务端的承载能力,我们在移动端采集技术上不断更新迭代,持续多年保持市场覆盖领先的地位。
我们最初SDK的设计思想是简单高效,因此在SDK端没有任何对数据预处理的逻辑,甚至缓存策略也非常简单,所有实时产生的数据都会实时上报服务器。但随着移动端流量的暴涨,这种高并发的请求对服务器带来很大的压力。下图是1.0版本的通信协议。
于是考虑通过控制发送频率来减小并发,开发者可以根据业务需要采用不同的发送策略:启动、间隔、退出发送,并且在平台可随时变更。虽然有效减小了服务端的压力,但又带来了另一个问题,单条数据的包体大小有可能超过request-body的上限,导致请求超时。并且流量压力同样是需要亟待解决的问题,于是,在2.0版本上我们对数据进行了压缩,并增加了安全机制。 服务端增加了数据预处理的逻辑,完善了对数据的校验。
只能单向通信的协议是不灵活的,有很多时候我们需要SDK的行为进行一些控制,比如发送策略的修改、屏蔽错误埋点数据,或者发现数据被污染决定抛弃,这些操作服务器需要通知到SDK,并且在没有长连接的情况下该怎么做。在3.0版本上我们把http请求的response的信息包体设计控制语义,SDK除了从response获得服务器的接收状态,同时可以获得服务器的控制指令,从而实现服务器想要得到的效果。
如果每一条Log都必须等待并解析服务器返回的控制信息,显然服务器对数据处理的时效性和并发处理能力会大大折损,并且有些业务数据其实无需解析并执行这些控制信息。因此,我们对业务数据进行了精细的分解,一些业务数据使用双向通信协议,能够解析并执行控制指令,其余的业务数据属于状态无关数据,仍然使用单向通信协议。
那么未来其实还可以将控制协议与业务传输协议分离,各自使用不同的发送频率,但又能保证所有业务数据是受服务器指令控制的。
移动数据采集SDK架构主要由三部分组成:用户接口、业务模块和控制模块。
我们可以从几个场景的时序图来解析这几个模块的工作原理。
用户启动App的时候,其实是触发了开发者调用的初始化接口,Service Moudle和Control Moudle会异步的进行一些初始化的操作:创建Session、加载设备信息等。
当用户在APP中有点击、滑动屏幕的行为,会触发开发者在APP中预设置埋点事件。
Servie Moudle会生成相应的事件数据,调用Control Moudle的接口检查发送策略和安全策略,之后Servie Moudle会将事件数据放到缓存队里中待发送。
无论用户退出APP后,SDK还会在短暂的瞬间完成很多操作:结束Session、持久化保存数据,在iOS中还会直接完成数据封装、打包、上报的工作。
我们提供的产品功能越来越多,业务场景越来越复杂,为了满足各种各样的解决方案的需求,SDK需要为各个业务场景维护多个分支、多个版本,开发资源浪费、版本迭代周期拉长,为了解决这个问题,我们必须要设计一个灵活的架构,使每个产品功能变成可自由组合、拆卸的组件。
组件化将统一约定package和public API的文件规范。针对当前业务的需求,建立标准的SDK产品公共库(如:network,serialize,configure,cache等),组件化结构分为两部分,Common将作为一个独立的library package,而Component中每个产品作为独立library。
其结构如下:
组件的划分的颗粒度,可以根据业务需求,我们的设计是根据产品,或者业务来划分组件。一个产品可能包含很多功能,比如统计产品包含事件数据采集、错误数据采集、A/B Test等功能,Push产品包含消息推送和应用内消息,在某些场景下,可能有些开发者会只使用部分功能,比如,只用错误分析功能和Push的消息推送,那么组件颗粒细化到功能层,就会更加灵活,可满足更多场景的需求,并且体积的减小是对开发者来说是非常有吸引力的。
组件化的架构改变了以前业务逻辑与基础功能深度耦合的状况,业务开发人员可以专注于业务逻辑的实现,而不需要考虑如网络通信、消息队列管理、设备信息采集等基础功能的实现。业务逻辑代码的任何改动,不会影响基础功能逻辑,加强了代码的健壮性,同时在回归测试周期上也大大缩短。
【友盟+】数据采集技术将持续的适应业务场景的变化,未来我们的目标是让我们的SDK更加智能,更加安全,让企业及开发者集成更加简单、数据更加精准。