Doris实战——美联物业数仓

时间:2024-03-03 08:18:09

目录

一、背景

1.1 企业背景

1.2 面临的问题

二、早期架构

三、新数仓架构

3.1 技术选型

3.2 运行架构

3.2.1 数据模型

 纵向分域

横向分层

数据同步策略

3.2.2 数据同步策略

 增量策略

全量策略

四、应用实践

4.1 业务模型

4.2 具体应用

五、实践经验

5.1 数据导入

5.2 数据模型

5.3 查询优化—前缀索引

5.4 外部数据源读取

5.5 数据字典

六、架构收益

七、生产问题

  原文大佬的这篇Doris数仓的实战文章写的挺全面(跟本人目前所负责的数仓项目,有些分析场景 很相似),这里直接摘抄下来用作学习和知识沉淀。

一、背景

1.1 企业背景

     传统行业面对数字化转型往往会遇到很多困难,比如缺乏数据管理体系、数据需求开发流程冗长、烟囱式开发、过于依赖纸质化办公等,美联物业也有遇到类似的问题。本文主要介绍关于美联物业在数据体系方面的建设,以及对数据仓库搭建经验进行的分享和介绍,旨在为数据量不大的传统企业提供一些数仓思路,实现数据驱动业务,低成本、高效的进行数仓改造。

1.2 面临的问题

    美联物业早在十多年前就已深入各城市开展房地产中介业务,数据体系的建设和发展与大多数传统服务型公司类似。

     我们的数据来源于大大小小的子业务系统和部门手工报表数据等,存在历史存量数据庞大,数据结构多样复杂,数据质量差等普遍性问题。此外,早期业务逻辑处理多数是使用关系型数据库 SQL Server 的存储过程来实现,当业务流程稍作变更,就需要投入大量精力排查存储过程并进行修改,使用及维护成本都比较高。

  基于此背景,我们面临的挑战可以大致归纳为以下几点:

 (1)缺乏数据管理体系,数据无法降本复用:多部门、多系统、多字段,命名随意、表违反范式结构混乱;对同一业务来源数据无法做到多份报表复用,反复在不同报表编写同一套计算逻辑。

(2)历史大多数业务数据存储在关系型数据库中,分表分库已无法做到上亿数据秒级分析查询。

(3)数据需求开发流程冗长、烟囱式开发。每当业务部门提出一个数据需求,数据开发就需要在多个系统之间进行数据兼容编写存储过程,从而导致存储过程的可移植性和可读性都非常差。

(4)部门之间严重依赖文本文档的处理工作,效率低下。

二、早期架构

   针对上述的几个需求,我们在平台建设的初期选⽤了 Hadoop、Hive、Spark 构建最初的离线数仓架构,也是比较普遍、常见的架构,运作原理不进行过多赘述。

   我们数据体系主要服务对象以内部员工为主,如房产经纪人、后勤人员、行政人事、计算机部门等。当前数据体系无需面向 C 端用户,因此在数据计算和资源方面的压力并不大,早期基于 Hadoop 的架构可以满足一部分基本的需求。但是随着业务的不断发展、内部人员对于数据分析的复杂性、分析的效率也越来越高,该架构的弊端日益越发的明显,主要体现为以下几点:

(1)传统数据架构组件繁多,维护复杂,运维难度非常高。

(2)数据处理链路过长,导致查询延迟变高

(3)数据时效性低:只可满足T+1的数据需求,导致数据分析效率低下

(4)传统公司的计算量和数据量不大,搭建Hadoop生态组件显得杀鸡用牛刀。

三、新数仓架构

   基于上述业务需求及痛点,我们开始了架构升级,并希望在这次升级中实现几个目标:

  • 初步建立数据管理体系,搭建数据仓库。

  • 搭建报表平台和报表快速开发流程体系。

  • 实现数据需求能够快速反应和交付(1小时内),查询延迟不超过 10s。

  • 最小成本原则构建架构,支持滚动扩容。

3.1 技术选型

    经过调研了解以及朋友推荐,了解到了Doris ,并很快与社区取得了联系,Doris的优势如下:

(1)极速性能

    Doris 依托于列式存储引擎、自动分区分桶、向量计算、多表Join能力强悍和物化视图等功能的实现,可以覆盖众多场景的查询优化,海量数据也能可以保证低延迟查询,实现分钟级或秒级响应。

