GMTC北京站9折购票倒计时,部分日程已上线,戳此查看 了解详情
写点什么

快手 HBase 在千亿级用户特征数据分析中的应用与实践

  • 2019 年 7 月 24 日
  • 本文字数:3569 字

    阅读完需:约 12 分钟

快手 HBase 在千亿级用户特征数据分析中的应用与实践

快手建设 HBase 差不多有 2 年时间,在公司里面有比较丰富的应用场景:如短视频的存储、IM、直播里评论 feed 流等场景。本次只分享其中的一个应用场景:快手 HBase 在千亿级用户特征数据分析中的应用与实践。为什么分享这个 Topic?主要原因:对于大部分公司来说,这都是一个普适的场景,因为很普遍,所以可选择的分析引擎也非常多,但是目前直接用 HBase 这种分析用户特征的比较少,希望通过今天的分享,大家在将来遇到这种场景时, 可以给大家提供一个新的解决方案。


本次分享内容包括:


  • 业务需求及挑战:BitBase 引擎的初衷是什么;

  • BitBase 解决方案:在 HBase 基础上,BitBase 的架构是什么样;

  • 业务效果:在快手的实际应用场景中,效果如何;

  • 未来规划:中短期的规划。


业务需求及挑战

1. 业务需求


用一句话来概括业务需求:在千亿级日志中,选择任意维度,秒级计算 7-90 日留存。


如上图所示。左边是原始数据,可能跨 90 天,每一天的数据可以看作是一张 Hive 宽表,在逻辑上可以认为每行数据的 rowkey 是 userId(这里不严谨,userId 可能是重复的),需要通过 90 天的原始数据计算得到右边的表,它的横轴和纵轴都是日期,每个格子表示纵轴日期相对于横轴日期的留存率。


该需求的挑战:


  • 日志量大,千亿级;

  • 任意维度,如 city、sex、喜好等,需要选择任意多个维度,在这些维度下计算留存率;

  • 秒级计算,产品面向分析师,等待时间不能过长,最好在 1-2 秒。


2. 技术选型


面对这些问题,我们当时的技术选型:


① Hive,因为大部分数据可能是存在 Hive 里,可以直接写 SQL 计算,该方案不用做数据迁移和转换,但是时延可能是分钟到小时级别,因此否定了这个方案。


② ES,通过原始数据做倒排索引,然后做一个类似计算 UV 的方式求解,但是在数据需要做精确去重的场景下,它的耗时比较大,需要秒到分钟级。


③ ClickHouse,ClickHouse 是一个比较合适的引擎,也是一个非常优秀的引擎,在业界被广泛应用于 APP 分析,比如漏斗,留存。但是在我们的测试的中,当机器数量比较少时 ( <10 台 ),耗时依然在 10 秒以上。


立足于这种场景,是否存在其它解决方案,延迟可以做到 2-3 秒(复杂的场景 10 秒以下),同时支持任意维度组合?基于 HBase,结合业界简单/通用的技术, 我们设计并实现了 BitBase 解决方案,用很少的资源满足业务需求。


BitBase 解决方案

1. 数据模型


如上图所示,首先将原始数据的一列的某个值抽象成 bitmap(比特数组),举例:city=bj,city 是维度,bj (北京) 是维度值,抽象成 bitmap 值就是 10100,表示第 0 个用户在 bj,第 1 个用户不在北京,依次类推。然后将多维度之间的组合转换为 bitmap 计算:bitmap 之间做与、或、非、异或,举例:比如在北京的用户,且兴趣是篮球,这样的用户有多少个,就转换为图中所示的两个 bitmap 做与运算,得到橙色的 bitmap,最后,再对 bitmap 做 count 运算。count 表示统计“1”的个数,list 是列举“1”所在的数组 index,业务上表示 userId。


2. BitBase 架构


整个 BitBase 架构包括五部分:


  • 数据存储:主要存储两类数据,一类数据是 bitmap 索引和数据,另一类是转换字典的归档文件(见后面描述)。

  • 数据转换:有两种方式,第一种是通过 mrjob 转换,第二种是在线计算或导入;

  • 数据计算:负责计算和调度,并把 IO 数据计算结果返回给 Client;

  • Client:站在业务的角度,把它们的业务逻辑分装成一个个业务的接口;

  • ZK:整个系统是一个分布式的服务,用 ZK 做管理。


3. 存储模块


