简介: 本文将会为您分享天猫国际如何通过Hologres实现计算、存储、服务统一的实时交互式分析。
作者:景闻 阿里巴巴数据技术及产品部数据技术专家
天猫国际营销活动分析实时排行榜是在大促中帮助业务快速的分析商家或者品牌的交易和流量的数据情况,给下一步大促的销售目标,流量蓄水等等做出运营决策;尤其是在活动当天当发现行业的问题之后,仅仅靠子行业的拆分不足以确定具体的问题,也不一定有具体的业务抓手,所以需要有到商家、品牌和商品粒度的数据来快速定位问题。
原始技术方案的架构如下图所示,可以看到是非常典型的Lambda架构,实时和离线分别是两套系统,离线数据通过MaxCompute(原MaxCompute)轻度汇总同步至MySQL,实时增量数据通过Blink清洗后同步至HBase,最后在数据服务里面以View的形式将实时和离线数据合并,提供对外服务。
整个架构在实际业务执行中会有非常多的痛点,典型的有以下几个:
1)ADS层模型任务多
流计算和批处理任务都分别需要开发基于商品,卖家,品牌粒度的满足应用层的三个ADS模型数据,三个数据同步任务,分别需要创建三个oneservice服务,满足三个数据模块应用。
2)计算过程数据膨胀
在营销活动分析的场景下,看数据都是基于天猫国际业务类型和行业为大前提,因此通常在离线和实时的计算任务中,我们都是并行同时计算好不同的bu类型和所有的行业粒度的数据,这就导致了计算的过程中的数据的大量膨胀。
3)流批分离
当前产品上根据时间进行选择读取实时数据还是离线数据,三天之内的数据通过实时任务计算的数据,三天前的历史数据是通过批处理任务计算的离线数据,存在两套任务同时运行,增加了运维的复杂性。
4)产品搭建逻辑复杂
每一个产品展示的报表模块都需要通过实时数据提供的os接口和离线数据提供的os来进行,产品搭建的工作量比较大,通过时间来判断什么时候来读取离线os的数据,什么时候来读取实时os的数据,逻辑比较繁杂。
思考:为了提升研发效率和产品搭建的效率,我们只需要开发到DWD层的明细数据,明细数据只需要存储叶子类目,在交互式分层层面按需去关联行业维表,来提供对外随机的查询服务,从而节省了构建ADS层的多个模型数据以及数据服务接口的时间,在产品搭建上基于一个数据接口就能满足多个不同的应用场景的数据服务,提升产品搭建层面的效率,降低了产品搭建时的逻辑代码的复杂性。
策略:我们希望能够有一款产品,能统一计算写入任务,做到流批统一,对外提供自由的交互式查询服务。
在产品技术选型之前,需要先梳理业务需要用到的表以及数据量,选取几张最具代表性的表用于验证实际业务场景中产品技术可行性,以及验证关键指标性能问,包括查询QPS、写入TPS等。主要选取的表以及数据量如下:
(1) 交易明细数据表
| buyer_id + item_id +order_id |
| 20191111 | 4800W |
| 20200618 | 600W |
| 20200721 | 300W |
(2)流量IPV明细数据表
| visitor_id + item_id |
| 20191111 | 2.1亿 |
| 20200618 | 7000W |
| 20200721 | 2600W |
在技术选型方面,我们锁定了两款产品,一款是AnalyticDB for MySQL,一款是Hologres。ADB是阿里云数据库事业部团队提供的云原生数据仓库AnalyticDB MySQL版,是阿里巴巴自主研发的海量数据实时高并发在线分析云计算服务。Hologres是阿里云计算平台事业部提供的一款全面兼容PostgreSQL协议并与大数据生态无缝打通的实时交互式分析产品。从实际业务场景出发,两者的主要区别有以下几点:
1)与MaxCompute的打通性
Hologres:与MaxCompute打通,可以直接通过外部表读取MaxCompute数据进行查询分析,无需存储就能查询。
ADB:能加速查询MaxCompute,提供复杂交互式分析、实时混合数据仓库等多种场景。
2)成本方面
从我们每年ADB和Hologres的的单价上对比,Hologres成本相比ADB略微低。
3)灵活度
均能满足OLAP场景,Hologres兼容兼容PostgreSQL生态,ADB坚兼容MySQL协议,均能满足实时和离线批量的数据导入和分析。
4)性能
以下是Hologers的测试性能,数据量和大小均以MaxCompute的存储格式为准,没有进行一些特殊的索引和优化处理。
| 数据量 | 测试项 | 响应时间
| 4600W(20.64GB) | SUM | 2.7s
| 2300W(5.04GB) | SUM | 1.1s
| 4600W(20.64GB) | COUNT | 2.5s
| 2300W(5.04GB) | COUNT | 1.0s
| 4600W(5.04GB) | COUNT(distinct) | 2.8s
| 2300W(5.04GB) | COUNT(distinct) | 1.6s
| 4600W(20.64GB) | AVG | 1.7s
| 2300W(5.04GB) | AVG | 0.9s
| 4600W(20.64GB) | ROW_NUMBER | 2.6s
| 2300W(5.04GB) | AVG | 2.2s
结论:综合很多种种因素,我们最终选择Hologres作为交互式分析的查询引擎
使用Hologres后的架构如下图所示。
技术架构升级后,主要有以下几个优势:
商品和卖家以及品牌粒度页面的数据统一通过一个实时计算任务来统一计算,计算过程中不关联行业和业务BU类型的维表,在交互式分析端按需统一通过商品ID和叶子类目ID进行关联维表查询。提升了研发的效率和降低了运维的难度,也没有做到计算任务的膨胀,节省了计算资源。
统一通过Hologres的内部分区表的形式存储实时写入的交易和流量明细数据,提供的统一的数据管理和维护,将存储统一即可实现同库间的任意交互式分析查询服务。
商品和卖家以及品牌粒度的页面均可以通过一份通用的具有占位符的FBI的数据集来实现,通过FBI的报表模式实现数据可视化,提升了产品搭建的效率。
下面将会讲述Hologres在实时排行榜中的具体实践过程:
首先第一个是表设计,合理的表设计能够大大提升查询效率,尤其是当数据量变大的时候,相关索引的选择和配置对性能优化有着非常大的作用。所以在Hologres中创建表之前,一定要想清楚表的使用场景,查询逻辑。
在该方案中,由于需要涉及到交易的明细数据按照商品,卖家,品牌粒度汇总和流量数据进行join,同时还需要按照行业以及bu类型进行检索,主要用到的表DDL如下:
sql
CREATE TABLE IF NOT EXISTS public.dwd_intl_trd_pay_itm_buyer_ri(
stat_date text not null
,stat_hour text not null
,bu_id text not null
,bu_id_level1 text not null
,bu_id_level2 text not null
,item_id text not null
,item_title text
,item_tier text
,seller_id text
,seller_nick text
,seller_level text
,brand_id text
,brand_name text
,cate_id text not null
,pay_time text
,buyer_id text not null
,div_idx_actual_total_fee float8
,is_wap text
,is_jhs text
,biz_order_id text not null
,buy_amount int8
,PRIMARY KEY (stat_date,stat_hour,item_id,buyer_id,biz_order_id)
)
PARTITION BY LIST(stat_date);
CALL SET_TABLE_PROPERTY('public.dwd_intl_trd_pay_itm_buyer_ri', 'orientation', 'column');
CALL set_table_property('public.dwd_intl_trd_pay_itm_buyer_ri', 'storage_format', 'segment');
CALL set_table_property('public.dwd_intl_trd_pay_itm_buyer_ri', 'segment_key', 'stat_date,stat_hour,bu_id,bu_id_level1,bu_id_level2,cate_id');
call set_table_property('public.dwd_intl_trd_pay_itm_buyer_ri', 'distribution_key', 'stat_date,stat_hour');
CALL set_table_property('public.dwd_intl_trd_pay_itm_buyer_ri', 'shard_count’, ‘30');
CREATE TABLE IF NOT EXISTS public.dwd_intl_log_ipv_itm_visitor_ri(
stat_date text not null
,stat_hour text not null
,bu_id text not null
,bu_id_level1 text not null
,bu_id_level2 text not null
,item_id text not null
,item_title text
,seller_id text
,seller_nick text
,brand_id text
,brand_name text
,cate_id text not null
,visitor_id text not null
,ipv int8
,PRIMARY KEY (stat_date,stat_hour,item_id,visitor_id)
)
PARTITION BY LIST(stat_date);
CALL SET_TABLE_PROPERTY('public.dwd_intl_log_ipv_itm_visitor_ri', 'orientation', 'column');
CALL set_table_property('public.dwd_intl_log_ipv_itm_visitor_ri', 'storage_format', 'segment');
CALL set_table_property('public.dwd_intl_log_ipv_itm_visitor_ri', 'segment_key', 'stat_date,stat_hour,bu_id,bu_id_level1,bu_id_level2,cate_id');
call set_table_property('public.dwd_intl_log_ipv_itm_visitor_ri', 'distribution_key', 'stat_date,stat_hour');
CALL set_table_property('public.dwd_intl_log_ipv_itm_visitor_ri', 'shard_count', ‘50');
同时借助Hologres的表属性设置,根据业务场景针对性优化,主要有以下几点:
(1)基础属性的设置
distribution_key
指定分布列,数据将按照指定列,shuffle到各个shard
set_table_property('public.dwd_intl_trd_pay_itm_buyer_ri', 'distribution_key', 'stat_date,stat_hour,brand_id,seller_id');
clustering_key
指定一些列作为聚簇索引
set_table_property('public.dwd_intl_trd_pay_itm_buyer_ri‘, 'clustering_key‘,'stat_date,stat_hour,cate_id');
segement_key
文件索引,数据按该索引划分文件,可以通过segement_key快速索引到某一文件
set_table_property('public.dwd_intl_trd_pay_itm_buyer_ri', 'segment_key', 'stat_date,stat_hour,bu_id,bu_id_level1,bu_id_level2,cate_id');
(2)高级属性的设置
设置合理的TableGroup
Table Group非常关键的作用就是做local join,从而大大提升join效率,尤其是多表和比较大数据量join的时候
call set_table_property('public.dwd_intl_trd_pay_itm_buyer_ri', 'colocate_with', 'public.dwd_intl_log_ipv_itm_visitor_ri');
设置Shard_count
数据量:7亿/230GB的数据量,设置在2Kcore左右,交易30和流量50
实例资源:1个shard至少需要1个core来负责计算
写入性能:根据交易和流量的RPS来指定
Join需求:有夺标join的查询case时,需要考虑TableGroup
sql
CALL set_table_property('public.dwd_intl_trd_pay_itm_buyer_ri', 'shard_count', '30');
CALL set_table_property('public.dwd_intl_log_ipv_itm_visitor_ri', 'shard_count', '30');
通过一系列的优化,在实际业务场景中达到的优化效果如下:
1)用户增加五端通模块从90s-->8s
2)淘宝直播模块查询从9s-->2s
3)当前实时查询1.8s
当前流计算任务的开发是基于dataphin平台上采用BlinkSql进行的,这个平台让实时任务的开发变得相当的容易,这里主要记录下当Hologres作为实时任务的sink的时候的一些需要注意的点:
Hologres兼容PostgreSQL生态,提供JDBC/ODBC Driver,因此可以直接对接BI工具实现可视化展现,在实际业务中,主要用到数据服务(阿里内部叫oneservice)和FBI(阿里集团内的一款可视化报表工具)。
在数据中台的数据建设和数据服务的链路上,我们常常需要按照生产者和消费者的模式一样,通过oneservice将我们开发好的持久化的数据提供的统一的数服务。最初原生的方案设计是按照如下链路[1]进行的
但是在实际过程中,由于oneservice对于交互分析这样的场景支持的很弱,尤其是涉及到查询逻辑涉及到join的实时,就会出现timeout以及一些其他的问题。其次oneservice将查询query下推到Hologres查询的时候,oneservice很多的pg生态的语法都不支持。最终我们通过上图的链路[2]也就是通过FBI内置的Postgresql引擎来直接连Hologres实现数据查询服务的。
数据集动态配置
FBI层面通过创建数据集,将商品,卖家,品牌的三个页面统一分析,力争通过一个数据集来动态实现查询服务,这里需要涉及到数据集中应用到的占位符和基于vilocity语法来实现动态的配置。
Python
from dwd_intl_trd_pay_itm_buyer_ri
where
stat_date = '${bizdate:20200722}'
#if ((! ${bu_level_two} ) and (${bu_level_one} == "111"))
and bu_id = '${bu_level_one}'
#elseif ((! ${bu_level_two} ) and (${bu_level_one} != "111"))
and bu_id_level2 = '${bu_level_two}'
#elseif (( ${bu_level_two} ) and (${bu_level_one} == "111"))
and bu_id = '${bu_level_one}'
#elseif (( ${bu_level_two} ) and (${bu_level_one} != "111"))
and bu_id_level1 = '${bu_level_one}'
#else
and bu_id_level1 = '${bu_level_one}'
#end
group by
'${dims}'
页面布局设计
FBI的页面布局设计这个比较简单,直接通过报表的模式展示即可,但是需要同营销活动分析的级联模式保持一致,尤其是涉及到行级关联的一些地方还是需要一些技巧和设置的,否则初始化的性能不太好。最终的页面和查询如下:
总结来说,使用Hologres之后,除了上面讲诉的做到了计算、存储、服务统一的优势之外,从业务上来说还有以下几个突出价值:
将公共层的明细数据存入Hologres,提供给业务方能够进行随意交互式分析,相比于以前的cube模型的需要关联多个模型的取数方式,极大的提升了数据分析的效率。
整个公共层明细数据在行业的维度只包含叶子类目数据,在每年的行业类目调整中,不会因为类目维表的变更,导致进行回刷数据,极大的节省了回刷的数据资源。
由于需要看历史数据,所以需要保存最近400天的数据,明细数据太过于庞大,因此需要将历史数据进行汇总,有成交的商品是27W X 400 = 1亿+(大促会比较大) 降低存储压力,同时也会同Hologres技术团队一起引入高压缩比的存储格式。
当前通过Hologres的交互式分析技术和FBI的可视化工具能够做到查询均在3s左右,但还是有很多的一些可以化的细节的地方,比如查询的优化,FBI可视化工具搭建以及使用的一些小问题上,需要结合Hologres技术团队,FBI的技术团队一起来共建,反哺技术链的建设更加完善。
当前的技术方案不存在因为行业的频繁调整而带来的大量历史数据回刷的问题,但是如果存在一些逻辑的调整或者一些不可控的因素导致需要回刷历史数据,因此需要设计实时的数据回刷方案。
由于当前的Hologres中存储的大量的交易和流量的IPV明细数据,因此在很多的数据看板,数据分析中都存在可以直接复用当前数据,直接在数据集上进行自由的交互式分析,提升数据研发,数据分析,产品搭建等研发效率。
文章链接>>https://developer.aliyun.com/article/776646?spm=a2c6h.12873581.0.0.4bcb56813ayX86&groupCode=ai