图3.5.1 alias早期数据结构设计
alias利用Redis的Set和Hash结构实现正查和反差的功能,为什么反差用hash,前面讲到1个设备在1个alias_type下只保存最新的alias。这也是出于保护用户的目的,如果1个设备同时存在多个alias下,在开发者执行圈选的时候可能会多次选出这个设备造成多次无效触达。
这个设计平淡无奇,的确也可以满足绝大部分客户的筛选场景,但是随着业务量的增加有几个问题逐渐暴露
轮询成为海量设备查询的瓶颈,且不可突破。
Redis数据持久化难的问题凸显,数据分析难上加难。
Alias无法很好的满足数据返还链路的需求。
3.4.2 研究Alias的解法分库的确是很好的思路但是仍然无法满足性能问题和持久化问题,而且随着行业对大数据的关注,数据返还也成为更多开发者的诉求。打通数据返还链路做好客户数据的存、取、管、用已经是一个重要的行业方向。为了解决这个问题U-Push通过离线和实时相结合制定措施
分库,增加KA级别客户独享库,压缩横向扩容空间。
分层,基于Lindorm做持久化分层存储。
离线留存,通过日志系统留存下行筛选结果,一方面完善统计需求,一方面通过回执返还客户。
3.4.3 基于Lindorm宽表的分层设计用宽表代替Redis的Set设计做正查,用普通表基于设备ID的联合主键做反查,在查询时候通过将单次轮询改为多次mget尽量压缩IO损耗寻找响应性能和服务稳定的中间值,Lindorm的磁盘存储可以满足业务需求的同时通过exporter的配置实现lindorm数据T+1同步至ODPS。
图3.5.2 基于Lindorm款表的分层设计
3.4.4 数据迁移的尝试和思考数据迁移是在很多业务架构中都是痛中之痛,如何保证稳定、平滑、安全的迁移需要付出大量的成本。U-Push在Alias的数据迁移中做了多种方案的研究和思考。
Tair整体dump迁移,dump方案理论上可行但是有较大的业务风险,出于稳定性的考虑放弃。
写请求增量更新,通过客户的写请求逐key迁移,会有漫长的灰度时间,且无法执行彻底清理,胜在稳定性强。
扫描设备主库,分客户批次灰度迁移。在U-Push的功能中,提供了appkey下alias_type的功能,客户可以在开发者控制台查询appkey下的alias_type列表,为实现这个功能对appkey和alias_type做了集合索引,这个索引成为数据迁移的关键。通过扫描设备库获取appkey和device_token,结合alias_type去反查库查找alias,再拿appkey+alias_type+alias去正查库查询device_token列表完成迁移。
第三种方法可以实现存量数据的完美迁移,对线上服务几乎没影响,但是在百亿级设备下,以1wTPS计算仍然需要10天的时间,好在该方案可以实现单个客户的灰度与回滚。
5. 结语