数据仓库就是为了解决数据库不能解决的问题而提出的
OLTP
OLTP(OnLine Transaction Processing 联机事务处理) 。简单一些,就是数据库的增删查改。举个例子,你到银行,去取一笔钱出来,或者转账,或者只是想查一下你还有多少存款,这些都是面向“事务”类型的操作。这样的操作有几个显著的特点:
- 首先要求速度很快, 基本上都是高可靠的在线操作(比如银行)
- 还有这些操作涉及的数据内容不会特别大(否则速度也就相应的降低)
- 最后,“事务”型的操作往往都要求是精准操作,比如你去银行取款,必须要求一个具体的数字,你是不可能对着柜台员工说我大概想取400到500快之间吧,那样人家会一脸懵逼;
OLAP
OLAP是Online analytical processing的英文缩写,指联机分析处理。从字面上我们能看出是做分析类操作。通过分析数据库中的数据来得出一些结论性的东西
为了表示跟OLTP的数据库(database)在数据量和复杂度上的不同,一般称OLAP的操作对象为数据仓库(data warehouse),简称数仓;
对于数据仓库的概念我们可以从两个层次予以理解:
- 首先,数据仓库用于支持决策,面向分析型数据处理,它不同于企业现有的操作型数据库;
- 其次,数据仓库是对多个异构的数据源有效集成,集成后按照主题进行了重组,并包含历史数据,而且存放在数据仓库中的数据一般不再修改;
总结:为了进行OLAP,把分布在各个散落独立的数据库孤岛整合在了一个数据结构里面,称之为数据仓库;
- 面向主题:面向主题特性是数据仓库和操作型数据库的根本区别;所谓主题:是指用户使用数据仓库进行决策时所关心的重点方面,如:收入、客户、销售渠道等;所谓面向主题,是指数据仓库内的信息是按主题进行组织的,而不是像业务支撑系统那样是按照业务功能进行组织的
- 集成性:集成性是指数据仓库会将不同源数据库中的数据汇总到一起;
- 企业范围:数据仓库内的数据是面向公司全局的。比如某个主题域为成本,则全公司和成本有关的信息都会被汇集进来;
- 历史性:较之操作型数据库,数据仓库的时间跨度通常比较长。前者通常保存几个月,后者可能几年甚至几十年;
- 时变性:时变性是指数据仓库包含来自其时间范围不同时间段的数据快照。有了这些数据快照以后,用户便可将其汇总,生成各历史阶段的数据分析报告;
数据仓库平台逐步从BI报表为主到分析为主、到预测为主、再到操作智能为目标
数据仓库的核心组件有四个:
- 业务系统各源数据库:业务系统包含各种源数据库,这些源数据库既为业务系统提供数据支撑,同时也作为数据仓库的数据源(注:除了业务系统,数据仓库也可从其他外部数据源获取数据);
- ETL:数据仓库会周期不断地从源数据库提取清洗好了的数据,因此也被称为"目标系统"。ETL分别代表:
- 提取extraction:表示从操作型数据库搜集指定数据;
- 转换transformation:表示将数据转化为指定格式,并进行数据清洗保证数据质量;
- 加载load:加载过程表示将转换过后满足指定格式的数据加载进数据仓库;
- 数据仓库
- 前端应用
叫“湖”的另一个重要原因是数据湖是需要精细治理的,一个缺乏管控、缺乏治理的数据湖最终会退化为“数据沼泽”,从而使应用无法有效访问数据,使存于其中的数据失去价值
数据湖(Data Lake)是一个存储企业的各种各样原始数据的大型仓库,其中的数据可供存取、处理、分析及传输。数据湖是以其自然格式存储的数据的系统或存储库,通常是对象blob或文件;
数据湖通常是企业所有数据的单一存储,包括源系统数据的原始副本,以及用于报告、可视化、分析和机器学习等任务的转换数据;
数据湖可以包括:
- 来自关系数据库(行和列)的结构化数据;
- 半结构化数据(CSV,日志,XML,JSON);
- 非结构化数据(电子邮件,文档,PDF)和二进制数据(图像,音频,视频);
目前,HDFS是最常用的部署数据湖的技术,所以很多人会觉得数据湖就是HDFS集群。数据湖是一个概念,而HDFS是用于实现这个概念的技术。
AWS关于数据湖:数据湖是一个集中式存储库,允许您以任意规模存储所有结构化和非结构化数据。您可以按原样存储数据(无需先对数据进行结构化处理),并运行不同类型的分析 – 从控制面板和可视化到大数据处理、实时分析和机器学习,以指导做出更好的决策;
总结:
- 数据湖中的数据是原始数据,是业务数据的完整副本;数据湖中的数据保持了他们在业务系统中原来的样子。
- 数据湖需要具备完善的数据管理能力(完善的元数据) 可以管理各类数据相关的要素,包括数据源、数据格式、连接信息、数据schema、权限管理等。
- 数据湖需要具备多样化的分析能力 包括但不限于批处理、流式计算、交互式分析以及机器学习;同时,还需要提供一定的任务调度和管理能力。
- 数据湖需要具备完善的数据生命周期管理能力。不光需要存储原始数据,还需要能够保存各类分析处理的中间结果,并完整的记录数据的分析处理过程,能帮助用户完整详细追溯任意一条数据的产生过程;
- 数据湖需要具备完善的数据获取和数据发布能力。数据湖需要能支撑各种各样的数据源,并能从相关的数据源中获取全量/增量数据;然后规范存储。数据湖能将数据分析处理的结果推送到合适的存储引擎中,满足不同的应用访问需求。
总结:数据湖应该是一种不断演进中、可扩展的大数据存储、处理、分析的基础设施;以数据为导向,实现任意来源、任意速度、任意规模、任意类型数据的全量获取、全量存储、多模式处理与全生命周期管理;并通过与各类外部异构数据源的交互集成,支持各类企业级应用;
数据湖还有以下特点:
- 从源系统导入所有的数据,没有数据流失。
- 数据存储时没有经过转换或只是简单的处理。
- 数据转换和定义schema 用于满足分析需求。
Hadoop是以HDFS为核心存储,以MapReduce(简称MR)为基本计算模型的批量数据处理基础设施;
围绕HDFS和MR,产生了一系列的组件,不断完善整个大数据平台的数据处理能力,例如面向在线KV操作的HBase、面向SQL的HIVE、面向工作流的PIG等。同时,随着大家对于批处理的性能要求越来越高,新的计算模型不断被提出,产生了Tez、Spark、Presto、Flink等计算引擎,MR模型也逐渐进化成DAG模型;
批处理模式无论如何提升性能,也无法满足一些实时性要求高的处理场景,流式计算引擎应运而生,例如Storm、Spark Streaming、Flink等;
Lambda架构的核心理念是“流批一体”,整个数据流向自左向右流入平台。进入平台后一分为二,一部分走批处理模式,一部分走流式计算模式。无论哪种计算模式,最终的处理结果都通过统一服务层对应用提供,确保访问的一致性,底层到底是批或流对用户透明;
Lambda架构虽然解决了应用读取数据的统一性问题,但是“流批分离”的处理链路增大了研发的复杂性。因此,有人就提出能不能用一套系统来解决所有问题。目前比较流行的做法就是基于流计算来做。流计算天然的分布式特征,注定了他的扩展性更好。通过加大流计算的并发性,加大流式数据的“时间窗口”,来统一批处理与流式处理两种计算模式;
数据湖需要包括一系列的数据管理组件,包括:
- 数据接入;
- 数据搬迁;
- 数据治理;
- 数据质量管理;
- 资产目录;
- 访问控制;
- 任务管理;
- 任务编排;
- 元数据管理等
数据中台是指通过企业内外部多源异构的数据采集、治理、建模、分析,应用,使数据对内优化管理提高业务,对外可以数据合作价值释放,成为企业数据资产管理中枢。数据中台建立后,会形成数据API,为企业和客户提供高效各种数据服务
首先数据仓库的分层:
数据仓库为什么要分层:
- 把复杂问题简单化:将复杂的任务分解成多层来完成,每一层只处理简单的任务,方便定位问题;
- 减少重复开发:规范数据分层,通过中间层数据,能够减少极大的重复计算,增加一次计算结果的复用性;
- 隔离原始数据:不论是数据的异常还是数据的敏感性,使真实数据与统计数据解耦;
- 数据集市:是一种微型的数据仓库,更少的数据,一般是某个局部范围内的数据;
- 数据仓库:企业级,为整个企业提供决策手段;数据仓库是能够将多个数据源的数据经过ETL处理之后,按照一定的主题集成起来提供决策支持和联机分析应用的结构化数据环境;
表命名:
- ODS层命名:
ods_tableName
- DWD层命名:
dim_tableName/fact_tableName
- DWS层命名:
dws_tableName
- DWT层命名:
dwt_tableName
- ADS层命名:
ads_tableName
- 临时表命名:
xxx_tmp
- 用户行为表,以log为后缀
脚本命名:
- 数据源_to_目标_db/log.sh
- 用户行为脚本以log为后缀,业务数据以db为后缀;
范式可以立即为设计一张表的表结构,符合标准级别,即规范和要求
**优点:**降低数据的冗余性
**缺点:**获取数据时需要通过join拼接处最后的数据
目前主要范式:第一范式、第二范式、第三范式、巴斯-科德范式、第四范式、第五范式等
现阶段数据处理大致可以分为两类:联机事务处理(OLTP,On-line Transaction Processing)和联机分析处理(OLAP,On-line Analytical Processing)。OLTP是传统的关系型数据的主要应用,主要是基本的、日常的事务处理;OLAP是数据仓库的系统的主要应用,支持复杂的分析操作
关系模型严格遵守第三范式,从上图中可以看出较为松散、零碎,物理表数量多,但数据冗余程度低。关系模型主要应用在OLTP系统中,为了保证数据的一致性以及避免冗余,大部分业务系统的表遵循三分是
维度模型如上图,主要应用在OLAP系统中,通常以某一个事实表作为中心进行表的组织,主要面向业务,特征可能是数据冗余。通常采用维度模型建模,把相关的表整理成两种:事实表和维度表
在维度建模的基础上分为:星型模型、雪花模型、星座模型
星型模型是由事实表和多个维表组成;星型模型存取数据速度快,主要是针对各个维做了大量预处理,如按照维度进行预先的统计、分组合排序等,主要特点:
- 维表只和事实表关联,维表之间没有关联;
- 每个维表的主键为单列,且该主键放置在事实表中,作为两边连接的外键;
- 以事实表为核心,维表围绕核心呈星形分布;
雪花模型是对星型模型的扩展,它将星型模型的维表进一步层次化,原来的各个维表可能被扩展为小的事实表,形成一些局部的层次区域;雪花模式通过更多的连接引入了更多的复杂性。随着存储变得越来越廉价,大多数情况,一般不采用雪花模型
方法;雪花模型的有点是最大限度地减少数据存储量,以及把较小的维表联合在一起来改善查询性能。但是它增加了用户必须处理的表的数量,增加了某些查询的复杂性;
**雪花模型与星型模型主要区别:**在于维度的层级,标准的星型模型维度只有一层,而雪花模型可能会涉及多级
星座模型与前两种的区别是事实表的数量,星座模型是基于多个事实表。很多数据仓库都是有多个事实表的;星座模型与前两种模型并不冲突
星座还是雪花,取决与性能优先还是灵活更优先,整体来看,倾向为维度更少的星型模型,尤其是hadoop体系,减少join就是减少shuffle;但是也不是绝对的
维度表:一般是对事实的描述信息,每一张维表对应现实世界中的一个对象或者概念(可以认为是一个名词),例如用户、商品、日期、地区、类目等
维度表的特征:
- 维表的范围很宽,具有多个属性,列比较多;
- 跟事实表相比,行数相对较少;
- 内容相对固定
比如昨天早上张三在京东花费200元购买了一个皮包
。那么以购买为主题进行分析,可从这段信息中提取三个维度:时间维度(昨天早上)
,地点维度(京东),
商品维度(皮包)
。通常来说维度表信息比较固定,且数据量小
事实表表示对分析主题的度量,表中的每一行数据代表一个业务事件(比如下单、退款、支付等)。事实这个术语表示的是业务事件的度量值(可统计的次数、个数、件数、金额等)
比如昨天早上张三在京东花费200元购买了一个皮包
,200元就是事实信息。事实表包含了与各维度表相关联的外码,并通过JOIN方式与维度表关联。事实表的度量通常是数值类型,且记录数会不断增加,表规模迅速增长;
每个事实表的行包括:具有可加性的数值型的度量值、与维表相连接的外键、通常具有两个或两个以上的外键、外键之间表示维表之间的多对多的关系;
事实表的特征:
- 数据量非常的大;
- 内容相对的窄:列数较少(瘦高)
- 经常发生变化
事实表分类:
- 事务事实表:记录有关特定事件的事实(例如,销售事件,保存在原子的粒度,也称为原子事实表)一旦事务被提交,事实表数据被插入,数据不再进行更改;
- 周期快照事实表:记录给定时间点的事实(例如,月末的帐户详细信息、每月的销售额)
- 累积快照事实表:记录了给定时间点的汇总事实(例如,某产品的当月迄今总销售额),用于跟踪业务事实的变化,比如订单从下单开始、打包、运输、签收各个业务阶段的时间点数来跟踪订单生命周期
比如针对HDFS层的数据处理:
- 保持数据原貌不做任何改动,起到备份数据的作用;
- 数据采用压缩,减少磁盘存储空间;
- 创建分区表,防止后续的全表扫描;
DWD层需要构建维度模型,一般采用星型模型,呈现的状态一般是星座模型;维度建模一般按照四个步骤:选择业务过程 → 声明粒度 → 确认维度 → 确认事实
(1)选择业务过程
在业务系统中,挑选感兴趣的业务线,比如下单业务、支付业务、退款业务等,一条业务线对应一张事实表;
(2)声明粒度
数据粒度是指数据仓库的数据中保存数据的细化程度或综合程度的级别;
声明粒度意味着精确定义事实表中的一行数据表示什么,应该进可能选择最小粒度,以此来满足各种需求;
典型的粒度:
- 订单的中的每个商品项作为下单事实表中的一行,粒度为每次;
- 每周的订单次数作为一行,粒度为每周;
(3)确定维度
维度的主要作用是描述业务的事实,主要表示的是谁、何处、何时
等信息;
确定维度的原则:后续需求中是需要分析相关维度的指标;例如需要统计什么时间下的订单、哪个地区下的订单多、没哪个用户下的订单多。需要确定的维度就包括:时间维度、地区维度、用户维度等;
另外维度表需要根据维度建模中的星型模型原则进行维度退化,即将多张维度表合并为一张维度表;
(4)确定事实
事实指的是业务中的度量值(次数、个数、金额、件数);在DWD层中,以业务过程为建模驱动,基于每个具体业务过程的特点,构建最细粒度的明细层事实表。事实表可以适当当做宽表处理
DWD层是以业务为驱动的,DWS层、DWT层、ADS层都是以需求为驱动的,跟维度建模已没有关系;
针对DWD层在对数据进行清洗的时候,一般遵循以下原则:
- 数据唯一性校验:通过数据采集工具采集的数据存在重复的可能性;
- 数据完整性校验:采集的数据可能会出现缺失字段的情况,针对缺失字段的数据建议直接丢掉,如果可以确定是哪一列缺失也可以进行补全,可以用同一列上的前一个数据或者同一列上的后一个数据来填补
- 数据合法性校验-1:针对数字列中出现了null 或者 - 之类的异常值,全部替换成一个特殊值,列入 0 或者 -1,可以根据具体的业务场景而定;
- 数据合法性校验-2:针对部分字段需要校验数据的合法性,例如用户的年龄不能是负数等;
DWS宽表是站在不同维度的角度去看事实表的,比如按省份、用户、活动等
DWS层宽表包括:每日商品行为、每日会员行为等;
DWT层是统计各个主题对象的累积行为
-
需要建哪些表:和 DWS 层一样。以维度为基准,去关联对应多个事实表
-
宽表里面的字段:我们站在维度表的角度去看事实表,重点关注事实表度量值的累积值、事实表行为的首次和末次时间
对各大主题指标分别进行分析
针对订单表、订单商品表、流水表等表,数据比较多,如果使用全量的方式,会造成大量的数据冗余,浪费磁盘空间。一般这类表的同步都是增量的同步,每日采集新增的数据。
需要注意的是:如订单表,如果单纯的按照订单产生时间增刊采集数据,是有问题的,因为存在可能今天下单,明天才支付的情况,但是hive是不支持数据更新的,虽然mysql中的订单的状态改变了,但是hive的订单状态还是之前的状态;
一般针对这种问题,有以下解决方案:
- (1)每天全量导入订单数据,在项目初期是没有问题的,但是随着订单量的增长,每天导入大量的数据到HDFS中,这样会存在大量的数据冗余;
- (2)只保存当天的全量订单数据,在每次导入之前,删除前一天保存的全量订单数据,这种方式虽然不会造成数据冗余,但是无法查询订单的历史状态,只有当前的最新状态;
- (3)拉链表:这种方式在普通增量导入的基础上进行完善,把变化的数据也导入了进来,这样既不会造成大量的数据冗余,还可以查询订单的历史状态;
拉链表是针对数仓设计中表存储数据的方式,记录每条信息的生命周期,一旦一条记录的生命周期结束,就重新开始一条新的记录,并把当前日期放入生效开始日期,如果当前信息至今有效,在生效结束日期填入一个极大值(如9999-12-31)
下面是一张拉链表的初始数据:
用户id | 姓名 | 手机号码 | 开始日期 | 结束日期 |
---|---|---|---|---|
1 | 张无忌 | 13111111111 | 2021-01-01 | 2021-01-02 |
1 | 张无忌 | 13222222222 | 2021-01-02 | 2021-01-03 |
1 | 张三丰 | 13333333333 | 2021-01-03 | 9999-12-31 |
- 开始日期:表示该条记录的生命周期开始时间,t_end_date 表示该条记录的生命周期结束时间;
- 结束日期(9999-12-31):表示该条记录目前处于有效状态;
- 如果查询当前所有有效的记录,则
select * from user where 结束日期 = '9999-12-31'
- 查询历史:通过
生效开始日期 <= 某个日期 且 生效结束日期 >= 某个日期
能够得到某个时间的数据全量切片,比如要查询2021-01-01的历史快照,则select * from user where t_start_date <= '2021-01-01' and end_date >= '2021-01-01'
;
拉链表形成过程:
- (1)假设2021-01-01的用户全量表是初始的用户表:
user_id user_name 1 张三 2 李四 3 王五 - (2)初始的拉链表就等于最开始的2021-01-01的用户全量表
user_id user_name start_time end_time 1 张三 2021-01-01 9999-12-31 2 李四 2021-01-01 9999-12-31 3 王五 2021-01-01 9999-12-31 - (3)第二天1月2日用户全量表(用户2发生状态改变,用户4、5增加)
user_id user_name 1 张三 2 李小四 3 王五 4 赵六 5 田七 - (4)根据用户表的
创建时间和操作时间
得到用户变化表
user_id user_name 2 李小四 4 赵六 5 田七 - (5)用户变化表与之前的拉链表合并得到
user_id user_name start_time end_time 1 张三 2021-01-01 9999-12-31 2 李四 2021-01-01 2021-01-02 2 李小四 2021-01-02 9999-12-31 3 王五 2021-01-01 9999-12-31 4 赵六 2021-01-02 9999-12-31 5 前期 2021-01-02 9999-12-31
针对订单表,如果希望使用拉链表的方式实现数据采集,需要既采集增量,还要采集订单状态变化了的数据;订单表的订单状态字段有这么几个:未支付、已支付、未发货、已发货;
假设系统是2021-03-1开始运营的
那么到3月1日结束订单表的数据如下:
订单ID | 创建时间 | 更新时间 | 订单状态 | 释义 |
---|---|---|---|---|
001 | 2021-03-01 | null | 未支付 | 新增 |
002 | 2021-03-01 | 2021-03-01 | 已支付 | 新增 |
3月2日结束订单表的数据
订单ID | 创建时间 | 更新时间 | 订单状态 | 释义 |
---|---|---|---|---|
001 | 2021-03-01 | 2021-03-02 |
已支付 | 修改 |
002 | 2021-03-01 | 2021-03-01 | 已支付 | 新增 |
003 |
2021-03-02 |
2021-03-02 |
已支付 |
新增 |
基于订单表的这些数据如何制作拉链表呢?
基本思路如下:
-
(1)首先针对3月1号订单数据构建初始拉链表,拉链表中需要一个 start_time(数据生效开始时间)和end_time(数据生效结束时间),默认情况下 start_time 等于表的创建时间, end_time 初始为一个无限大的日期:9999-12-31
将3月1日的订单数据导入拉链表中,此时拉链表的数据如下
订单ID 订单状态 start_time end_time 001 未支付 2021-03-01 9999-12-31 002 已支付 2021-03-01 9999-13-31 -
(2)在3月2日的时候,需要将订单表中发生了变化的数据和新增的订单数据整合到之前的拉链表中,此时需要
先创建一个每日更新表
,将每日新增
和变化了的数据保存到里面; -
(3)基于
拉链表
和每日更新表
进行left jioin
,根据订单id进行关联,如果可以关联上,说明这个订单的状态发生了改变,然后将订单状态发生了变化的数据 end_time 改为 2021-03-01(当天日期 -1 天),然后再和每日更新表的数据执行 union all 操作,将结果重新insert到拉链表中; -
(4)最终拉链表的数据如下:
订单id 订单状态 start_time nd_time 001 未支付 2021-03-01 2021-03-01
002 已支付 2021-03-01 9999-12-31 001
已支付
2021-03-02
9999-12-31
003
已支付
2021-03-02
9999-12-31
代码实现过程
参考sql:拉链表制作过程
数据会发生变化,但是大部分数据都是不变的,即缓慢变化维;
比如用户信息会发生变化,但是每天变化的比例都不高,如果数据量达到一定规模,按照每日全量的方式保存效率很低,比如1亿用户*365天;
假设存放了5年的拉链数据,那么这张表势必会比较大,当查询的时候性能就比较低了,可以尝试以下思路来解决:
- 尝试对 start_time 和 end_time 做索引,这样可以提高一些性能;
- 保留部分历史数据,可以在一张表里面存放全量的拉链表数据,再对外暴露一张只提供近3个月数据的拉链表;
Flume、logstash、Filebeat、Sqoop
- Flume、logstash 从性能消耗上差不多,都是基于JVM执行的,都是重量级的组件,支持多种数据源和目的地;
- FileBeat 是一个只支持文件数据采集的工具,一个轻量级的组件,性能消耗比价低,其是基于Go语言开发的;
HDFS、MySQL
Hive、Spark、Flink
实时数据merge:https://tech.meituan.com/2018/12/06/binlog-dw.html