用数据存储设计的核心目的是让计算更快。


如上图,左边为一天的原始数据,包括多个 table,通过 mrjob 或者 rpc 的方式转换成中间的 bitmap。


bitmap 分为两部分,第一部分为 meta 信息(橙色部分),第二部分是 data 信息:


  • Meta 信息唯一定位一个 bitmap,db 可以认为是 hive 中的 db,table 也可以认为是 hive 中的 table,event 表示维度 (如:城市),eventv 表示维度值 (如:bj),entity 表示 userId(也可能是 photoId),version 表示版本。

  • BitmapData 从物理上讲是一个比特数组,把比特数组按照一定的大小进行切块:b1,b2,b3,…,bn,从而实现分块存储,分块计算。


最后把 bitmap 存在 HBase 的 3 张表中: 两张核心表和一张辅助表。


  • BitmapMeta,保存 bitmap 的 meta 信息和一些 block 索引信息。

  • BlockData, 直接保存 bitmap block 数据。

  • BlockMeta,保存 block 的 meta 信息,起辅助作用。


4. 计算模块


一个完整的计算流程涉及到三个组件:BitBase Client、BitBase Server 和 HBase regionServer。


① BitBase Client 首先把业务的需求封装成计算表达式,然后把计算表达式发给 BitBase Server;


② BitBaseServe 接收到请求后,从 BitmapMeta 表中查询 Block 索引,然后根据索引将表达式切分为 n 个子表达式;


③ 如果所有 bitmap 的 db 相同,则走 coprocessor 路由,否则按照数据亲和性,将 block 计算分发到其它 bitbaseServer 中。


④ 根据第 3 步的调度策略,分两条不同的路径计算 block 表达式


⑤ BitBase Server 聚合 block 计算表达式的结果,然后返回给 BitBase Client。


两种计算方式的对比:


  • 非本地计算,解决跨 db 计算的需求,它主要的瓶颈在于网卡和 GC。

  • 本地计算,解决同 db 计算的需求,它主要的瓶颈在 CPU 和 GC 上。整体上看本地计算的性能比非本地计算的性能提高 3-5 倍,所以要尽量采用本地计算方式。


5. DeviceId 问题


在引入 Bitmap 数据模型之后,我们隐含的也引入了一个非常大的问题:无法支持 deviceId。要支持 deviceId,首先需要将 deviceId 转化为数字类型,并且转换之后的 DeviceIdIndex 必须要满足四个条件:


① 连续:deviceIdIndex 如果存在空洞,会降低压缩效率,同时 Block 数量会增加,计算复杂度相应增加,最终计算变慢;


② 一致:deviceId 和 deviceIdIndex 必须是一一对应的,否则计算结果不准确;


③ 反解:根据 deviceIdIndex 能够准确、快速地反解成原始的 deviceId;


④ 转换快:在亿级数据规模下,deviceId 转化为 deviceIdIndex 的过程不能太长。


6. DeviceId 方案

连续、一致、支持反解



如何保证连续、一致、支持反解?解决方案非常简单,利用 HBase 实现两阶段提交协议。如上图中间实线部分所示,定义 deviceId 到 deviceIdIndex 的映射为字典。第一张表存储字典的 meta 信息;第二张表存储 index 到 deviceId 的映射;第三张表存储 deviceId 到 index 的映射。


生成 Index 的过程。举例说明, 假设我们已经生成了 1w 个 deviceId 映射,那么此时 f:max=1w,现在将新生成 1k 条映射:


① 将 f:nextMax=f:max+1k=1.1w;


② 写 Index 到 deviceId 的反向映射表,1k 条;


③ 写 deviceId 到 Index 的正向映射表,1k 条;


④ 把 f:max=f:nextMax=1.1w 更新到 meta 表,生成过程结束。


如果在生成过程中出现异常或服务器宕机,则执行回滚流程:


① 如果我们检测到 f:nextMax 不等于 f:max(f:nextMax>f:max),则从表 2 中查询 max 到 nextMax 的数据,从表 3 中删掉相应的 deviceId 到 index 的映射记录;


② 再删掉表 2 中相应的 index 到 deviceId 的记录;


③ 最后把 f:nextMax=f:max,从而实现数据 100%一致。


