带你读《阿里云产品五月刊》——八、Hologres RoaringBitmap在Lazada选品平台的最佳实践

本文涉及的产品
实时数仓Hologres,5000CU*H 100GB 3个月
云原生数据仓库AnalyticDB MySQL版,基础版 8ACU 100GB 1个月
简介: Hologres RoaringBitmap在Lazada选品平台的最佳实践

简介: Lazada选品平台包含全网商家、商品的圈选,通过Hologres RoaringBitmap能力帮助业务突破选品池20w大小限制,6000+选品池调度完成由12h下降至1h,单个选品池调度时间由90s下降至2s。

 

Lazada选品平台包含全网商家、商品的圈选,通过Hologres RoaringBitmap能力帮助业务突破选品池20w大小限制,6000+选品池调度完成由12h下降至1h,单个选品池调度时间由90s下降至2s。

选品平台介绍

Lazada选品平台是面向内部运营小二选品的操作系统,其核心能力是:通过用户制定的规则条件组合以筛选出满足期望的业务实体,这里的业务实体包括但不仅限于:商品、商家。站在电商运营体系上来看,选品系统的核心职能在于 选 和 供,选出合适的 “品”(商品、商家... ),供给到对应的 “渠道” (会场、频道、JFY...)。通过供和选核心能力的组合,选品平台在营销活动链路中作为数据通路,打通从商家到消费者的核心链路,并且在导购链路赋能了会场、FlashSale、JFY等等诸多业务,覆盖了Lazada的绝大数场景化供给。

 

从选的角度来讲,可以用于运营范围圈定、业务准入门槛、大促会场和日常频道投放等。在大促招商以及商家运营系统中,商家范围界定就成为整个运营流程的起点也是最值得关注的一点,限定满足预期的商家会让后续的流程更加顺滑也势必会取得更好的效果;在各种官方营销活动中,各行业运营会根据商家层级、货品类目、成交表现等为商家提供特定报名入口,为消费者提供更匹配的货品,选品成为不同层次门槛制定的有力抓手。

从供的角度来讲,多货品集交并差供给、离线供给、打标供给、渠道供给等能力让选品成为数据通路的统一出口。这里供给的含义不单纯是将数据以在线或者离线的方式提供给下游,可能是一次打标任务、一次 excel 导出、也可能是持续的增量打去标任务。

image.png

 

Hologres(原交互式分析)是一站式实时数据仓库引擎,支持海量数据实时写入、实时更新、实时分析,支持标准SQL(兼容PostgreSQL协议),支持PB级数据多维分析(OLAP)与自助分析(Ad Hoc),支持高并发低延迟的在线数据服务(Serving),与MaxCompute、Flink、DataWorks深度融合,提供离在线一体化全栈数仓解决方案。

 

在过去几个月,我们把选品平台的底层数据引擎从Ha3替换成Hologres,并使用DataWorks+Flink构建了一套和Saro类似的离在线数据同步解决方案,打破了使用搜索引擎支撑选品的传统,开创了OLAP数据库在选品平台上应用的先河。

RoaringBitmap科普

Bitmap

在介绍RoaringBitmap之前,先来了解下Bitmap。

 

Bitmap的基本思想就是用一个bit位来标记某个元素对应的Value,而Key即是该元素。由于采用了Bit为单位来存储数据,因此在存储空间方面,可以大大节省。

 

假设有这样一个需求:在20亿个随机整数中找出某个数m是否存在其中,并假设32位操作系统,4G内存

 

在Java中,int占4字节,1字节=8位(1 byte = 8 bit)

 

如果每个数字用int存储,那就是20亿个int,因而占用的空间约为 (2000000000*4/1024/1024/1024)≈7.45G

 

如果按位存储就不一样了,20亿个数就是20亿位,占用空间约为 (2000000000/8/1024/1024/1024)≈0.233G

 

假设有四个整数:int[ ] a = { 0, 3, 5, 7 },使用下图的Bitmap表示,表格标记了0到7的数字,其中 0、3、5和7被标记为1:

  image.png

 

因为1Int = 4Bytet = 32Bit,所以一个Int所占的二进制位可以映射32个数字,相当于压缩了32倍,那么之前20亿个整数所需要的7.45GB内存可缩减至233.41MB。

 

