1、背景html
奕星 (EAS) 是腾讯内部专一于游戏营销活动分析的系统,在营销活动效果分析中,奕星遇到一个最大的问题就是对活动参与人数的去重,并给出对应的活动号码包。单个营销活动的周期是固定的,但活动与活动之间时间不多会有彻底相同的状况。
好比A活动时间是1-10号,B活动是5-15号,那么若是想分别获得 A 和 B 的去重参与人数,则必须分别开启任务对 A 和 B 在他们所属的时间区间内进行计算去重。在海量日志中天天对数千个营销活动进行相似计算,对资源消耗是一个不小的挑战。
而实际状况下,须要计算的任务量还远远不止于此,奕星同时还提供游戏官网非活动连接的去重数据,甚至每一个连接在每一个推广渠道的去重数据,这个任务量级目前高达天天 50W+ 以上。
总结来看,面临的主要问题就是如何在海量数据的状况下,处理数量巨大的并且周期各不相同的去重计算任务。node
2、原有解决方案算法
对于这个问题,奕星以前尝试了很多方案,这里简单介绍一下。
1. 基于TDW临时表的方案
TDW 是腾讯内部通用的一站式大数据平台,服务稳定,功能强大。对于这些任务的计算,奕星最先是想借助于 TDW 的计算能力来完成。
思路很简单,就是在 pysql 中循环对每一个活动执行对应的 hiveSQL 来完成 T+1 时效的计算。
但这个方案最大的缺点就是:任务基本都是顺序执行,重复扫描大量日志,致使效率很是低下,并且从HDFS中拉取最终的去重文件也很是耗时。
虽而后面采用多种思路优化,好比将原始日志先天天统一批量去重一次入到临时表里,全部计算基于临时表来完成等,但最终仍是效率没法进一步提升而放弃。
2. 基于实时计算+文件增量去重的方案
在奕星的数据统计中,基于 Storm 的实时计算任务,主要是提供各个活动的实时 PV 和参与次数等计数类数据。
因为内存资源有限,业界也有基于近似去重算法(如 hyperloglog )直接在 Storm 中算出近似去重结果的,但没法给出精确的结果和最终的号码包文件,因此不符合选型要求。
而内存资源有限,更不可能容纳下这么大量的号码包数据,因此经过内存彻底得出最终精确去重结果的方案基本不现实。
但内存虽然不能容纳整个活动期间的号码数据或者一天以内的号码数据,可是否能够容纳 1 分钟,5 分钟的号码数据?
经过测试计算发现,在内存中缓存 5 分钟内的去重号码数据是彻底可行的,而且最高能够将原始日志下降 90% 以上的量级。缓存 1 分钟的话,最高也能够将原始日志下降 70% 以上的量级。
主要的缘由是玩家参与活动的时候是即时参与行为,好比一个玩家来到一个活动页面后,通常是连续将活动中能参与的功能都参与下,不会参与完一个等好久再参与下一个,因此致使同一个玩家的日志时间连续性较高,单位时间窗口内去重后量级会下降不少。
基于此,目前奕星主要是基于 Storm 在单位时间窗口内进行初次去重,以达到下降原始数据量级的目的。
最初的基于 TDW 的去重方案,除了重复扫描等问题外,还有一个问题就是:同一个活动不一样日期之间的计算没法先后衔接,好比 A 活动在活动期间(1-10号),天天的计算逻辑基本一致,都是要全量扫描 1-10 号之间的日志(或中间结果)来完成计算。
因此团队将目光投向如何在活动前期去重的基础上来增量去重的问题上来。最终选定的方案是基于文件的计算方案,以下图所示,活动天天都滚动生成最新的去重号码包文件,而第二天同一个活动的日号码包再与这个总包交叉后获得更新的号码包文件,如此重复,直到活动结束获得最终的活动号码包文件。
3. 基于实时计算+LevelDB增量去重方案
文件增量去重的方案,运行了一段时间后,就出现了一个很大的问题:就是每日新增的文件量巨大,日均几十万。
虽然没有达到把单台机器 inode 占满的状况,但在增量去重时,大量的小文件 IO 操做,致使增量去重效率很是低,最后被迫只支持高优先级业务的活动和单个活动参与量大于必定阀值的大活动。
通过团队小伙伴的调研,最终将目光锁定在 Google 的 LevelDB 上,LevelDB 是 Google 开源的持久化 KV 单机数据库,具备很高的随机写,顺序读/写性能,可是随机读的性能很通常。
也就是说,LevelDB 很适合应用在查询较少,而写入不少的场景,这正好符合咱们号码包去重服务的应用场景。
另外号码包的存储自己也是一个K-V的存储,文件名为 key,文件内容为 value,正好跟 LevelDB 支持的 K-V 结构相似。
使用 LevelDB 后,能够毫秒级获得某个活动的准确去重人数,而且能够在 10 秒内导出千万量级的号码包文件,相比传统的文件操做,大大提升了号码包去重服务的总体效率。
3、基于CLickHouse的解决方案sql
虽然基于 LevelDB 的去重服务能够很好的知足大部分营销活动的人数去重需求。但扩展性较差,数据回溯困难等问题比较突出,
类
似于基于预计算模式的 O
LAP
系统。
好比系统只支持活动整个期间内的去重人数计算,若是想知道活动期间内某一段时间内的去重就没法实现。
另外若是某个活动引入了脏数据后,只能将整个活动的
K
-V
结构删除后重跑,很是耗时。
团队通过调研后,将目光锁定到基于
M
PP
的
O
LAP
方案上。
基于 MPP 的 OLAP 系统,在数据库非共享集群中,每一个节点都有独立的磁盘存储系统和内存系统,业务数据根据数据库模型和应用特色划分到各个节点上,每台数据节点经过专用网络或者商业通用网络互相链接,彼此协同计算,做为总体提供数据库服务。
相对于基于预计算模式的 OLAP 系统来讲,它最大的优势就是灵活,扩展性强,而最大的缺点是响应时间不及时,甚至须要较长的时间等待。
而在营销活动效果分析中,每每灵活性比效率要更加剧要,或者说效率是能够稍微妥协的一面,因此咱们选择基于 MPP 的 OLAP 系统。
目前市面上有不少优秀的 OLAP 系统,但要么是收费的(Vertica),要么是基于 hadoop 生态的(presto,Impala),总体架构比较重。
而做为战斗民族开源神器的 ClickHouse 不但拥有本身的文件系统和极高的压缩比,在集群部署上甚至能够不用 zk 来独立部署,甚至在性能上“吊打”商业的 OLAP 系统(详见
官方测评数据:https://clickhouse.tech/benchmark/dbms/
)。
综合以上考虑,最终选择了 ClickHouse,去重服务就变成了 SQL 查询,例以下面这条 SQL 就是查询 LOL 官网某个页面在 9 月 6 日这 1 天的 UV:
select uniqExact(uvid) from tbUv where date='2020-09-06' and url='http://lol.qq.com/main.shtml';
在 24 核 96G 内存的机器上,实际测试下来在 1 亿条记录中,精确去重一个参与量为100W 的活动,仅需 0.1 s 不到,而导出这个号码包文件只须要 0.2 s 不到。
虽然查询效率上比 LevelDB 有一点差距,但灵活性却大大提升,能够任意指定时间区间和条件来作去重查询,符合当前业务场景关注灵活度的需求场景,并且性能上从毫秒到秒级的延迟基本也能够接受。
4、结语数据库
去重服务的的问题伴随奕星系统整个开发和运营周期,期间经历过不少尝试,部分临时的尝试方案还没有在本文列出,但一直的出发点就是业务需求自己,而且结合当时的运维环境来选取对应的技术方案。
不追求绝对的高性能(意味成本也高),而关注最合适,易于扩容,搬迁,故障替换等有利于服务长期稳定运营的特性。固然,随着更多利器的出现,也会去不断的尝试使用,毕竟科学技术才是第一辈子产力。
目前 ClickHouse 在奕星等多个数据系统和诸多个性化营销分析的场景中落地使用,数据总规模超过 5 千亿,还在不断增加中。