大数据lambda架构实现方案
基础结构
此项目主要为拓客查找潜在企业客户,展示企业客户详情需求提供服务。借鉴DDD设计思想对域进行划分,由于需求比较简单明确,此处主要按主体类型划分为企业客户域、店铺客户域等。
目前仅针对企业客户域进行了重新设计,目录结构如下:
.
├── app.py <-- 服务入口
├── DarkPortal
│ ├── dark_portal.thrift <-- RPC接口声明
│ ├── connection.py <-- RPC服务配置
├── model <-- 数据模型
│ ├── entity <-- 实体
│ ├── value_object <-- 值对象
│ └── target_enterprise_customer.py <-- 聚合根(企业客户)
├── infrastructure <-- 基础设施
│ └── repository <-- 仓储
│ ├── dao <-- 数据访问对象
│ └── target_enterprise_customer_repository.py <-- 企业客户聚合根仓储
├── logic
│ ├── enterprise_customer <-- 增量逻辑
│ ├── advance_search.py <-- 高筛逻辑
│ ├── enterprise.py <-- 详情页逻辑
│ ├── search.py <-- 企业查询逻辑
└── test
└── increment <-- 增量逻辑单元测试
模型设计详见target_enterprise_customer
,仓储主要对外暴露增改企业客户接口、各类查询企业客户接口以及展示企业客户各类型详情接口,暂不涉及删除逻辑
增量更新
当前项目基于Lambda架构设计数据增量上线流程
Lambda架构
-
经典的lambda架构如图所示,分为三层结构
-
批处理层(batch layer),已有的切库流程属于此层,离线全量计算,稳定可靠
-
速度层(speed layer),实现数据实时性的一层,需保证计算逻辑与批处理层处理逻辑一致,复杂度远高于批处理层
-
服务层(serving layer),主要用于合并增量数据,将原查询函数转换成多个满足monoid性质的查询函数,合并查询结果,保证结果一致
-
-
Lambda架构存在比较明显的两个痛点,
- 必须维护两套代码(增量逻辑与全量逻辑),维护的成本高,任何需求变更均需反应在两套代码上,切需分开测试;容易出现数据不一致情况
- 当遇到部分宽依赖的计算逻辑,增量逻辑出现明显的性能瓶颈(比如过滤曾出现过的证书编号),可能需要权衡需求与计算资源, 无法做到完全一致。
-
目前主流的观点,增量逻辑并不严格可靠;需通过定时全量计算的逻辑来消除错误,保证最终一致性
数据流
-
内部库入库项目pytrans负责生产增量数据,通过定时任务
scripts.sync_increment_to_doncus
上传增量到OSS并调用tungee-bigdata-center服务创建增量入库任务,借由celery队列调用本项目对应RPC接口进行入库
明细数据更新
-
定期切库生产出的明细表collection的流程属于批处理层,基于此基础上,主要设计速度层以及服务层。此处设计了两张表用于满足需求:
- increment_collection:考虑采集数据本身不可靠且增量计算逻辑易错,设计increment_collection用于存储原始的增量数据,以内部库入库时间戳作为版本号区分时间顺序,即increment_collection的唯一标识为文档ID + 版本号。鉴于删除逻辑的特殊性且应用场景少,暂仅支持增量文档删除逻辑,不支持原始文档删除逻辑。
- merge_collection:实时查询时做合并逻辑性能不佳,添加了merge_collection用于按文档ID预先合并增量数据与存量数据。考虑预计算对计算性能的要求相对较低且需要能及时回滚或重算,合并逻辑需保证幂等性。目前此合并逻辑较为简单,通过文档ID遍历increment_collection所有有效增量数据,按时间戳顺序update文档即可
-
根据设计,当需要回滚增量时,仅需将某版本增量数据标记为失效,触发合并逻辑覆盖旧数据即可。而运营系统修改数据则是插入一条高版本的增量数据,触发合并逻辑覆盖旧数据即可
-
查询时,同时与collection和merge_collection建立连接,惰性有序的取出并按增量>历史版本的顺序合并查询结果(相当于对两个有序队列求交集)。由于一般情况下增量数据有限,查询性能受影响较小。对于聚合操作如count,则通过预计算二次维度的方式避免性能问题
-
整个流程封装成了DAO对象,仅对外暴露写入增量以及查询接口,保证视图一致性。代码以及表定义详见base_dao
聚合数据更新
-
明细表添加了增量数据,相应的聚合数据也需同步更新
-
同样考虑及时重算或回滚的需求,聚合计算的逻辑也需实现幂等。由于当前业务逻辑主要按照企业主体进行聚合,聚合的数据量有限尚可实时查询数据库取出所有依赖数据进行计算,部分数据倾斜导致取依赖数据耗时过长的逻辑通过特殊逻辑暂且跳过(比如招聘岗位过多)。此外聚合计算逻辑必须给所有维度赋予初始值,新的聚合数据为空或缺失导致数据覆盖异常
-
聚合计算对资源消耗太大,实时计算并不可取,所以增加了cache用于缓存聚合计算结果。为保证一致性,聚合数据更新到cache后通过定时任务同步到es
-
早期采用每入一条增量数据则同步重算关联所有企业主体的机制,保证了一致性但性能较低。鉴于实际需求仅需满足最终一致性且数据采集的常用的名单推送机制容易出现短期的增量数据均属于同一企业主体的情况,增加了任务队列cache_sync_queue,用于记录企业主体增量情况以及去重,再通过定时任务异步聚合计算,提高了计算性能
-
查询时,先从cache中获取数据,若有数据直接返回。若无数据则证明当前的企业主体无增量,直接查询切库时生产出的数据表即可