Bitmap的问题在于,不管业务中实际的元素基数有多少,它占用的内存空间都恒定不变。如果Bitmap中的位的取值范围是1到100亿之间,那么Bitmap就会开辟出100亿Bit的存储空间。但是如果实际上值只有100个的话,100亿Bit的存储空间只有100个Bit为1,其余全部为0,数据存储空间浪费严重,数据越稀疏,空间浪费越严重。

 

 

RoaringBitmap

为了解决Bitmap稀疏存储浪费空间的问题,出现了很多稀疏位图的压缩算法,RoaringBitmap就是其中的优秀代表。

 

RoaringBitmap是高效压缩位图,简称RBM。RBM的历史并不长,它于2016年由S. Chambi、D. Lemire、O. Kaser等人在论文《Better bitmap performance with Roaring bitmaps》与《Consistently faster and smaller compressed bitmaps with Roaring》中提出。

 

RoaringBitMap的基本思路:

 

将数据的前半部分,即高16位作为桶的编号,分为65536个桶,RBM中将这些小桶称之为Contriner(容器)

 

存储数据时,按照数据的高16位做为Contriner的编号去找对应的Contriner(找不到就创建对应的Contriner),再将低16位放入该Contriner中:

image.png

与Bitmap相比的优势

 

空间节省:Bitmap比较适用于数据分布比较稠密的存储场景中;RoarringBitMap在稀疏存储上空间更省,稠密和Bitmap一致。

更高效的做交、并操作:将大块的Bitmap分成各个小块,其中每个小块在需要存储数据的时候才会存在。所以当进行交集或并集运算的时候,只需要去计算存在的一些块,而不需要像Bitmap那样对整个大的块进行计算。这里既不是用空间换时间,也没有用时间换空间,而是用逻辑的复杂度同时换取了空间和时间。

集合运算性能

下面这段代码测试RoaringBitmap与数组在交集运算上的性能差异:

RoaringBitmap rbAnd1 = new RoaringBitmap();
for (int k = 100000; k < 200000; k++) {
    rbAnd1.add(k);
}
RoaringBitmap rbAnd2 = new RoaringBitmap();
for (int k = 150000; k < 200000; k++) {
    rbAnd2.add(k);
}
Long start = System.currentTimeMillis();
rbAnd1.and(rbAnd2);
System.out.println("roaringBitmap and 耗时:" + (System.currentTimeMillis() - start) + "ms");
List<Integer> list1 = new ArrayList<>();
for (int k = 100000; k < 200000; k++) {
    list1.add(k);
}
List<Integer> list2 = new ArrayList<>();
for (int k = 150000; k < 200000; k++) {
    list2.add(k);
}
start = System.currentTimeMillis();
list1.retainAll(list2);
System.out.println("list and 耗时:" + (System.currentTimeMillis() - start) + "ms");

测试结果:

 

roaringBitmap and 耗时:1ms
list and 耗时:3056ms


下面这段代码测试RoaringBitmap与数组在差集运算上的性能差异:

RoaringBitmap rbAnd1 = new RoaringBitmap();
for (int k = 100000; k < 200000; k++) {
    rbAnd1.add(k);
}
RoaringBitmap rbAnd2 = new RoaringBitmap();
for (int k = 150000; k < 200000; k++) {
    rbAnd2.add(k);
}
Long start = System.currentTimeMillis();
rbAnd1.andNot(rbAnd2);
System.out.println("roaringBitmap andNot 耗时:" + (System.currentTimeMillis() - start) + "ms");
List<Integer> list1 = new ArrayList<>();
for (int k = 100000; k < 200000; k++) {
    list1.add(k);
}
List<Integer> list2 = new ArrayList<>();
for (int k = 150000; k < 200000; k++) {
    list2.add(k);
}
start = System.currentTimeMillis();
list1.removeAll(list2);
System.out.println("list andNot 耗时:" + (System.currentTimeMillis() - start) + "ms");

测试结果:

 

roaringBitmap andNot 耗时:1ms
list andNot 耗时:3350ms


从测试结果不难看出,在集合传统的交差集运算上,RoaringBitmap具有无与伦比的速度优势。

RoaringBitmap实践

指标存储

前文提到我们把选品平台的底层数据引擎升级成Hologres,Hologres数仓存储了lazada全平台的商品,按目前运营小二组合商品表现数据来选品的习惯,我们把商品的表现数据抽象成商品指标存储在大宽表(为什么叫大宽表,因为随着业务关注视角的不同,指标越来越多,目前已经接近300个字段)。

 