(2)极低成本

     降本提效已经成为现如今企业发展的常态,免费的开源软件就比较满足我们的条件,另外基于 Doris 极简的架构、语言的兼容、丰富的生态等,为我们节省了不少的资源和人力的投入。并且 Doris 支持 PB 级别的存储和分析,对于存量历史数据较大、增量数据较少的公司来说,仅用 5-8 个节点就足以支撑上线使用。

(3)足够简单

    美联物业及大部分传统公司的数据人员除了需要完成数据开发工作之外,还需要兼顾运维和架构规划的工作。因此我们选择数仓组件的第一原则就是"简单",简单主要包括两个方面:

  • 架构简单:Doris 的组件架构由 FE+BE 两类进程组成,不依赖其他系统,整体架构简洁易用,极简运维,弹性伸缩.

  • 使用简单:Apache Doris 兼容 MySQL 协议,支持标准 SQL,有利于开发效率和共识统一,此外,Doris 的 ETL 编写脚本主要使用 SQL进行开发,使用 MySQL 协议登陆使用,兼容多数 MySQL 语法,提供丰富的数据分析函数,省去了 UDF 开发工作。

3.2 运行架构

    在对Doris性能检测之后,我们完全摒弃了之前使用 Hadoop、Hive、Spark 体系建立的数仓,决定基于Doris 对架构进行重构,以 Doris 作为数仓底座进行开发,实现存,算统一。

  • 数据集成:利用 DataX、Flink CDC 和Doris 的 Multi Catalog 功能等进行数据集成。
  • 数据管理:利用 Apache Dolphinscheduler 进行脚本开发的生命周期管理、多租户人员的权限管理、数据质量校验等。

  • 监控告警:采用 Grafana + Prometheus进行监控告警,Doris 的各项监控指标可以在上面运行,解决了对组件资源和日志的监控问题。

  • 数据服务:使用帆软 Report 为用户提供数据查询和分析服务,帆软支持表单制作和数据填报等功能,支持自助取数和自助分析。

3.2.1 数据模型

 纵向分域

    房地产中介行业的大数据主题大致如下,一般会根据这些主题进行数仓建模。建模主题域核心围绕"企业用户"、"客户"、"房源"、"组织"等几个业务实体展开,进行维度表和事实表的设计。

   我们从前线到后勤,对业务数据总线进行了梳理,旨在整理业务实体和业务活动相关数据,如多个系统之间存在同一个业务实体,应统一为一个字段梳理业务总线有助于掌握公司整体数据结构,便于维度建模等工作。

   下图为我们简单的梳理部分房地产中介行业的业务总线:

横向分层

   数据分层采用传统数仓最常见的 5 层结构(ods, dwd,dim,dws,ads),主要是利用 Apache Doris + Apache DolphinScheduler 进行层级数据之间的调度任务编排和管理。

数据同步策略

  我们在8点到24点之间采用增量策略,0点到8点执行全量策略,采用增量+全量的方式是考虑到:当ODS表因为记录的历史状态字段变更或者CDC出现数据未完全同步的情况下,可以及时进行全量补数和修正历史状态变化数据

层级 备注 存储策略
ODS 利用datax doris write进行数据的本地导入要注意参数设置exec_mem_limit参数大小,部分全量数据较大超过限制会导致stream load 失败 8点到24点增量策略;0点到8点全量策略一次
DWD 部分事实表涉及缓慢变化维,需要进行拉链存储 8点到24点增量策略;0点到8点全量策略一次,部分表拉链存储
DWS和ADS 注意数据校验问题,加入审计时间,如etl_time,last_etl_time,create_time等字段,方便后续故障排查 8点到24点增量策略;0点到8点全量策略一次
DIM 维度表存放层,如客户,房源,职员,职级,岗位等 每小时整点全量

3.2.2 数据同步策略

 增量策略

1)where >= "业务时间-1天或-1小时"

     增量的 SQL 语句不使用where ="业务时间当天"的原因是为了避免数据漂移情况发生,换言之,调度脚本之间存在时间差,如 23:58:00 执行了脚本,脚本的执行周期是10 分钟/次,但是源库中最后一条数据是在23:59:00才新增的,真正这时候where="业务时间当天"就会将该数据漏掉。

