更多技术交换、求职机会,欢送关注字节跳动数据平台微信公众号,回复【1】进入官网交换群

因为流量红利逐步消退,越来越多的广告企业和从业者开始摸索精细化营销的新门路,取代以往的全流量、粗放式的广告轰炸。精细化营销意味着要在数以亿计的人群中优选出那些最具后劲的指标受众,这无疑对提供根底引擎反对的数据仓库能力,提出了极大的技术挑战。

本篇内容将聚焦字节跳动OLAP引擎技术和落地教训,从广告营销场景登程,上篇解说利用ByteHouse 减速实时人群包剖析查问的技术原理;下篇以字节跳动外部场景为例,具体拆解广告业务的实现逻辑和业务成果。(文本为下篇)

广告精准投放场景

广告投放过程个别蕴含数据收集->数据整合->人群圈选->广告投放->反馈剖析等要害流程,人群圈选是广告精准投放的关键步骤,它帮忙确定广告指标受众,辅助投放平台依据不同受众和广告指标优化投放策略,晋升广告收益;

人群预估

人群预估次要是依据肯定的圈选条件,确认命中的用户数目。在广告精准投放过程中,广告主须要晓得以后选定的人群组合中大略会有多少人,用于辅助判断投放状况进而确定投放估算,通常要求计算工夫不能超过 5 秒。

广告投放

广告精准投放过程中遇到的问题与痛点:

数据预估:广告主须要对选定的人群组合进行预估,以便判断投放状况并确定投放估算。但人群包数据量多,基数大。平台的用户数上亿,仅抖音的 DAU 就几亿,抖音、头条对应的人群包在亿级别,晚期的预估版本采纳ElasticSearch,但因为数据过于宏大,只能采纳1/10抽样存储,导致10%的误差,业务难以承受。

查问性能:广告主能够设定一个非常复杂的圈选条件,导致计算简单(单次计算可能蕴含几百上千个人群包),Hive和ES等计划在解决大数据量时,查问速度会变得十分慢,如果须要查问某个广告主的所有用户,须要扫描整个用户库,而这个过程可能须要几分钟甚至几个小时,无奈满足实时性要求。

存储空间大:Hive和ES等计划须要额定的索引构造,导致存储空间变大,从而减少了存储老本。例如,如果须要对用户属性进行索引,就须要额定的存储空间来存储索引数据。

不反对高并发:Hive和ES等计划在解决高并发申请时,容易呈现性能问题,无奈反对高效的广告投放。例如,如果同时有多个广告主须要查问用户信息,就可能会呈现查问阻塞或响应提早等问题。

数据查问效率:采纳ClickHouse反对预估,但随着数据量的增长,ClickHouse在以后存储引擎的反对下也难以保障查问工夫。这导致了数据查问效率的问题,影响了用户体验。

ByteHouse BitEngine计划

计划简介

新查问引擎

针对广告人群预估业务开发的新查问引擎,基于ClickHouse提供的MergeTree Family系列引擎,增加了新的bitmap64类型和一系列的相干聚合函数。BitEngine提供的bitmap64类型适宜存储和计算大量的用户ID之间的关系;在广告人群预估业务中,bitmap64类型用于存储人群包数据,而后将人群包之间的交并补计算转化为bitmap之间的交并补,从而达到远超一般查问的性能指标。

实现步骤

创立一个bitmap64类型,能够将用户ID间接存储在bitmap中,提供一系列交并补的聚合计算,并且还心愿能够充分利用多核CPU的并行计算能力,由此咱们设计了BitEngine。示例如下

CREATE TABLE cdp.tag_uids_map (tags String,uids BitMap64 BitEngineEncode)ENGINE = HaMergeTree('/clickhouse/xxxx/{shard}', '{replica}')ORDER BY tag

tag_uids_map存储格局如下

要查问 A&B 的后果 SQL 为

SELECT bitmapCount('A&B') FROM tag_uids_mapBitEngine

实现逻辑

