Doris:Doris介绍
Posted 不死鸟.亚历山大.狼崽子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Doris:Doris介绍相关的知识,希望对你有一定的参考价值。
1 Doris简介
Apache Doris是一个现代化的基于MPP(大规模并行处理)技术的分析型数据库产品。简单来说,MPP是将任务并行的分散到多个服务器和节点上,在每个节点上计算完成后,将各自部分的结果汇总在一起得到最终的结果(与Hadoop相似)。仅需亚秒级响应时间即可获得查询结果,有效地支持实时数据分析。
Apache Doris可以满足多种数据分析需求,例如固定历史报表,实时数据分析,交互式数据分析和探索式数据分析等。令您的数据分析工作更加简单高效!
MPP ( Massively Parallel Processing ),即大规模并行处理,在数据库非共享集群中,每个节点都有独立的磁盘存储系统和内存系统,业务数据根据数据库模型和应用特点划分到各个节点上,每台数据节点通过专用网络或者商业通用网络互相连接,彼此协同计算,作为整体提供数据库服务。非共享数据库集群有完全的可伸缩性、高可用、高性能、优秀的性价比、资源共享等优势。简单来说,MPP 是将任务并行的分散到多个服务器和节点上,在每个节点上计算完成后,将各自部分的结果汇总在一起得到最终的结果 ( 与 Hadoop 相似 )。
2 核心特性
- 基于MPP(大规模并行处理)架构的分析型数据库
- 性能卓越,PB级别数据毫秒/秒级响应
- 支持标准SQL语言,兼容mysql协议
- 向量化执行器
- 高效的聚合表技术
- 新型预聚合技术Rollup
- 高性能、高可用、高可靠
- 极简运维,弹性伸缩
3 Doris特点
性能卓越
TPC-H、TPC-DS性能领先,性价比高,高并发查询,100台集群可达10w QPS,流式导入单节点50MB/s,小批量导入毫秒延迟
简单易用
高度兼容MySql协议;支持在线表结构变更高度集成,不依赖于外部存储系统
扩展性强
架构优雅,单集群可以水平扩展至200台以上
高可用性
多副本,元数据高可用
4 Doris发展历程
5 开源OLAP引擎对比
5.1 OLTP 与 OLAP
OLTP
- 操作型处理,叫联机事务处理OLTP(On-Line Transaction Processing),主要目标是做数据处理,它是针对具体业务在数据库联机的日常操作,通常对少数记录进行查询、修改。
- 用户较为关心操作的响应时间、数据的安全性、完整性和并发支持的用户数等问题。
- 传统的关系型数据库系统(RDBMS)作为数据管理的主要手段,主要用于操作型处理。
OLTP的查询一般只会访问少量的记录,且大多时候都会利用索引。比如最常见的基于主键的 CRUD 操作
OLAP
- 分析型处理,叫联机分析处理OLAP(On-Line Analytical Processing),主要目标是做数据分析。
- 一般针对某些主题的历史数据进行复杂的多维分析,支持管理决策。
- 数据仓库是OLAP系统的一个典型示例,主要用于数据分析。
OLAP 的查询一般需要 Scan 大量数据,大多时候只访问部分列,聚合的需求(Sum,Count,Max,Min 等)会多于明细的需求(查询原始的明细数据)
HTAP
HTAP 是 Hybrid Transactional(混合事务)/Analytical Processing(分析处理)的简称。
基于创新的计算存储框架,HTAP 数据库能够在一份数据上同时支撑业务系统运行和 OLAP 场景,避免在传统架构中,在线与离线数据库之间大量的数据交互。此外,HTAP 基于分布式架构,支持弹性扩容,可按需扩展吞吐或存储,轻松应对高并发、海量数据场景。
目前,实现 HTAP 的数据库不多,主要有 PingCAP 的 TiDB、阿里云的 HybridDB for MySQL、百度的 BaikalDB 等。其中,TiDB 是国内首家开源的 HTAP 分布式数据库
5.2 OLAP引擎分类
OLAP按存储器的数据存储格式分为MOLAP(Multi-dimensional OLAP) 、ROLAP(Relational OLAP)和 HOLAP(Hybrid OLAP)。
MOLAP:基于多维数组的存储模型,也是OLAP最初的形态,特点是对数据进行预计算,以空间换效率,明细和聚合数据都保存在cube中。但生成cube需要大量时间和空间。MOLAP可选Kylin、Druid等开源产品。
通过预计算,提供稳定的切片数据,实现多次查询一次计算,减轻了查询时的计算压力,保证了查询的稳定性,是“空间换时间”的最佳路径。实现了基于Bitmap的去重算法,支持在不同维度下去重指标的实时统计,效率较高。
ROLAP:完全基于关系模型进行存储数据,不需要预计算,按需即时查询。明细和汇总数据都保存在关系型数据库事实表中。
基于实时的大规模并行计算,对集群的要求较高。MPP引擎的核心是通过将数据分散,以实现CPU、IO、内存资源的分布,来提升并行计算能力。在当前数据存储以磁盘为主的情况下,数据Scan需要的较大的磁盘IO,以及并行导致的高CPU,仍然是资源的短板。因此,高频的大规模汇总统计,并发能力将面临较大挑战,这取决于集群硬件方面的并行计算能力。传统去重算法需要大量计算资源,实时的大规模去重指标对CPU、内存都是一个巨大挑战。目前Doris最新版本已经支持Bitmap算法,配合预计算可以很好地解决去重应用场景。
HOLAP:混合模型,细节数据以ROLAP存放,聚合数据以MOLAP存放。这种方式相对灵活,且更加高效。
其中doris是一个ROLAP引擎, 可以满足以下需求
- 灵活多维分析
- 明细+聚合
- 主键更新
对比其他的OLAP系统
- MOLAP模式的劣势(以Kylin为例)
- 应用层模型复杂,根据业务需要以及Kylin生产需要,还要做较多模型预处理。这样在不同的业务场景中,模型的利用率也比较低。
- 由于MOLAP不支持明细数据的查询,在“汇总+明细”的应用场景中,明细数据需要同步到DBMS引擎来响应交互,增加了生产的运维成本。
- 较多的预处理伴随着较高的生产成本。
- ROLAP模式的优势
- 应用层模型设计简化,将数据固定在一个稳定的数据粒度即可。比如商家粒度的星形模型,同时复用率也比较高。
- App层的业务表达可以通过视图进行封装,减少了数据冗余,同时提高了应用的灵活性,降低了运维成本。
- 同时支持“汇总+明细”。
- 模型轻量标准化,极大的降低了生产成本。
综上所述,在变化维、非预设维、细粒度统计的应用场景下,使用MPP引擎驱动的ROLAP模式,可以简化模型设计,减少预计算的代价,并通过强大的实时计算能力,可以支撑良好的实时交互体验。
总结
- 数据压缩率Clickhouse好
- ClickHouse单表查询性能优势巨大
- Join查询两者各有优劣,数据量小情况下Clickhouse好,数据量大Doris好
- Doris对SQL支持情况要好
6 使用场景
上图是整个Doris的具体使用场景,主要是它的接收数据源,以及它的一个整体的模块,还有最后它的一个可视化的呈现。后面会有一张更详细的图去介绍它整个的来源,以及最后可以输出的数据流向。
一般情况下,用户的原始数据,比如日志或者在事务型数据库中的数据,经过流式系统或离线处理后,导入到Doris中以供上层的报表工具或者数据分析师查询使用。
7 架构体系
7.1 名称解释
7.2 整体架构
Doris主要整合了Google Mesa(数据模型),Apache Impala(MPP Query Engine)和Apache ORCFile (存储格式,编码和压缩) 的技术。
为什么要将这三种技术整合?
- Mesa可以满足我们许多存储需求的需求,但是Mesa本身不提供SQL查询引擎。
- Impala是一个非常好的MPP SQL查询引擎,但是缺少完美的分布式存储引擎。
- 自研列式存储:存储层对存储数据的管理通过storage_root_path路径进行配置,路径可以是多个。存储目录下一层按照分桶进行组织,分桶目录下存放具体的tablet,按照tablet_id命名子目录。
因此选择了这三种技术的组合。
Doris的系统架构如下,Doris主要分为FE和BE两个组件:
Doris的架构很简洁,使用MySQL协议,用户可以使用任何MySQL ODBC/JDBC和MySQL客户端直接访问Doris,只设FE(Frontend)、BE(Backend)两种角色、两个进程,不依赖于外部组件,方便部署和运维。
- FE:Frontend,即 Doris 的前端节点。主要负责接收和返回客户端请求、元数据以及集群管理、查询计划生成等工作
- BE:Backend,即 Doris 的后端节点。主要负责数据存储与管理、查询计划执行等工作。
- FE,BE都可线性扩展
FE主要有两个角色,一个是follower,另一个是observer。多个follower组成选举组,会选出一个master,master是follower的一个特例,Master跟follower,主要是用来达到元数据的高可用,保证单节点宕机的情况下,元数据能够实时地在线恢复,而不影响整个服务。
Observer节点仅从 leader 节点进行元数据同步,不参与选举。可以横向扩展以提供元数据的读服务的扩展性。
数据的可靠性由BE保证,BE会对整个数据存储多副本或者是三副本。副本数可根据需求动态调整。
7.3 元数据架构
Doris采用==Paxos协议以及Memory+ Checkpoint + Journal的机制==来确保元数据的高性能及高可靠。元数据的每次更新,都会遵照以下几步:
- 首先写入到磁盘的日志文件中
- 然后再写到内存中
- 最后定期checkpoint到本地磁盘上
相当于是一个纯内存的一个结构,也就是说所有的元数据都会缓存在内存之中,从而保证FE在宕机后能够快速恢复元数据,而且不丢失元数据。
Leader、follower和 observer它们三个构成一个可靠的服务,如果发生节点宕机的情况,一般是部署一个leader两个follower,目前来说基本上也是这么部署的。就是说三个节点去达到一个高可用服务。单机的节点故障的时候其实基本上三个就够了,因为FE节点毕竟它只存了一份元数据,它的压力不大,所以如果FE太多的时候它会去消耗机器资源,所以多数情况下三个就足够了,可以达到一个很高可用的元数据服务。
7.4 数据分发
- 从表的角度来看数据结构,用户的一张 Table 会拆成多个 Tablet,Tablet 会存成多副本,存储在不同的 BE 中,从而保证数据的高可用和高可靠。
- 数据主要都是存储在BE里面,BE节点上物理数据的可靠性通过多副本来实现,默认是3副本,副本数可配置且可随时动态调整,满足不同可用性级别的业务需求。FE调度BE上副本的分布与补齐。
- 如果说用户对可用性要求不高,而对资源的消耗比较敏感的话,我们可以在建表的时候选择建两副本或者一副本。比如在百度云上我们给用户建表的时候,有些用户对它的整个资源消耗比较敏感,因为他要付费,所以他可能会建两副本。但是我们一般不太建议用户建一副本,因为一副本的情况下可能一旦机器出问题了,数据直接就丢了,很难再恢复。一般是默认建三副本,这样基本可以保证一台机器单机节点宕机的情况下不会影响整个服务的正常运作。
7.5 MPP架构
SELECT k1,SUM(v1) FROM A,B WHERE A.k2=B.k2 GROUP BY k1 ORDER BY SUM(v1)
该语句包含了合并、聚合计算、排序等多种操作;在执行计划的时候,MPP 将其拆分成多份,分布到每台机器执行,最后再将结果汇总。假如有10台机器,在大数据量下,这种查询执行方式可以使得查询性能达到10倍的提升。
基于Doris的小程序用户增长实践
导读:本文的主题为基于Doris的小程序用户增长实践,将从实际案例出发介绍基于 Doris 用户分层解决方案,重点分享了项目中的难点和架构解决方案,以及怎么使用 Doris做用户分层,如何做到秒级的人数预估和快速产出用户包。主要内容包括:
小程序私域精细化运营能力介绍
用户分层技术难点
用户分层的架构和解决方案
未来规划
01
小程序私域精细化运营能力介绍
好,现在开始。现在首先介绍一下我们小程序当前的私域精细化运营的能力有哪些。
首先我们为啥要做思域精细化运营呢,这起源于两个痛点:
私域用户的价值不突出
比如:我有100万个用户,我想给高收入人群去推荐奢侈品的包包,但是我不知道在这100万人里面有多少人是这种高收入人群
缺乏主动触达的能力
然后针对这两个问题,我们产品上面提出了一个解决方案 -- 就是分层运营,它主要分为两部分:一个是运营触达,还有一个是精细化的人群。
举个例子:如图示,从上往下看:当运营想搞一个活动时(比如 DataFun Talk 这个活动),可以选择消息、私信、卡券、小程序内这四个通路中的一个进行推送,选完通路之后,就需要选择需要推送的人群,这时候就要用到精细化人群,精细化人群是基于百度大数据平台提供的画像数据、新闻数据生成的,最后根据选择人群、推送通路完成推送。之后我们还会提供触达效果的分析,主要包括下发量、点展、到达之类的,另外针对人群也会提供整个用户群体更细致化的分析。
这套解决方案的收益和价值:
对于开发者来说:
合理地利用私域流量提升价值
促进用户活跃和转化
对于整个生态来讲:
提高了私欲利用率和活跃度
激活了开发者主动经营的意愿
促进了生态的良性循环
以上讲的是一个产品的方案,接下来跟大家讲一下具体的功能
1. 分层运营-B端视角
首先介绍下 B 端视角下分层运营平台是如何工作的,比如说我是开发者,我是怎么去做去创建用户分层的。
这里我们提供了自定义配置筛选的功能,可以从用户关注、卡券、交易、活跃行为、性别、年龄等多种维度选择,同时提供了预估人数的功能,可以实时的算出来你当前圈选的用户有多少人,方便评估一下人数是否 OK,如果 OK 的话,就直接生成人群,如果不 OK 的话,就重新选择筛选条件。
完成人群筛选之后,会进入分层管理列表,在列表里面可以根据需要点击对应的推送按钮就可以直接推送,推送方式包括私信、群发。当然了,这里也有群体分析功能。
B 端功能入口:
小程序开发者后台 -> 运营中心 -> 分层运营 -> 分层管理 -> 自定义筛选
2. 分层运营-C端视角
简单展示下 C 端视角下分层运营的一个样式:如图截取的是百度APP 上通知和私信的样式。
02
用户分层技术难点
1. 分层运营经典案例
下面给大家介绍分层运营的一个经典的案例 -- 我们跟汽车大师的合作案例:
需求是汽车大师要对近一周付费且活跃的用户进行一个评价送券的活动。图中截图展示了这个活动的交互过程:汽车大师推送一个通知(图中:8/6日通知),然后用户在《 百度APP -> 我的 -> 通知 》里面就可以看到汽车大师的通知消息,点开之后跳转到《咨询待评价页面》,然后写完评价后系统会自动发券并通知给用户;在这个活动中达成的效果如下:
准确判断了用户需求,活跃用户价值,页面的打开率达到了 9.51%
用户次均使用时长提升 2.5 倍
活动带来新增付费转化率达 17.71%
简单介绍下一些这里面的基本运营技巧:
结合和实际的业务场景,无中间页跳转的折损
拼接消息组件,自动发券场景过度顺转
场景可定期复用,节省人力成本。创建完人群之后,可以一直使用,不需要重复创建
"分享和使用" 双按钮强强势引导
上面的分享主要是让大家了解用户分层运营给开发者带来运营效率以及转化效果的一个提升,从而促进用户增长。这种看起来是特别的香,对不对 ?但是它有没有什么技术难点,答案是当然有,而且还特别大,不过没关系,大家不用担心了,你们认真听完煜杨老师接下来的分享这些难点就会变得很 Easy了,用之前一句特别流行的广告语就是:妈妈再也不用担心我的工作了。
2. 分层运营难点
难点的话,大家可以看下图,可以看到我把难点跟方法论都放到了一起,其实最开始我是想先讲难点,然后后面再讲方法论的,这样的话就可以调一下大家的胃口????。后来我又一想,大家都是程序员对不对,既如此,程序员何苦为难程序员,还是少一些套路,多一些真诚比较好。所以最后,我就把难点跟方法论都放到一起了,这样可以给大家一个直观的一个认识。
首先给大家简单介绍遇到的四个难点:
TB级数据。数据量特别大,前面讲到我们是基于画像和行为去做的一个用户分层,数据量是特别大的,每天的数据量规模是 1T +
查询的频响要求极高,毫秒级到秒级的一个要求。前面介绍 B 端视角功能时大家有看到,我们有一个预估人数的功能,用户只要点击 ”预估人数“ 按钮,我们就需要从 TB 级的数据量级里面计算出筛选出的人群人数是多少,这种要在秒级时间计算 TB 级的数量的一个结果的难度其实可想而知
计算复杂,需要动静组合。怎么理解?就是现在很多维度我们是没办法去做预聚合的,必须去存明细数据,然后去实时的计算,这个后面也会细讲
产出用户包的时效性要求高。这个比较好理解,如果产出特别慢的话,肯定会影响用户体验
针对上面的四个难点,我们的解法是:
针对第一个难点 --> 压缩存储,降低查询的数量级。
具体选型就是使用 Bitmap 存储,这解法其实很好理解,不管现在主流的 OLAP引 擎有多么厉害,数据量越大,查询肯定会越慢,不可能说数据量越大,我查询还是一直不变的,这种其实不存在的,所以我们就需要降低存储。
针对第二和第三个难点 --> 选择合适计算引擎
我们调研了当前开源的包括 ClickHouse, Doris, Druid 等多种引擎,最终选择了基于 MPP 架构的OLAP引擎 Doris。
这里可以简单跟大家介绍一下选择 Doris 的原因,从性能来说其实都差不多,但是都 Doris 有几个优点:
第一:它是兼容 Mysql 协议,也就是说你的学习成本非常低,基本上大家只要了解mysql, 就会用Doris, 不需要很大的学习成本。
第二:Doris 运维成本很低,基本上就是自动化运维。
针对第四个难点 --> 选择合适的引擎
通过对比 Spark 和 Doris,我们选择了 Doris ,后面会详细讲为什么会用 Doris。
03
用户分层的架构和解决方案
介绍难点以及解法之后,接下来从架构跟解决方案里面跟大家细讲一下,难点是怎么解决的。
分层运营架构:
首先介绍一下我们分层运营的架构。架构的话分为两部分,就是在线部分跟离线部分。
在线部分:
分为了四层:服务层、解析层、计算层跟存储层,然后还有调度平台和监控平台。
服务层,主要功能包含:
权限控制:主要是户权限、接口权限的控制
分层管理:主要是是对用户筛选的增删改查
元数据管理:主要是对页面元素、ID-Mapping 这类数据的管理
任务管理:主要是支持调度平台任务的增删改查
解析层,是对DSL的一个解析、优化、路由以及Sql模板:
比如要查在线预估人数,首先会在解析层做一个 DSL 的解析,之后根据不同情景做 DSL 的优化,比如选择了近七天活跃且近七天不活跃的用户,这种要七天活跃和七天不活跃的交集显然就是零了,对不对?像这样情况在优化层直接将结果 0 返回给用户就不会再往下走计算引擎,类似还有很多其他优化场景。然后优化完之后会使用 DSL 路由功能,根据不同查询路由到不同的 Sql 模板进行模板的拼接。
计算层,计算引擎我们使用 Spark 和 Doris:
Spark:离线任务
Doris:实时任务
存储层:
Mysql:主要用来存用户分层的一些用户信息
Redis:主要用作缓存
Doris:主要存储画像数据和行为数据
AFS:主要是存储产出的用户包的一些信息
调度平台:
主要是离线任务的调度
监控平台:
整个服务稳定性的监控
离线部分:
离线部分的话主要是对需要的数据源(比如说画像、关注、行为等数据源)做 ETL 清洗,清洗完之后会做一个全局字典并写入 Doris。任务最终会产出用户包,并会分发给小程序 B 端跟百度统计:
小程序 B 端:推送给手机端用户
百度统计:拿这些用户包做一次群体分析
以上就是一个整体的架构。
图中大家可以看到有几个标红的地方,同时也用数字 1、2、3 做了标记,这几个标红是重点模块,就是针对于上面提到的四个难点做的重点模块改造,接下来会针对这三个重点模块一一展开进行讲解。
1. 全局字典
首先讲解全局字典这个模块,全局字典的目的主要是为了解决难点一:数据量大,需要压缩存储同时压缩存储之后还要保证查询性能。
为啥要用全局字典:
这里大家可能会有一个疑问,就是说我用 BitMap 存储为啥还要做全局字典?这个主要是因为 Doris 的 BitMap 功能是基于 RoaringBitmap 实现的,因此假如说用户 ID 过于离散的时候,RoaringBitmap 底层存储结构用的是 Array Container 而不是 BitMap Container,Array Container 性能远远差于 BitMap Container。因此我们要使用全局字典将用户 ID 映射成连续递增的 ID,这就是使用全局字典的目的。
全局字典的更新逻辑概况:
这里是使用 Spark 程序来实现的,首先加载经过 ETL 清洗之后各个数据源(画像、关注、行为这些数据源)和全局字典历史表(用来维护维护用户 ID 跟自增 ID 映射关系),加载完之后会判断 ETL 里面的用户ID 是否已经存在字典表里面,如果有的话,就直接把 ETL 的数据写回 Doris 就行了,如果没有就说明这是一个新用户,然后会用 row_number 方法生成一个自增 ID ,跟这个新用户做一次映射,映射完之后更新到全局字典并写入 Doris。
2. Doris
接下来介绍第二个重点模块 Doris。
2.1 Doris 分桶策略
分桶策略的目的是为了解决难点二:查询频响要求高。
为啥要做分桶策略:
我们之前使用了全局字典保证用户的连续递增,但是我们发现用了全局字典之后,BitMap 的查询性能其实并没有达到我们预期的那样丝滑般柔顺的感觉,哈哈哈。。。对,还是特别慢,然后我们就特别郁闷了,开始怀疑 BitMap 并不像传说中的那么快,难道童话都是骗人的吗?我们就在想怎么解决这个问题,后来我们发现 Doris 其实是分布式的一个集群,它会按照某些 Key 进行分桶,也就是分桶之后用户ID 在桶内就不连续,又变成零散的了。
举个例子,如图中左侧原始数据,可以看到 appkey 有A1、A2,channel 有C1、C2、C3,然后 userid 是0、1、2、3、4、5 六个连续的 userid 。我们按照 appkey 和 channel 进行分桶,这样的话分完桶之后的结果就是右边这张图:桶一 key 是A1、C1,userid 就是0、2;桶二 key 是 A1、C2,userid 就是 1、4;桶三 key 是A2、C3,userid 是3、5;大家能比较直观地看到在桶中 userid 已经不连续了,不连续的话,BitMap 的性能就没法发挥出来的,它会走 Array Container 去存储,它的性能会比较差。
解决方式:
这里,其实我想问一下大家,这种怎么去保证桶内的连续?大家如果有想法,可以私下一起讨论下,现在大家不要给自己加戏啊, 今天的star是我啊, 大家要focus on me 身上啊。开个玩笑啊, 活跃下直播间气氛。
接下来我会跟大家分享一下我们的一个方案,对了,给大家五秒钟的时间,大家可以现在记笔记了,真的,这个方案是我们经历了无数个日日夜夜跟无数根头发总结出来的,非常有实战意义。
好,现在讲一下我们的方案,我们的方案是在表里面增加了一个 hid 的字段,然后让 Doris 按照 hid 字段进行分桶,这里 hid 生成算法是:
hid = V/(M/N) 然后取整
其中:
V:全局字典的用户ID 对应的整数
M:预估的用户总数
N:分层数
还是结合上面的例子,大家可以看一下:userid 是六个即 0~5,所以 M= 6;分为三个桶,N = 3;因此 M 除以 N 就等于二。这样的话我就要用 userid 去除以二,然后取整作为 hid。可以看一下,比如说 userid 是零,0÷2 取整为 0 ,userid 是一的话,hid 还是这样,因为 1÷2 的整数部分是零;同理 2÷2 、3÷2 是一,4÷2、5÷2 是二,这样的话就把 userid 跟 hid 做对应,然后再根据 hid 做分层。大家可以看到分层结果,hid = 0 时 userid 是0、1,hid = 1 时 userid 是2、3,hid = 2时 userid 是 4、5,这样就保证了桶内连续。
2.2 doris之用户画像标签优化
前面给大家讲了分桶与全局字典这两个通用的策略,就是说大家要做 BitMap 的话,这两个东西肯定是要考虑的,但是只考虑这两个东西,还并不能说达到性能的最优,还要结合自己的实际业务去做针对性的优化,这样才能达到一个性能的最优,接下来我会给大家介绍我们的具体业务优化:画像标签的优化。
画像标签优化解决的难点也是难点二:查询频响要求高。这个问题当时是有两个方案。
方案一:
tag_type, tag_value 。tag_type 是用来记录标签的类型,tag_value 是用来记录标签的内容。
如图所示:比如说 tag_type 是性别,tag_value 可能是男或女,bitmap 这里就是存储所有性别是男的用户 id 列表。
同样对于 tag_type 是地域、tag_value 是北京,bitmap 存储的是所有地域在北京的用户 id 列表。
方案二:
大宽表,使用大宽表在一行记录了所有的标签,然后使用 bitmap 记录这个标签的用户 id 列表。
最终我们选择了方案二,为什么没有选方案一呢 ?因为方案一它是一个标签对应一个用户 bitmap,当我想查一个联合的结果就比较耗时,比如我想查询性别是男且区域是北京的所有用户,这样的话我需要取出 “男” 的用户和 “北京“ 的用户,两者之间做一个交集,对吧?这种的话肯定会有计算量会有更多的时间消耗,但是如果用大宽表去做存储的话,就可以根据用户常用的查询去构建一个物化视图,当用户的查询(比如在北京的男性)命中了物化视图,就可以直接去取结果,而不用再去做计算,从而降低耗时。
这里还有一个知识点跟大家分享一下:在使用 Doris 的时候,一定要尽量去命中它的前缀索引跟物化视图,这样会大大的提升查询效率。
2.3 doris之动静组合查询
好,用户标签讲完之后继续讲下一个难点的解决方案:动静组合查询,对应的难点是难点三:计算复杂。
首先介绍一下什么叫动静组合查询:
静态查询:我们定义为用户维度是固定的,就是可以进行预聚合的查询为静态查询。比如说男性用户,男性用户个就是一个固定的群体,不管怎么查用户肯定不会变,就可以提前进行预聚合的。
动态查询:主要偏向于一些行为,就是那种查询跟着用户的不同而不同。比如说查近30天收藏超过三次的用户,或者还有可能是近30天收藏超过四次的用户,这种的话就很随意,用户可能会查询的维度会特别的多,而且也没法没办法进行一个预聚合,所以我们称之为动态的一个查询。
然后小程序用户分层,相比于同类型的用户分层功能增加了用户行为筛选,这也是小程序产品的特点之一。比如说我们可以查近 30 天用户支付订单超过 30元的男性, 这种 ”近 30天用户支付订单超过 30元“ 的查询是没办法用 bitmap 做记录的,也没办法说提前计算好,只能在线去算。这种就是一个难点,就是说我怎么用非 bitmap 表和 bitmap 做交并补集的运算,为了解决这个问题,我们结合上面的例子把查询拆分为四步:我要查近30天用户支付订单超过30元的男性,且年龄在 20 ~30 岁的用户(具体查询语句参考 PPT 图片)
第一步我先查 20~30岁的男性用户。因为是比较固定,这里可以直接查 bitmap 表,
第二步我要查近30天用户支付订单超过30元的用户。这种的话就没办法去查 bitmap 表了,因为 bitmap 没有办法做这种聚合,只能去查行为表。
第三步就是要做用户ID 跟在 线 bitmap 的一个转化。Doris 其实已经提供了这样的功能函数: to_bitmap,可以在线将用户 id 转换成 bitmap。
第四步是求交集。就是第一步和第四步的结果求交集。
然后,请大家要注意一下,整篇的核心其实是在第三步:Doris 提供了 to_bitmap 的功能,它帮我们解决了非 bitmap 表和 bitmap 联合查询的问题。讲到这里,我其实想给大家表现出那种Doris特别惊艳、特别帅那种感觉,但是我线下练习了好多遍都无法表演出来, 你们看我现在的表演 有点太浮夸了, 用力过猛了。谁让我是个程序员,不是个演员呢,没有办法演出那种感觉、那种感情。所以我只能把我想表达的感情跟大家说出来,大家一定要懂我,对,就是那种很惊艳的感觉,大家一定要懂我~
以上是我们基于 Doris 用户分层方案的一个讲解,基于上述方案整体的性能收益是:
95分位耗时小于一秒
存储耗降低了9.67倍
行数优化了八倍
说明了基于 Doris 的用户存储方案还是特别有效果的, 希望我们的经验能给大家能有所帮助。
3. 如何快速产出用户包
现在讲一下第三部分:用户包。这部分主要是用来解决难点四:产出用户包要求时效性高。这个其实我们也有两个方案:
方案一:调度平台 + spark。
这个其实比较容易理解,因为你要跑离线任务很容易就想到了 spark。在这个调度平台里面用了 DAG 图,分三步:先产出用户的 cuid,然后再产出用户的 uid,最后是回调一下做一次更新。
方案二:调度平台 + solo。
执行的 DAG 图的话就是:solo 去产出 cuid,uid,还有回调。
solo:是百度云提供的 Pingo 单机执行引擎,大家可以理解为是一个类似于虚拟机的产品,这个其实是公有云:《百度智能云》里面已经有的功能,大家感兴趣的可以去登录百度智能云官网 去看一下。
最终的方案选型我们是选用了 Doris,因为 Doris 比 Spark 更快,为啥快?
首先介绍下方案一,方案一使用的是 Spark ,它存在几个问题:比如 Yarn 调度比较耗时,有时候也会因为队列的资源紧张而会有延迟,所以有时候会出现一个很极端的情况就是:我产出零个用户,也要30分钟才能跑完,这种对用户的体验度非常不好。
方案二的话就是我们利用了 Doris 的 SELECT INTO OUTFILE 产出结果导出功能,就是你查出的结果可以直接导出到 AFS,这样的效果就是最快不到三分钟就可以产出百万级用户,所以 Doris 性能在某些场景下比 Spark 要好很多。
最后大家可以看到其实我这里叙述的时候语气依然是比较平淡的,是吧?没有带什么感情,但是我其实还想表达出那种惊叹和喜悦的感情,就是 Doris 性能在某些场景下比 Spark 还要好,但是大家要懂我,我毕竟是个程序员不是一个演员,没法表达出那种感觉,但是你们一定要懂我啊,哈哈,开个玩笑,活跃一下直播间气氛。
04
未来规划
未来的规划:
首先在产品上我们会继续的丰富分层的应用场景,拓展关系维度丰富触达的形式,然后探索分层和商业的结合模式。
在技术上我们会从时效性丰富性跟通用性上做文章:
时效性:我们会把交易,订单,关注等行为时实化
丰富性:我们会接入更多的用户画像,标签和行为
通用性:我们会把全局字典插件化,然后通用到各个业务上
这就是我们的未来规划。后面有机会再根大家从 Doris 的架构方面跟大家介绍下 Doris 的性能为何如此强悍。
今天的分享就到这里,谢谢大家。
在文末分享、点赞、在看,给个3连击呗~
分享嘉宾:
赵煜杨
百度 | 资深研发工程师
负责手百小程序数据产品的工程架构工作,从0到1主持设计了精细化用户分层系统,实现了百亿级TB量级小程序用户画像、行为数据秒级预估,保障了小程序私域运营的落地。具有超过6年在高可用、大数据方向的工作经验,一直专注在数据工程架构、个性化推荐工程等工作上,对技术团队管理也比较有经验,目前个人专注于大数据、个性化推荐、高可用架构等技术方向。
以上是关于Doris:Doris介绍的主要内容,如果未能解决你的问题,请参考以下文章
悄悄学习Doris,偷偷惊艳所有人 | Apache Doris四万字小总结