2)每次跑增量脚本前,需要将表中最大的主键ID存入辅助表,where >= "辅助表记录ID"

    如果 Doris 表使用的是 Unique Key 模型,且恰好为组合主键,当主键组合在源表发生了变化,这时候where >=" 业务时间-1天"会记录该变化,把主键发生变化的数据 Load 进来,从而造成数据重复。而使用这种自增策略可有效避免该情况发生,且自增策略只适用于源表自带业务自增主键的情况。

3)表分区

   例如日志表等基于时间的自增数据,且历史数据和状态基本不会变更,数据量非常大,全量或快照计算压力非常大的场景,这种场景需要对 Doris 表进行建表分区,每次增量进行分区替换操作即可,同时需要注意数据漂移情况。

全量策略

1)Truncate Table清空表插入

       如果是面向C端用户的公司和白天调度时间千万别这么做,否则会导致一段时间没有数据,Truncate Table适合数据量较小的表,凌晨没有用户使用系统的公司。

2)ALTER TABLE tbl1 REPLACE WITH TABLE tbl2  表替换

    这种方式是一种原子操作,适合数据量大的全量表。每次执行脚本前先 Create 一张数据结构相同的临时表,把全量数据 Load 到临时表,再执行表替换操作,可以进行无缝衔接。

四、应用实践

4.1 业务模型

  • 业务模型是最常见的分钟级调度ETL
  • 离线数据利用DataX批量同步,通过Flink CDC将RDS的数据实时同步到Doris,利用Doris的物化视图或者Aggregate模型表进行实时汇总处理。
  • 所有层级表模型大部分采用Unique key主键模型,可以有效保证数据脚本的幂等性,解决下游数据重复的问题
  • ETL脚本通过Dolphinscheduler(简称DS)进行编排和统一调度
  • 帆软BI进行自助取数和分析

部署建议

  • 初次部署建议配置:8 节点 2FE * 8BE 混合部署

  • 节点配置:32C * 60GB * 2TB SSD

  • 对于存量数据TB级、增量数据GB级的场景完全够用,如有需要可以进行滚动扩容。

4.2 具体应用

    1)离线业务数据和日志数据集成利用 DataX 进行增量和全量调度,Datax支持CSV格式和多种关系型数据库的Redear,而 Doris 在很早之前就提供了 DataX Doris writer 连接器。

   2)实时部分借助了Flink CDC将RDS的数据实时同步到Doris,利用Doris的物化视图或者Aggregate模型表进行实时指标的汇总处理,因为我们只有部分指标需要实时处理,不希望产生过多的数据库连接和 Flink Job,因此我们使用Dinky的多源合并和整库同步功能,也可以自己简单实现一个Flink DataStream 多源合并任务,只通过一个 Job 可对多个 CDC 源表进行维护。值得一提的是, Flink CDC 和 Apache Doris 新版本支持 Schema Change 实时同步,在成本允许的前提下,可完全使用 CDC 的方式对 ODS 层进行改造。

EXECUTE CDCSOURCE demo_doris WITH (
  'connector' = 'mysql-cdc',
  'hostname' = '127.0.0.1',
  'port' = '3306',
  'username' = 'root',
  'password' = '123456',
  'checkpoint' = '10000',
  'scan.startup.mode' = 'initial',
  'parallelism' = '1',
  'table-name' = 'ods.ods_*,ods.ods_*',
  'sink.connector' = 'doris',
  'sink.fenodes' = '127.0.0.1:8030',
  'sink.username' = 'root',
  'sink.password' = '123456',
  'sink.doris.batch.size' = '1000',
  'sink.sink.max-retries' = '1',
  'sink.sink.batch.interval' = '60000',
  'sink.sink.db' = 'test',
  'sink.sink.properties.format' ='json',
  'sink.sink.properties.read_json_by_line' ='true',
  'sink.table.identifier' = '${schemaName}.${tableName}',
  'sink.sink.label-prefix' = '${schemaName}_${tableName}_1'
);

3) 脚本语言采用shell+sql或纯sql的形式,我们在Apache DolphinScheduler上进行脚本生命周期管理和发布,如ODS层,可以编写通用的DataX Job 文件,通过传参的方式将DataX Job 文件传参执行源表导入,无需在每一个源表编写不同的DataX Job,支持统一配置参数和代码内容,维护起来非常方便。另外我们在 DolphinScheduler上对 Doris 的 ETL 脚本进行管理,还可以进行版本控制,能有效控制生产环境错误的发生,进行及时回滚。