其中商品指标不乏多值字段,如:商品所属类目、商品已报名活动、商品所属行业...,存储这些多值字段,我们一开始采用数组类型字段进行存储。如果运营小二使用了多值指标进行选品,规则翻译模块会把运营的输入翻译成数组的交集运算提交到Hologres执行。直到我们从Hologres的监控发现,CPU偶有冲高到100%的情况:

image.png

通过抓取该段时间的慢SQL,我们发现导致CPU冲高的大部分SQL都是数组取交集的运算。

image.png

问题定位到了,当时想到两种优化方案:

 

多值字段从数组换成RoaringBitmap,RoaringBitmap是一种高效的Bitmap压缩算法,目前已被广泛应用在各种语言和各种大数据平台。适合计算超高基维的,常用于去重、标签筛选、时间序列等计算中。

多值字段依旧使用数组,数据落表时先排好序再写入,在查询取交集时,传入比较的数组也排好序,即“先排序再比较”的策略。

 

两种优化方案优劣比较:

image.png

 

离线写入:即商品大宽表数据由MaxCompute写入到Hologres,选品平台的数据层一般由离线数据和在线数据两部分组成

 

综上,字段类型修改为RoaringBitmap,离线写入的耗时增加1min左右 CPU消耗增加10%,对离线链路构建时长的影响可以忽略;查询性能大幅优于有序的数组和现有无序的数组。

 

基于此,我们把商品大宽表的23个多值字段由数组类型升级成RoaringBitmap,整体优化收益如下:

 

商品大宽表存储空间下降 30% ~ 40% ,存储文件个数下降 30% ~ 40% (不同国家有所差异,整体在30% ~ 40%)。文件个数减少有以下几个好处:

提高查询性能:更少的文件意味着查询需要扫描的数据量和文件数量都较少,从而提高查询速度和系统整体性能。

减少存储开销:小文件会在硬盘上产生更多的碎片,导致磁盘空间利用率降低,文件个数减少有助于提高磁盘空间利用率。

简化管理:当文件数量较多时,管理和监控任务会变得更加复杂。文件个数减少能够简化管理和维护工作,提高运维效率。

优化备份和恢复:备份大量小文件通常比备份少量大文件所需的时间更长。文件个数减少可以缩短备份和恢复的时间,提高业务连续性。

减轻元数据压力:文件系统需要跟踪每个文件的信息(如权限、大小等),大量的小文件会增加元数据的压力。文件个数减少有助于减轻元数据服务器的压力,保证系统的稳定运行。

Hologres CPU利用率下降 30%

image.png

Hologres RoaringBitmap类型字段建表语句参考:

BEGIN;
CREATE TABLE public.test (
    product_id bigint NOT NULL,
    product_categories roaringbitmap,
    ds text NOT NULL,
    PRIMARY KEY (product_id, ds)
) PARTITION BY LIST (ds);
CALL set_table_property('public.test', 'orientation', 'column,row');
CALL set_table_property('public.test', 'distribution_key', 'product_id');
END;

 选品池运算

 

选品池:符合运营小二选品规则的业务实体(商品、商家...)的集合,选品池数据一般为商品ID或商家ID的集合

 

“供给”是选品平台的核心能力,围绕着“供给”,我们构建了选品池持续的增量打标/去标的核心能力。打标供给核心流程如下:

image.png

当前打标供给流程核心问题定义:

 

数据冗余:因为需要对选品池今天和昨天的数据进行比较,选品池今天的数据从选品引擎实时拉取,选品池昨天的数据冗余到Mysql以方便第二天进行比较

选品池运算:今天和昨天的选品池数据对比,在应用内存中进行,如果选品池数据量过大,容易触发应用频繁的FullGC。技术通过设置20w上限来规避这个问题,业务对突破20w的述求越来越强烈

调度效率低:6000+选品池调度完成,要12h,单个选品池调度完成花费80~90s

在了解到RoaringBitmap在集合存储具有较大的空间优势,在集合运算具有较大的时间优势,我们决定使用RoaringBitmap来存储选品池数据。

 

在RoaringBitmap落地过程中,遇到了很多困难和挑战,罗列其中一二:

 