用 HBase 实现两阶段提交协议要求 index 生成流程和回滚流程一定是单线程的,从而出现性能瓶颈,所以 BitBase 设计了归档流程,以支持快速转换(见后面的描述)。Meta 表中有两个字段,如果发现新产生的数据大于 f:archive_num 就发起归档,把表 3 中的新数据直接写到 HDFS 中 archive_path 目录下。


快速转化



这里我们用到了 MRjob 中的 Join:


① 同时输入原始数据和字典归档数据,在 MRjob 中根据 deviceId 做 join;


② 判断 deviceId 是否 join 成功;


③ 如果成功了,直接写 hdfs,这样就得到了转化后的数据;


④ 如果 join 失败,直接请求单实例 BitBase Master,BitBase Master 通过两阶段提交协议生成新的映射;


⑤ 然后返回给 join task 执行替换 deviceId;


⑥ 把转换后的数据写入 hdfs。


反解的过程很简单,直接多并发读取 HBase。


业务效果


如上图所示,第一个图是,2 维度,不同时间跨度计算留存的时间延迟,第 2 个图是 15 日留存在不同维度上的时延,时延并不会随着维度的增长而增长,原因是维度越多,表达式中可能不需要计算的 block 块也越多。



如上图所示,BitBase 可以应用在 app 分析,用户增长,广告 DMP,用户画像等多个业务场景中。


未来规划


根据现在面临的业务场景,BitBase 后续会在多个方面做优化。支持实时聚合,在一些业务场景下,如运营效果监测,导入时效需要 <5min,BitBase 需要支持实时聚合;支持 SQL 查询,目前只支持 api 的接入方式,在一些简单场景下比较复杂;开源,希望通过开源,和大家一起挖掘 BitBase 的业务场景。


作者介绍


陈杨,快手大数据高级研发工程师。负责快手 HBase 以及相关生态组件的维护与研发。


本文来自 DataFun 社区


原文链接


https://mp.weixin.qq.com/s/xWNSI9jZVIYaGxdBsSB8gw


2019 年 7 月 24 日 08:007529

评论

发布
暂无评论
发现更多内容

【LeetCode】制作 m 束花所需的最少天数Java题解

HQ数字卡

算法 LeetCode 5月日更

架构实战营 模块三:学习总结

👈

架构实战营

假如只剩下canvas标签

执鸢者

大前端 canvas

模块3 学习总结

TH

架构实战营

9个国外最佳免费编程学习一站式网站,谁用谁知道!

北游学Java

Java c++ php JavaScript

Semaphore

wzh

Java 并发 java工具类

消息队列详细设计架构文档

Hesher

架构 MQ Architecture 消息队列 架构实战营

第三课作业

杰语

架构训练营——模块2作业

圆心角

架构实训营 作业三——消息队列架构设计文档

开拓纪

第三章作业 #架构实战营

读写锁

wzh

Java 并发编程 并发 JUC

一文看懂 Go 的数据类型

Rayjun

Go 语言

ARTS - week 8 补打卡

steve_lee

模块3作业 3

dwade

#架构实战营

模块3作业 消息队列架构设计文档

TH

架构实战营

架构实战营-模块3-作业

笑春风

架构实战营模块三作业

冷大大

作业 架构实战营 模块三

架构训练营模块3作业《消息队列架构设计文档》-江哲

江哲

Java Stream 源码分析

Yano

Java stream

Spark中将DAG划分为Stage核心算法

五分钟学大数据

spark 5月日更

前端百题斩[001]——typeof和instanceof

执鸢者

面试 大前端

applet跨域访问安全性问题(java.security.AccessControlException:access denied)

xcbeyond

跨域 5月日更 疑难杂症

【架构实战营】第3模块作业

swordman

架构实战营

优秀程序员都在注意的十个点

你呀不牛

Java 设计模式 代码 技巧

模块三作业 - 消息队列系统架构设计文档

王子凡kerry

架构实战营

通过 Netty、ZooKeeper 手撸一个 RPC 服务!

Yano

Java 微服务 Netty RPC

消息队列构架设计文档

Chris Cheng

消息队列架构设计

俞嘉彬

架构实战营

用组合式创新模型做产品建模

石云升

组合式创新 5月日更 产品建模

HBase与Hadoop的关系

大数据技术指南

HBase 5月日更

自研集群 + MySQL 存储详细架构文档

@oo?金樱子

快手 HBase 在千亿级用户特征数据分析中的应用与实践_大数据_DataFunTalk_InfoQ精选文章