4) 发布 ETL 脚本后导入数据,可直接在帆软 Report 进行页面制作。基于登陆账号来控制页面权限,如需控制行级别、字段级别权限,可以制作全局字典,利用 SQL 方式进行控制。Doris 完全支持对账号的库表权限控制,这一点和 MySQL 的设置完全一样,使用起来非常便捷。

  在新的架构体系,新增的数据需求直接利用帆软BI进行自助取数和分析,最快可在当天响应交付

   除以上之外,还可以利用 Doris备份实现容灾恢复、Grafana + Prometheus对集群进行指标规则监控告警、开启 Doris审计日志对执行 SQL 效率进行监控等,慢查询定位及优化等,因篇幅限制,此处不进行详细说明。

五、实践经验

5.1 数据导入

  我们使用 DataX进行离线数据导入,DataX 采用的是 Stream Load方式导入,该方式可以通过参数控制导入批次流量,DataX导入不需要借助计算引擎,开箱即用的特点非常方便。另外,Stream Load导入是同步返回结果,而其他导入方式一般是异步返回结果。

    在数据导入方式上,大部分返回结果是异步操作,即在Doris里该导入任务状态有可能是失败的,而Dolphinscheduler会误以为该脚本已经执行成功,因此在bash等脚本里执行Doris的导入操作逻辑时,还需要判断上游任务状态是否成功,可以在脚本里执行show load,再用正则去过滤状态进行判断。

5.2 数据模型

   所有层级表模型大部分采用Unique key主键模型,可以有效保证数据脚本的幂等性,解决下游数据重复的问题。

5.3 查询优化—前缀索引

    尽量把非字符类型的,如int类型的、where条件中最常用的字段放前排36个字节内,在点查场景下,过滤这些字段返回的结果基本可在毫秒级别实现。

5.4 外部数据源读取

   Catalog 方式:使用 JDBC 外表连接,对 Doris生产集群数据进行读取,便于生产数据直接 Load 进测试服务器进行测试。另外,新版支持多数据源的Catalog,可以基于 Catalog 对 ODS 层进行改造,无需使用 DataX 对ODS 进行导入。

   但这种方式对FE节点的压力会很大,在导入过程中可明显观察FE节点CPU资源被拉满,如果Fe资源并不充足的情况下,建议选择Stream load的方式进行数据导入,如Datax。

5.5 数据字典

     利用Doris自带的information_schema元数据可以制作简单的数据字典,这一点对公司还未建立数据治理体系前是非常重要的一步,方便低成本管理数仓人员的操作规范。

利用 Doris自带的information_schema元数据制作简单的数据字典,利用数据字典可快速对表格和字段的全局查找和释义,这一点对公司还未建立数据治理体系前是非常重要的一步,最低成本形成数仓人员的数据规范,减少人员沟通成本,提高开发效率。

六、架构收益

   引入 Doris 之后,美联物业实现了只用少数服务器、快速搭建一套数据仓库,成功实现降本赋能。在这段时间的运行中,给我们带来的部分收益如下:

  • 自动取数导数:数据仓库的明细表可以定时进行取数、导数,自助组合维度进行分析。
  • 效率提升:T+1 的离线任务,时效降低至分钟级。

  • 查询延迟降低:面对上亿行数据的表,利用Doris在索引和点查方面的能力,即席查询延迟平均在1秒内,复杂查询也能5秒内响应。

  • 运维成本降低:从数据集成到数据服务,只需维护少数组件就可以实现整个链路的高效管理。

  • 存储资源节省:Doris 超高的压缩比,将数据压缩了70%,相较于 Hadoop 来说,存储资源的消耗大幅降低。

  • 数据管理体系初步形成:Doris 数仓的实现使得数据资产得以规范化的沉淀。

七、生产问题

  • 内存一直不释放

     Doris的BE节点在旧版本是开启PageCache 和 ChunkAllocator 的,目的是为了减少查询的延迟,这两个功能会占用一定比例的内存,并且一直不会释放,长此以往就会导致be计算资源越来越紧张。新版本直接禁用了这两个配置,但美联物业数仓是开启了这2项配置,并且每天凌晨进行be滚动重启的,既能保证be内存及时释放,也能降低查询延迟。

  • 数据备份

     目前Doris的备份依赖Broker load,只能基于BOS、HDFS 等文件系统,对于没有安装HDFS这类的服务器基本用不了。

参考文章:

Apache Doris 在美联物业的数据仓库应用实践,助力传统行业数字化革新|应用实践

美联物业基于Apache Doris数仓实践