为了解决数据冗余的问题,我们限定选品池数据不出Hologres数仓,也就是要借助Hologres的RoaringBitmap字段类型来存储选品池数据。但Hologres的RoaringBitmap字段类型只支持32位整数存储,商品ID和商家ID显然已经超过了32位整数的范围。于是,问题就演化成了RoaringBitmap怎么能存下64位整数。从实现复杂度,以及对未来SKU选品池支撑友好程度等多方面综合考虑,我们最终采用分桶法。

偏移法:

image.png

分桶法:将商品ID或商家ID拆为低位和桶号,这里我们直接将商品ID的高34位作为桶号,将低30位存入RoaringBitmap

分桶法:将商品ID或商家ID拆为低位和桶号,这里我们直接将商品ID的高34位作为桶号,将低30位存入RoaringBitmap

 

image.png

 

自定义id: 因为商品ID或商家ID均存在较大的断层,实际上商品数量和商家数量远未达到32位整数的上限,内部维护一个自增长ID去映射商品ID或商家ID

在攻克了诸多困难和挑战后,打标供给整体实现方案简化为如下流程:

 

image.png

 

选品池运算核心逻辑:

  image.png

 

优化整体收益:

 

数据流转效率:6000+选品池调度完成由12h下降至1h,单个选品池调度时间由90s下降至2s

系统稳定性:应用层FullGC次数下降88%

存储成本: 消除数据冗余,节省75GB存储空间

业务突破:帮助业务突破选品池20w大小限制,目前暂定50w

Hologres RoaringBitmap分桶表建表语句参考:

CREATE TABLE public.test_pool_dump_rb ( pool_id bigint NOT NULL, pool_type text NOT NULL, bucket bigint NOT NULL, pool_data roaringbitmap NOT NULL, ext text NOT NULL, ds text NOT NULL ,PRIMARY KEY (pool_id, bucket, ds) ) PARTITION BY LIST (ds); CALL set_table_property('public.test_pool_dump_rb', 'orientation', 'column,row'); CALL set_table_property('public.test_pool_dump_rb', 'clustering_key', 'pool_id:asc'); CALL set_table_property('public.test_pool_dump_rb', 'distribution_key', 'pool_id'); CALL set_table_property('public.test_pool_dump_rb', 'table_storage_mode', 'any'); CALL set_table_property('public.test_pool_dump_rb', 'auto_partitioning.enable', 'true'); CALL set_table_property('public.test_pool_dump_rb', 'auto_partitioning.time_unit', 'day'); CALL set_table_property('public.test_pool_dump_rb', 'auto_partitioning.time_zone', 'ASIA/SHANGHAI'); CALL set_table_property('public.test_pool_dump_rb', 'auto_partitioning.num_precreate', '2'); CALL set_table_property('public.test_pool_dump_rb', 'auto_partitioning.num_retention', '2'); CALL set_table_property('public.test_pool_dump_rb', 'auto_partitioning.num_hot', '-1'); END;

导出选品池数据到RoaringBitmap SQL参考:

insert into test_pool_dump_rb_${ds}
(pool_id, pool_type, bucket, pool_data, ext, ds)
select
#{poolId} as pool_id,
#{poolType} as pool_type,
product_id >> 30 as bucket,
rb_build(array_agg(${product_id} <![CDATA[&]]> 1073741823)) as pool_data,
#{ext} as ext,
#{ds} as ds
from (
    select product_id from test
) A
group by product_id >> 30

选品池差集运算SQL参考:

select A.pool_id, A.pool_type, A.bucket, rb_to_array(A.pool_data - if(B.pool_data is null, rb_build('{}'), B.pool_data)) as pool_data
from
(
    select pool_id, pool_type, bucket, pool_data
    from test_pool_dump_rb
    where pool_id = #{poolId}
    and ds = #{ds}
) A left join
(
    select pool_id, bucket, pool_data
    from test_pool_dump_rb
    where pool_id = #{poolId}
    and ds = #{differenceDs}
) B on A.pool_id = B.pool_id and A.bucket = B.bucket

总结

RoaringBitmap的成功应用,不仅是对业务功能的强力助推,彰显了技术对业务突破的关键赋能作用,更是先进技术驱动生产效率提升的典范。RoaringBitmap通过其高效的压缩机制大幅优化数据存储(空间效率),以及卓越的集合处理能力显著提高操作性能(时间效率),有效克服了业务在选品池规模上的原有约束,实现了对20万条数据容量限制的突破。这不仅证明了RoaringBitmap技术的先进性,也是技术创新提升核心竞争力的生动实例。


