特点
- 及时,近乎实时上报
- 批量上报,同时规避大数量单次上报
- 很好的解决埋点数据大量密集涌入的情况
- 耗时操作剥离主线程,不影响用户的正常操作
- 处理线程异常,增强应用稳定性
- 利用RxJava和OKHttp已有线程池,不显式增加新线程
- 重试机制支持,增加重试时机,保证之前失败数据达到数据平台
实时上报机制
先举一个例子
- 将埋点数据比作乘客
- 将数据平台比作目的地
- 而App的上报请求就是客车
- App则是负责发车的调度这
当调度者(App) 发现有一个乘客(埋点数据)时,就安排这个乘客上车,然后开始计时
- a.如果超过5分钟(举例需要),没有新的乘客乘车,就立即发车,被送达到目的地
- b.如果5分钟内,有新的乘客过来,就重新计时,按照a,b情况去匹配操作
- c.特殊情况,如果发车时,乘客过多,调度者会安排多辆客车立即发车(不再走a,b情况处理)。
调度者通过反复上面的操作,就会将乘客源源不断地送达到目的地
分批切块逻辑
- 为了规避大量数量(洪水般)数据单次上报带来的问题,我们队数据进行分批切块处理
- 分批切块处理后的每块的数据顺序保持原数据的顺序,比如
[1,2,3,4,5,6,7,8,9,10]
以3为一块的容量,可以分为[1,2,3]
,[4,5,6]
,[7,8,9]
,[10]
失败处理
- 无网络时收集的请求会写入文件
- 请求失败的数据会写入文件
- 当
网络请求恢复
和用户进入前台
和应用启动
时会上报失败的数据 - 具体实现的数据持久化处理,可以参考AsyncDataPersister
线程策略
- 关于执行线程并没有严格的限制
- 考虑到App的稳定性,我们结合RxJava的相关处理机制,将字符串与实例对象转换等,放在了工作者线程。
- 但是写入失败数据和读取失败数据,由于是IO耗时,我们也放在了工作者线程。
- 网络请求,我们利用了OKHttp的自有线程,并没有进行外部线程控制
不足与问题
- 极端情况下,可能会造成某些数据丢失(之前的实现方式也有问题)
- 分批切块的阈值缺少实践验证是否为最佳数值
- 实时上报检测时间阈值可能并非最佳
调试日志
adb logcat |grep --color=always -E "BufferedUsageEventUploader|UsageEventUploadManger|SecooDataUploader|AsyncDataPersister"