核心思想

  1. 对数据做分区划分和编码,保障每个区间的数据之间不存在交加,而后应用roaring bitmap保留数据;
  2. 计算时每个分区的数据能够独立的做聚合计算,充分利用机器的并行能力,每个分区外部的聚合计算就是多个bitmap之间的交并补,利用roaring bitmap高效的交并补计算升高CPU和内存的应用;
  3. 通过字典将编码的后果反解回来,数据编码是为了让数据的散布尽可能浓密,roaring bitmap在存储和计算的时候就能够取得更好的性能。

业务利用

业务要害因素

  1. 人群包:广告主自定义规定计算出来的人群数据,标签是dmp团队依据市场需求定义的人群数据。
  2. 标签ID:每天定时依据产出规定更新一次,人群ID是自增的,每天依据广告主需要进行新建计算。

对立编码

  1. 为了对标签数据和人群数据的uid对立编码,编码服务先将标签数据中的uid和人群数据中的uid提取进去进行对立编码,将全量uid平均hash到一万个桶中,桶编号为i[0<=i<=9999],uid在每个桶内由1开始程序编码,每个桶的范畴为i2^40 - (i+1)2^40。
  2. uid数据每天都在减少,因而须要反对增量编码, 编码服务每天会先获取增量uid,hash后程序搁置到每个桶中。

数据存储

  1. 实现编码后,会先把字典数据对立写入hive表中,便于字典的各种应用场景。
  2. 在数据通过分区和编码之后,ClickHouse能够以多种数据导入格局将数据以bitmap64类型存入磁盘。

数据计算

BitEngine如何充沛利用计算机的并行能力实现每个分区多个bitmap之间的交并补计算?
存在问题:
假如存在四个bitmap,别离为a,b,c,d;则(a | c) & (b | d)不肯定等于(a & b) | (c & d)。

人群包

  • 人群包A = [10001, 20001,30001,40001,50001],人群包B = [10001, 20001,20002,20003,20004]

冀望后果

通过BitEngine计算A&B = [10001, 20001]

设计方案

  • 人群包依照肯定的规定划分为多个区间,任意两个区间之间的人群包没有交加
  • 一个计算线程只读取同一个区间的人群包进行计算,失去一个两头后果
  • 最终的两头后果只须要简略的进行bitmap or计算即可

对于这个设计,BitEngine须要保证数据的读取和计算是严格依照区间进行。BitEngine在数据读取时会为每一个文件构建一个读工作,由一个线程调度模块实现整个工作的调度和读取,这个线程调度模块的调度准则是:

  • 不同分区的文件不会穿插读取(ClickHouse的文件读取粒度小于文件粒度,会存在多个线程先后读一个文件的状况,一个分区也可能由多个文件组成),即一个线程只会读A_1,B_1,不会在这之间读取A_2或者B_2。
  • 一个分区读取实现后,能够立刻触发聚合计算,执行bitmap之间的计算逻辑,取得两头后果。即A_1,B_1 读取实现后,能够立刻计算A_1 & B_1。
  • 线程计算完两头后果后,能够持续读其余文件

BitEngine实现所有两头后果的计算后,会依照后果的输入要求做一次数据合并:

  • 如果须要计算的后果是bitmap的基数的时候,BitEngine间接将各个两头后果的基数相加
  • 如果计算结果须要的是bitmap,BitEngine间接将所有的bitmap合并起来,这里合并指的是bitmap or计算

业务成果

广告业务成果

  • 数据存储空间放大了 3 倍+
  • 导入工夫放大了 3 倍+
  • 查问 avg/pct99/max 都降落显著,pct99 从 5 s 升高到 2 s
  • CPU 应用降落显著,PageCache 节俭 100 G+
  • 查问误差从10% 降落到 0%

BitEngine上线前后查问耗时监控

BitEngine上线后CPU负载比照

PageCache 应用状况(lower is better)

案例总结

BitEngine上线应用后,通过大量调优,在广告人群预估业务上获得了良好收益。将来,BitEngine将持续加强性能以撑持广告业务场景,包含:引擎集成数据编码,使编码对用户通明;提供细粒度的缓存以缓存局部反复表达式的计算结果;优化表达式解析等。

点击跳转云原生数据仓库ByteHouse理解更多