相关实践学习
基于Hologres轻松玩转一站式实时仓库
本场景介绍如何利用阿里云MaxCompute、实时计算Flink和交互式分析服务Hologres开发离线、实时数据融合分析的数据大屏应用。
目录
相关文章
|
1月前
|
DataWorks 数据挖掘 关系型数据库
基于hologres搭建轻量OLAP分析平台解决方案评测
一文带你详细了解基于hologres搭建轻量OLAP分析平台解决方案的优与劣
184 8
|
2月前
|
数据可视化 数据挖掘 OLAP
基于 Hologres 搭建轻量 OLAP 分析平台评测报告
【9月更文第6天】开作为互联网手游公司的产品经理和项目经理,数据分析对于我们的业务至关重要。我们一直在寻找高效、可靠的数据分析解决方案,以更好地了解玩家行为、优化游戏体验和提升运营效率。近期,我们体验并部署了《基于 Hologres 搭建轻量 OLAP 分析平台》解决方案,以下是我们对该方案的评测报告。
85 12
基于 Hologres 搭建轻量 OLAP 分析平台评测报告
|
1月前
|
SQL 分布式计算 数据挖掘
加速数据分析:阿里云Hologres在实时数仓中的应用实践
【10月更文挑战第9天】随着大数据技术的发展,企业对于数据处理和分析的需求日益增长。特别是在面对海量数据时,如何快速、准确地进行数据查询和分析成为了关键问题。阿里云Hologres作为一个高性能的实时交互式分析服务,为解决这些问题提供了强大的支持。本文将深入探讨Hologres的特点及其在实时数仓中的应用,并通过具体的代码示例来展示其实际应用。
154 0
|
2月前
|
存储 机器学习/深度学习 监控
阿里云 Hologres OLAP 解决方案评测
随着大数据时代的到来,企业面临着海量数据的挑战,如何高效地进行数据分析和决策变得尤为重要。阿里云推出的 Hologres OLAP(在线分析处理)解决方案,旨在为用户提供快速、高效的数据分析能力。本文将深入探讨 Hologres OLAP 的特点、优势以及应用场景,并针对方案的技术细节、部署指导、代码示例和数据分析需求进行评测。
127 7
|
2月前
|
机器学习/深度学习 DataWorks 数据挖掘
基于阿里云Hologres和DataWorks数据集成的方案
基于阿里云Hologres和DataWorks数据集成的方案
70 7
|
2月前
|
运维 数据挖掘 OLAP
阿里云Hologres:一站式轻量级OLAP分析平台的全面评测
在数据驱动决策的今天,企业对高效、灵活的数据分析平台的需求日益增长。阿里云的Hologres,作为一站式实时数仓引擎,提供了强大的OLAP(在线分析处理)分析能力。本文将对Hologres进行深入评测,探讨其在多源集成、性能、易用性以及成本效益方面的表现。
125 7
|
2月前
|
存储 SQL 分布式计算
Hologres 与阿里云生态的集成:构建高效的数据处理解决方案
【9月更文第1天】随着大数据时代的到来,数据处理和分析的需求日益增长。阿里云作为国内领先的云计算平台之一,提供了多种数据存储和处理的服务,其中Hologres作为一款实时数仓产品,以其高性能、高可用性以及对标准SQL的支持而受到广泛关注。本文将探讨Hologres如何与阿里云上的其他服务如MaxCompute、DataHub等进行集成,以构建一个完整的数据处理解决方案。
85 2
|
2月前
|
消息中间件 Java 数据库连接
Hologres 数据导入与导出的最佳实践
【9月更文第1天】Hologres 是一款高性能的实时数仓服务,旨在提供快速的数据分析能力。无论是从外部数据源导入数据还是将数据导出至其他系统,都需要确保过程既高效又可靠。本文将详细介绍如何有效地导入数据到 Hologres 中,以及如何从 Hologres 导出数据。
93 1
|
3月前
|
消息中间件 关系型数据库 MySQL
实时计算 Flink版产品使用问题之使用CTAS同步MySQL到Hologres时出现的时区差异,该如何解决
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
3月前
|
SQL 分布式计算 数据库
畅捷通基于Flink的实时数仓落地实践
本文整理自畅捷通总架构师、阿里云MVP专家郑芸老师在 Flink Forward Asia 2023 中闭门会上的分享。
8313 15
畅捷通基于Flink的实时数仓落地实践

热门文章

最新文章