生活服务数据同步优化方案
数据落地方案
数据分析
生活服务需要定时拉取保存的数据有“商户,团购,电影”三类.
数据项 | 数据量 | 下载文件尺寸 | 是否有分页 | 更新频率 |
---|---|---|---|---|
团购 | 400w+ | 13G+ | 是 | 高 |
商户 | 200W+ | 1-2G | 否 | 中 |
电影 | 200w- | 5M- | 按城市 | 高 |
对于所有数据都要经过如下四个阶段
下载 -> 保存 -> 对比差异 -> 更新线上数据
对每个阶段都要想办法改进效率. 方案说明
- 下载阶段,经过测试接口响应支持gzip压缩,且提供一个Last-Modify-Since头.通过压缩 提升下载速度,通过保存每一页的Last-Modify-Since下次下载时进行对比,只下载更新 的页,可以进一步减少需要下载的数据.
- 保存->对比差异阶段,线下原始数据表需要保存每条记录的md5摘要作为主键,通过对比摘要得到更新的记录.最终得到对比结果,更新到线上数据表中.
- 更新线上数据这个阶段可能会锁表,所以大量的数据更新会导致长时间阻塞访问.现有数据表索引过多更新效率极差,通过重新设计数据结构优化查询方案简化索引定 义. 通过在前三个阶段过滤掉未变更的数据,减少最终需要查询更新的线上数据.当最终需要的更新的数据依然很多的情况下采取后台重建表的方案.
具体流程如下:
通过上述改进可以适当提升拉取数据的频率保障数据的及时性.
程序架构:
程序抽象
每个数据任务抽象出如下几个操作,需要由子类实现.
- pickAnyPage : 下载某个分页(分页的下载不一定按顺序)
- newPagePuller : 创建某个分页的拉取操作,该操作将http请求分为请求头部和内容两 部分.
- parse : 解析下载到的页面为数据记录
- update : 将解析的结果更新到数据库中
声明周期方法:
- init : 初始化准备,由子类实现
- execute : 执行该任务,调用其他组件完成任务,并记录程序状态保存为TaskStatus
- onFinish : 任务结束时,对TaskStatus进行处理,由子类实现.子类可以在此阶段实现任务监控.
AbstractDataTask是整个任务的模板,定义每个任务的公共环节,并记录每个环节的状态.
拉取分页->摘要对比->解析->摘要对比->更新数据库
进一步优化
更新线上数据时需要进一步降低更新成本
- 缩小文档体积(减少冗余存储的数据)
- 合并索引,减少数据更新时需要更新的索引数量
- 以商户为中心进行查询,所有团购以商户卡片形式进行组织