写点什么

画像系统人群服务数据存储架构的演进与创新| 京东云技术团队

  • 2024-05-14
    北京
  • 本文字数:4361 字

    阅读完需:约 14 分钟

一、画像系统命中接口相关简介

什么是画像系统

标签画像系统是一种数据管理和分析工具,它通过整合和分析用户的行为数据、交易数据、社交数据等多维度信息,构建出用户的详细画像,帮助咱们运营人员更好地理解目标用户群体,从而实现精准营销和精细化运营。


提供了那些能力:标签注册,标签沉淀,标签取值;群体圈选;群体服务(群体命中,群体下载和订阅等 核心能力

怎么实现精准营销和精细化运营

命中接口:它作为连接用户数据和营销活动的桥梁,确保了营销信息能够准确地传递给最合适的用户群体。


业务场景


▪场景一:商城收银台页面,优惠券展示与否,以及优惠金额多少。


▪场景二:金融 APP 端资源位,展示哪种营销活动。



•……


在支付、消金、财富等核心业务中发挥着至关重要的作用,影响着用户拉新交易转化促活等关键环节。

命中接口实现逻辑

挑战

•如何保证三高:高性能(50ms 以下),高并发(百万级 TPS),高可用。


•数据量大:群体数量多,而且大量的群体的 pin 数量都是千万级别以上,甚至有的群体 pin 数量达到了数十亿。



二、画像系统 1.0 和 2.0 版本的命中接口

存储方式(物理机内存)

将人群数据从 OSS 拉取并存储在物理机(32C256G)中,由于群体数量过多,256G 不足以将所有的群体的 OSS 文件都保存下来,所以采用分片的逻辑,每个分片只存储群体 OSS 文件的四分之一。


方案优缺点

优点:


1、性能达标:基于内存取值,减少中间件依赖, 单机压测到 30000TPS,TP999 最高 40ms;


2、存储成本较低:在当时,和直接使用缓存相比,成本较低;


3、缓解了 CK 的压力:从 OSS 拉取文件,减少了 CK 查询次数。


缺点:


1、初始化群体非常慢: 由于数据是存在机器内存中,每次启动机器总要全量加载所有群体,但随着业务发展,群体数量的增加重启也会越来越慢;


2、扩容成本高:虽然分组内可以水平扩容,但是固定分组后,单机器的内存有限,一旦达到上限需要扩容分组时,必须成倍的扩容,导致扩容分组困难;


3、排查问题效率低:由于是自研的依赖于机器内存的存储方案,整体结构复杂,在运维的能力方面偏弱,运维的相关工具少。

三、画像系统 3.0 版本的命中接口

背景

•迁移到了 JDOS,JDOS 没有 256G 内存的物理机,所以我们采用的是 192G 内存的物理机


•群体数量由 8000+群体膨胀到 25000+群体, 由于 1.0 和 2.0 版本的四分片物理机存储的数据越来越多,快到物理机内存的极限了。


•从 OSS 拉取群体的时候,会由于网络抖动,导致拉取人群信息有不完整就断掉的情况,会造成重复拉取,导致物理机堆内存抖动,不稳定,影响 TP999,影响业务正常进行


存储方式(物理机内存)

依旧将人群数据存储在物理机中,但使用了拆分前置的操作,并且将原先的物理机四份片改为了八分片。先将群体的 OSS 文件拆分成 8 分,然后物理机对应的分片只需要去拉取自己分片对应的文件即可。


数据分层方案(缓存)

为什么需要使用缓存做数据分层

提高系统的可用性和可靠性: 应对不可预测的故障 ,网络问题,服务器故障等, 数据分层策略可以帮助系统应对这些不可预测的故障,提高系统的可用性和可靠性

存储方式

因为 set 集合的特征,元素小于 512 个会自动压缩,所以我们使用 set 集合来存用户的 offset 的。


四、画像系统 4.0 版本的命中接口

背景


由于在 3.0 的时候,offset 的编码已经超过了 2 的 32 次方。我们使用的 ck 版本加工群体位图的时候不支持大于 2 的 32 次方位图计算,升级版本不兼容。对 ck 计算层架构升级:小于 32 位的 offset 计算到现有的 bitmap 中,大于 32 位的 offset 计算时,所有 offset - 2^32,计算到高 32 位 bitmap。基于这点想到了如果低成本使用 R2M。也可以通过开发达到 RoaringBitmap 的压缩效果。

为什么要压缩

我们知道创建 Bitmap 的时候,长度必须是最大的 offset 的长度。再结合我们的场景,我们现在的 pin 数量已经超过了数十亿,但是每个人群不可能都是数十亿之多,所以我们位图存储的数据不是连续的,而是稀疏的。


假设我们现在只有 64 个用户,然后有一个人群包,只有 1 个 offset,63。


按照正常我们需要创建一个 64 位的 Bitmap



这时候我们就把数组拆分成 2 组,1 到 32 的用户存储到第 1 组,把 33 到 64 的用户存储到第二组。此时我们发现第一组的数组里全是 0,那第一组是不是可以不创建?这样我们就用一个 32 位大小的数组存储了 64 位的数据。


接下来更进一步,把 64 位的数组拆成每 16 个一组,那么我们只需要创建最后一个分组的数组,也就是 16 位的数组来达到进一步压缩的目的。



压缩流程

根据我们的业务场景,每个位图大小是 65536 压缩效果最好。


存储方式(缓存)

部署多个 R2M 集群(或分组),将群体 bitmap 进行拆分,并根据一定的路由策略存储到不同的集群上,通过不同的集群提供查询能力,如下图



在新方案中,增加了一整套的群体推送服务,包括数据的新增,更新,删除,检测,重试等全部可视化到页面,大大增强了群体加载的可监测性及有效性,而在之前的方案中,非常缺少这些有效的运维手段


流程对比

采用集中缓存替换自研分布式存储优缺点对比

性能对比

接口整体 TP999 耗时从 40ms 下降到 10ms 以内



五、命中接口的后续探索

一、逆向存储

背景

我们对一些耗时长的请求进行分析时发现,有些业务方传的群体编码,一次可能传几十个,这种情况我们可能需要判定几十次,然后把结果返回给用户,性能肯定比一次只传一个群体会差。所以我们想使用用户的 pin 当作 key,然后 value 是用户所在的群体数据。这样不管用户一次传多少个群体,我们只用取一次缓存就可以。

存储方式

key:用户的 pin 的 offset 为 key


value:用户所在的所有群体集合(以位图的方式存储)


优势

性能高:用户传多个群体编码的时候,我们只需要取一次缓存就可以,性能大大提高了。

二、规则判定

背景

发现有些用户在创建群体的时候,只用到了标签,然后对这些标签做逻辑与或非的操作。


举个例子:如果用户选择了两个标签(标签 1:男性,标签 2:三十岁以上,而且是且的关系)创建了一个人群,现在想判断一个 pin 是否在这个群体里面,我们可以怎么操作?我们只需要先判定用户是否是男性,然后判断用户是否三十岁以上,然后在内存中做逻辑且的操作就可以了。

优势

存储空间:不用存储整个群体位图文件,而且标签位图可重复使用,大大节省了存储空间

六、相关技术附录

CDP 系统中目前存在大量由 pin 集合组成的标签和群体,截止当前共有标签 4000+,有效群体 17000+。而且大量的群体都是 pin 数量都是千万级别以上,甚至有的群体 pin 数量达到了 40 亿+。如此大量的 pin 集合,对我们存储结构提出较高的要求。


这里拿群体举例,如果某群体包含 1000W 个 pin,通过文本文件存储,大概需要 150M,40 亿的群体就达到了惊人的 1504010=60000M,大约 60G,而我们的群体数量已经达到了 17000+,再加上标签数据,所需要的存储空间将不可接受。


并且,数据的存储只是其中一个方面,后续针对标签和群体的组合计算,创建出更细粒度的 pin 包也是一个挑战。


面对以上问题,CDP 采用了 Bitmap 的思路来解决,不但解决了存储空间问题,而且 Bitmap 本身的交并差运算,能够很好的支持用户对不同标签和群体的组合计算,详细方案如下。

一、bitmap 简介

它的基本思想是用 bit 位来唯一标记某个数值,这样可以用它来记录一个数值没有重复的数据元组。并且每一条数据只使用一个 bit 来标识,能够大大的节省存储空间。


比如,如果想存储一个数值数组[2,4,6,8]。


Java 中如果用 byte 类型来存储,不考虑其他开销,需要 4 个字节的空间,一个字节 8 位,也就是 4*8=32bit。


倘若使用更大的数据类型,存储空间也会相应增大,如使用 Integer(4 字节),则需要 448=128bit。


而如果采用 bitmap 的思想,只需要构建一个 8bit 空间,也就是一个字节的空间来存储,如下图。


二、pin 池编码

通过上文的例子,可以看到,使用 Bitmap 思想来存储,实际上每一个数据是一个 bit,而且不能重复,这一点用户 pin 是符合的,没有重复的 pin。


由于 bitmap 里只能存 0 或者 1 来标识当前位是否有值,而用户 pin 确是一个字符串,这就需要将数十亿的用户 pin 进行唯一性编码,这个编码也就是我们常说的 offset 偏移量。


每一个 pin 对应一个唯一的 offset,目前已到 46 亿+,也就是说当前最大的偏移量是 45 亿+,这部分由数据同学帮我们加工一张 pin 池表,其中包含了 pin 和 offset 的对应关系。这样,新注册的 pin,只要顺序增加 offset 值即可。


下边是一个简单示意图,假设我有 8 个 pin,pin1~pin8,对应的 offset 编号为 1~8。


我要建一个只包含双数 pin 的标签或群体,则我只需要将 offset 为 2,4,6,8 的位设为 1 即可。


三、ClickHouse 简介

有了位图之后,存在哪里,以及怎么进行位图之间的交并差的运算。基于这些问题,我们使用了 ClickHouse(以下简称 CK),一个由俄罗斯 Yandex 在 2016 年年开源的⾼性能分析型 SQL 数据库,是一个用于联机分析处理(OLAP)的列式数据库管理系统(columnar DBMS)


它具有以下特点:


1、完备的数据库管理功能,包括 DML(数据操作语言)、DDL(数据定义语言)、权限控制、数据备份与恢复、分布式计算和管理。


2、列式存储与数据压缩: 数据按列存储,在按列聚合的场景下,可有效减少查询时所需扫描的数据量。同时,按列存储数据对数据压缩有天然的友好性(列数据的同类性),降低网络传输和磁盘 IO 的压力。


3、关系模型与 SQL: ClickHouse 使用关系模型描述数据并提供了传统数据库的概念(数据库、表、视图和函数等)。与此同时,使用标准 SQL 作为查询语言,使得它更容易理解和学习,并轻松与第三方系统集成。


4、数据分片与分布式查询: 将数据横向切分,分布到集群内各个服务器节点进行存储。与此同时,可将数据的查询计算下推至各个节点并行执行,提高查询速度。


更多特性可查看官方文档:https://clickhouse.com/docs/zh/introduction/distinctive-features


还可以查看同事的这篇文章:如何使用Clickhouse搭建数十亿级用户画像平台看这一篇就够了


除了上文 CK 的特性之外,它还具有分析数据高性能,开发流程简便,开源社区活跃度高,并且支持压缩位图等优势。

四、群体加工链路

基于上面对 bitmap 以及 clickhouse 的介绍,我们采用的是 ClickHouse+Bitmap 实现标签群体组合计算和群体的存储



上图可以看到除了 CK 中的数据外,我们在 OSS 对象存储中也放了一份群体数据。

五、RoaringBitmap 压缩

我们最终使用的是 RoaringBitmap,一种高效的压缩位图实现,简称 RBM。于 2016 年由 S. Chambi、D. Lemire、O. Kaser 等人在论文《Better bitmap performance with Roaring bitmaps》 《Consistently faster and smaller compressed bitmaps with Roaring》中提出。


基本实现思路如下:


以整型 int(32 位)为例,将数据分成高 16 位和低 16 位两部分,低 16 位不变,作为数据位 Container,高 16 位作为桶的编号 Container,可以理解为高位的 Container 中,存放了很多个低位 Container。


比如,我要存放 65538 这个值,则高位为 65538>>>16=1,低位为 65538-65536*1=2,即存储在 1 号桶的 2 号位置,存储位置如下图:



我们当前使用的 RoaringBitmap 版本为 0.8.13,Container 包含了三种实现:ArrayContainer(数组容器),


作者:京东科技 王京星


来源:京东云开发者社区

发布于: 20 分钟前阅读数: 5
用户头像

拥抱技术,与开发者携手创造未来! 2018-11-20 加入

我们将持续为人工智能、大数据、云计算、物联网等相关领域的开发者,提供技术干货、行业技术内容、技术落地实践等文章内容。京东云开发者社区官方网站【https://developer.jdcloud.com/】,欢迎大家来玩

评论

发布
暂无评论
画像系统人群服务数据存储架构的演进与创新| 京东云技术团队_京东科技开发者_InfoQ写作社区