目录
1.1 什么是数据仓库
1.2 操作型系统与分析型系统
1.2.1 操作型系统
1.2.2 分析型系统
1.2.3 操作型系统和分析型系统对比
1.3 抽取-转换-装载
1.3.1 数据抽取
1.3.2 数据转换
1.3.3 数据装载
1.3.4 开发ETL系统的方法
1.4 数据仓库架构
1.4.1 基本架构
1.4.2 主要数据仓库架构
1.4.3 操作数据存储
1.5 实时数据仓库
1.5.1 流式处理
1.5.2 实时计算
1. Lambda架构
2. Kappa架构
1.5.3 实时数据仓库解决方案
小结
对于每一种技术,先要理解相关的概念和它之所以出现的原因,这对于我们继续深入学习其技术细节大有裨益。实时数据仓库首先是个数据仓库,只是它优先考虑数据的时效性问题。因此本篇开头将介绍业界公认的数据仓库定义,它和操作型数据库应用的区别,以及为什么我们需要数据仓库。 在对数据仓库的概念有了基本的认识后,有必要单独说明一下ETL这个最重要的过程,然后向读者介绍四种常见的数据仓库架构。本篇最后描述实时数据仓库的产生背景、特定需求和使用场景,并列举一些常见的实时数据仓库技术架构。
1.1 什么是数据仓库
数据仓库的概念可以追溯到十九世纪八十年代,当时IBM的研究人员开发出了“商业数据仓库”。本质上,数据仓库试图提供一种从操作型系统到决策支持环境的数据流架构模型。数据仓库概念的提出,是为了解决和这个数据流相关的各种问题,主要是解决多重数据复制带来的高成本问题。在没有数据仓库的时代,需要大量的冗余数据来支撑多个决策支持环境。在大组织里,多个决策支持环境独立运作是典型的情况。尽管每个环境服务于不同的用户,但这些环境经常需要大量相同的数据。处理过程收集、清洗、整合来自多个数据源的数据,并为每个决策支持环境做部分数据复制。数据源通常是早已存在的操作型系统,很多是遗留系统。此外,当一个新的决策支持环境形成时,操作型系统的数据经常被再次复用。用户访问这些处理后的数据。 数据仓库之父Bill Inmon在1991年出版的《Building the Data Warehouse》一书中首次提出了被广为认可的数据仓库定义。Inmon将数据仓库描述为一个面向主题的、集成的、随时间变化的、非易失的数据集合,用于支持管理者的决策过程。这个定义有些复杂并且难以理解,下面我们将它分解开来进行说明。
- 面向主题
传统的操作型系统是围绕机构的功能性应用进行组织的,而数据仓库是面向主题的。主题是一个抽象概念,简单地说就是与业务相关的数据的类别,每一个主题基本对应一个宏观的分析领域。数据仓库被设计成辅助人们分析数据。例如,一个公司要分析销售数据,就可以建立一个专注于销售的数据仓库,使用这个数据仓库,就可以回答类似于“去年谁是我们这款产品的最佳用户”这样的问题。这个场景下的销售,就是一个数据主题,而这种通过划分主题定义数据仓库的能力,就使得数据仓库是面向主题的。主题域是对某个主题进行分析后确定的主题的边界,如客户、销售、产品都是主题域的例子。
- 集成
集成的概念与面向主题是密切相关的。还用销售的例子,假设公司有多条产品线和多种产品销售渠道,而每个产品线都有自己独立的销售数据库。此时要想从公司层面整体分析销售数据,必须将多个分散的数据源统一成一致的、无歧义的数据格式后,再放置到数据仓库中。因此数据仓库必须能够解决诸如产品命名冲突、计量单位不一致等等问题。当完成了这些数据整合工作后,该数据仓库就可称为是集成的。
- 随时间变化
为了发现业务变化的趋势、存在的问题、或者新的机会,需要分析大量的历史数据。这与联机事务处理(Online Transactional Processin,OLTP)系统形成鲜明的对比。联机事务处理反应的是当前时间点的数据情况,要求高性能、高并发和极短的响应时间,出于这样的需求考虑,联机事务处理系统中一般都将数据依照活跃程度分级,把历史数据迁移到归档数据库中。而数据仓库关注的是数据随时间变化的情况,并且能反映在过去某个时间点的数据是怎样的。换句话说,数据仓库中的数据是反映了某一历史时间点的数据快照,这也就是术语“随时间变化”的含义。当然,任何一个存储结构都不可能无限扩展,数据也不可能只入不出地永久驻留在数据仓库中,它在数据仓库中也有自己的生命周期。到了一定时候,数据会从数据仓库中移除。移除的方式可能是,将细节数据汇总后删除,将老的数据转储到大容量介质后删除,直接物理删除等。
- 非易失
非易失指的是,一旦进入到数据仓库中,数据就不应该再有改变。操作型环境中的数据一般都会频繁更新,而在数据仓库环境中一般并不进行数据更新。当改变的操作型数据进入数据仓库时会产生新的记录,这样就保留了数据变化的历史轨迹。也就是说,数据仓库中的数据基本是静态的。这是一个不难理解的逻辑概念。数据仓库的目的就是要根据曾经发生的事件进行分析,如果数据是可修改的,将使历史分析变得没有意义。
除了以上四个特性外,数据仓库还有一个非常重要的概念就是粒度。粒度问题遍布于数据仓库体系结构的各个部分。粒度是指数据的细节或汇总程度,细节程度越高,粒度级别越低。例如,单个事务是低粒度级别,而全部一个月事务的汇总就是高粒度级别。
数据粒度一直是数据仓库设计需要重点思考的问题。在早期的操作型系统中,当细节数据被更新时,几乎总是将其存放在最低粒度级别上,而在传统数据仓库环境中,通常都不这样做。例如,如果数据被装载进数据仓库的频率是每天一次,那么一天之内的数据更新将被忽略。
粒度之所以是数据仓库环境的关键设计问题,是因为它极大地影响数据仓库的数据量和可以进行的查询类型。粒度级别越低,数据量越大,查询的细节程度越高,查询范围越广泛,反之亦然。
大多数情况下,数据会以很低的粒度级别进入数据仓库,如日志类型的数据或点击流数据,此时应该对数据进行编辑、过滤和汇总,使其适应数据仓库环境的粒度级别。如果得到的数据粒度级别比数据仓库的高,那将意味着在数据存入数据仓库前,开发人员必须花费大量设计和资源来对数据进行拆分。
现在你应该已经熟悉了数据仓库的概念,那么数据仓库里的数据从哪里来呢?通常数据仓库的数据来自各个业务应用系统。业务系统中的数据形式多种多样,可能是Oracle、MySQL、SQLServer等关系数据库里的结构化数据,可能是文本、CSV等平面文件或Word、Excel文档中的非结构化数据,还可能是HTML、XML等自描述的半结构化数据。这些业务数据经过一系列的数据抽取、转换、清洗,最终以一种统一的格式装载进数据仓库。数据仓库里的数据作为分析用的数据源,提供给后面的即席查询、分析系统、数据集市、报表系统、数据挖掘系统等。
从以上描述可以看到,从存储的角度看,数据仓库里的数据实际上已经存在于业务应用系统中,那么为什么不能直接操作业务系统中的数据用于分析,而要使用数据仓库呢?实际上在数据仓库技术出现前,有很多数据分析的先驱者已经发现,简单的“直接访问”方式很难良好工作,这样做的失败案例数不胜数。下面列举一些直接访问业务系统无法工作的原因:
- 某些业务数据由于安全或其它因素不能直接访问。
- 业务系统的版本变更很频繁,每次变更都需要重写分析系统并重新测试。
- 很难建立和维护汇总数据来源于多个业务系统版本的报表。
- 业务系统的列名通常是硬编码,有时仅仅是无意义的字符串,这让编写分析系统更加困难。
- 业务系统的数据格式,如日期、数字的格式不统一。
- 业务系统的表结构为事务处理性能而优化,有时并不适合查询与分析。
- 没有适当的方式将有价值的数据合并进特定应用的数据库。
- 没有适当的位置存储元数据。
- 用户需要看到的显示数据字段,有时在数据库中并不存在。
- 通常事务处理的优先级比分析系统高,所以如果分析系统和事务处理运行在同一硬件之上,分析系统往往性能很差。
- 有误用业务数据的风险。
- 极有可能影响业务系统的性能。
尽管需要增加软硬件的投入,但建立独立数据仓库与直接访问业务数据相比,无论是成本还是带来的好处,这样做都是值得的。随着处理器和存储成本的逐年降低,数据仓库方案的优势更加明显,在经济上也更具可行性。
无论是建立数据仓库还要实施别的项目,都要从时间、成本、功能等几个角度权衡比较,认真研究一下是否真正需要一个数据仓库,这是一个很好的问题。当你的组织很小,人数很少,业务单一,数据量也不大,可能你真的不需要建立数据仓库。毕竟要想成功建立一个数据仓库并使其发挥应有的作用还是很有难度的,需要大量的人、财、物力,并且即便花费很大的代价完成了数据仓库的建设,在较短一段时间内也不易显现出价值。在没有专家介入而仅凭组织自身力量建立数据仓库时,还要冒相当大的失败风险。但是,当你所在的组织有超过1000名员工,有几十个部门的时候,它所面临的挑战将是完全不同的。在这个充满竞争的时代,做出正确的决策对一个组织至关重要。而要做出最恰当的决策,仅依据对孤立维度的分析是不可能实现的。这时必须要考虑所有相关数据的可用性,而这个数据最好的来源就是一个设计良好的数据仓库。
假设一个超市连锁企业,在没有实现数据仓库的情况下,最终该企业会发现,要分析商品销售情况是非常困难的,比如哪些商品被售出,哪些没有被售出,什么时间销量上升,哪个年龄组的客户倾向于购买哪些特定商品等等这些问题都无从回答。而给出这些问题的正确答案正是一个具有吸引力的挑战。这只是第一步,必须要搞清楚一个特定商品到底适不适合18-25岁的人群,以决定该商品的销售策略。一旦从数据分析得出的结论是销售该商品的价值在降低,那么必须实施后面的步骤分析在哪里出了问题,并采取相应的措施加以改进。
在辅助战略决策层面,数据仓库的重要性更加凸显。作为一个企业的经营者或管理者,他必须对某些问题给出答案,以获得超越竞争对手的额外优势。回答这些问题对于基本的业务运营可能不是必须的,但对于企业的生存发展却必不可少。下面是一些常见问题的例子:
- 如何把公司的市场份额提升5%?
- 哪些产品的市场表现不令人满意?
- 哪些代理商需要销售政策的帮助?
- 提供给客户的服务质量如何?哪些需要改进?
回答这些战略性问题的关键一环就是数据仓库。就拿“提供给客户的服务质量如何?”这一问题来说,这是管理者最为关心的问题之一。我们可以把这一问题分解成许多具体的小问题,比如第一个问题是,在过去半年中,收到过多少用户反馈?可以在数据仓库上发出对应的查询,并对查询结果进行分析。之所以能够这样做,是因为数据仓库中含有每一条用户反馈信息。
你可能已经想到了,第二个问题自然就是,在这些用户反馈当中,给出“非常满意”、“一般”,“不满意”的人数分别有多少?下面的问题就是客户所强调的需要改进的地方和广受批评的地方是哪些?这在数据仓库的用户反馈信息中也有一列来表示,它也能从一个侧面反映出客户关心的问题是哪些。以上这三个问题的答案联合在一起,就可以得出客户服务满意度的结论,并且准确定位哪些地方急需改进。
下面简单总结一下使用数据仓库的好处:
- 将多个数据源集成到单一数据存储,因此可以使用单一数据查询引擎展示数据。
- 缓解在事务处理数据库上因执行大查询而产生的资源竞争问题。
- 维护历史数据。
- 通过对多个源系统的数据整合,使得在整个企业的角度存在统一的中心视图。
- 通过提供一致的编码和描述,减少或修正坏数据问题,提高数据质量。
- 一致性地表示组织信息。
- 提供所有数据的单一通用数据模型,而不用关心数据源。
- 重构数据,使数据对业务用户更有意义。
- 向复杂分析查询交付优秀的查询性能,同时不影响操作型系统。
- 开发决策型查询更简单。
1.2 操作型系统与分析型系统
上一小节已经多次提及操作型系统和分析型系统,本小节将详细阐述它们的概念及差异。在一个大组织中,往往都有两种类型的系统,操作型和分析型,而这两种系统大都以数据库作为数据管理、组织和操作的工具。操作型系统完成组织的核心业务,例如下订单、更新库存、记录支付信息等等。这些系统是事务型的,核心目标是尽可能快地处理事务,同时维护数据的一致性和完整性。而分析型系统的主要作用是通过数据分析评估组织的业务经营状况,并进一步辅助决策。
1.2.1 操作型系统
相信从事过IT或相关工作的读者对操作型系统都不会感到陌生。几乎所有的互联网线上系统、MIS、OA等等都属于这类系统的应用。操作型系统是一类专门用于管理面向事务的应用的信息系统。“事务”一词在这里存在一些歧义,有些人理解事务是一个计算机或数据库的术语,另一些人所理解的事务是指业务或商业交易,这里使用前一种语义。那么什么是数据库技术中的事务呢?这是首先需要明确的概念。
事务是工作于数据库管理系统(或类似系统)中的一个逻辑单元,该逻辑单元中的操作被以一种独立于其它事务的可靠方式所处理。事务一般代表着数据改变,它提供“all-or-nothing”操作,就是说事务中的一系列操作要么完全执行,要么完全不执行。在数据库中使用事务主要出于两个目的:
- 保证工作单元的可靠性。当数据库系统异常宕机时,其中执行的操作或者已经完成或者只有部分完成,很多没有完成的操作此时处于一种模糊状态。在这种情况下,数据库系统必须能够恢复到数据一致的正常状态。
- 提供并发访问数据库的多个程序间的隔离。如果没有这种隔离,程序得到的结果很可能是错误的。
根据事务的定义,引申出事务具有原子性、一致性、隔离性、持久性的特点,也就是数据库领域中常说的事务的ACID特性。
- 原子性(Atomicity)
指的是事务中的一系列操作或全执行或不执行,这些操作是不可再分的。原子性可以防止数据被部分修改。银行账号间转账是一个事务原子性的例子。简单地说,从A账号向B账号转账有两步操作:A账号提取,B账号存入。这两个操作以原子性事务执行,使数据库保持一致的状态,即使这两个操作的任何一步失败了,总的金额数不会减少也不会增加。
- 一致性(Consistency)
数据库系统中的一致性是指任何数据库事务只能以允许的方式修改数据。任何数据库写操作必须遵循既有的规则,包括约束、级联、触发器以及它们的任意组合。一致性并不保证应用程序逻辑的正确性,但它能够保证不会因为程序错误而使数据库产生违反规则的结果。
- 隔离性(Isolation)
在数据库系统中,隔离性决定了其他用户所能看到的事务完整性程度。例如,一个用户正在生成一个采购订单,并且已经生成了订单主记录,但还没有生成订单条目明细记录。此时订单主记录能否被其他并发用户看到呢?这就是由隔离级别决定的。数据库系统中,按照由低到高一般有读非提交、读提交、可重复读、串行化等几种隔离级。数据库系统并不一定实现所有的隔离级别,如Oracle数据库只实现了读提交和串行化,而MySQL、PostgreSQL数据库则提供这全部四种隔离级别。
隔离级越低,多用户并发访问数据的能力越高,但同时也会增加脏读、丢失更新等并发操作的负面影响。相反,高隔离级降低了并发影响,但需要使用更多的系统资源,也增加了事务被阻塞的可能性。
- 持久性(Durability)
数据库系统的持久性保证已经提交的事务是永久保存的。例如,如果一个机票预订报告显示一个座位已经订出,那么即使系统崩溃,被订了的座位也会一直保持被订出的状态。持久性可以通过在事务提交时将事务日志刷新至永久性存储介质来实现。
了解了事务的基本概念后,我们再来看操作型系统就比较容易理解了。操作型系统通常是高并发、低延迟的系统,具有大量检索、插入、更新操作,事务数量大,但每个事务影响的数据量相对较小。这样的系统很适合在线应用,它们有成千上万的用户同时使用,并要求能够立即响应用户请求。操作型系统常被整合到面向服务的架构(Service-Oriented Architecture,SOA)和Web服务里。对操作型系统应用的主要要求是高可用、高速度、高并发、可恢复和保证数据一致性,在各种互联网应用层出不穷的今天,这些系统要求是显而易见的。
操作型系统的数据库操作 在数据库使用上,操作型系统常用的操作是增、改、查,并且通常是插入与更新密集型的,同时会对数据库进行大量并发查询,而删除操作相对较少。操作型系统一般都直接在数据库上修改数据,没有中间过渡区。
操作型系统的数据库设计 操作型系统的特征是大量短的事务,并强调快速处理查询。每秒查询数(Queries-per-second,QPS)是操作型系统的一个有效度量指标。针对以上这些特点,数据库设计一定要满足系统的要求。
在数据库逻辑设计上,操作型系统的应用数据库大都使用规范化设计方法,通常要满足第三范式。这是因为规范化设计能最大限度的消除数据冗余,因而提供更快更高效地方式执行数据库写操作。关于规范化设计概念及其相关内容,会在下一篇“数据仓库设计基础”中做详细说明。
在数据库物理设计上,应该依据系统所使用的数据库管理系统的具体特点,做出相应的设计,毕竟每种数据库管理系统在实现细节上还是存在很大差异的。下面就以Oracle数据库为例,简要说明在设计操作型系统数据库时应该考虑的问题。
- 调整回滚段。回滚段是数据库的一部分,其中记录着最终被回滚的事务的行为。这些回滚段信息可以提供读一致性、回滚事务和数据库恢复。
- 合理使用聚簇。聚簇是一种数据库模式,其中包含有共用一列或多列的多个表。数据库中的聚簇表用于提高连接操作的性能。
- 适当调整数据块大小。数据块大小应该是操作系统块大小的倍数,并且设置上限以避免不必要的I/O。
- 设置缓冲区高速缓存大小。合理的缓存大小能够有效避免不必要的磁盘I/O。
- 动态分配表空间。
- 合理划分数据库分区。分区最大的作用在于可用性和可维护性,使得数据维护期间保持事务处理的性能。
- SQL语句优化。有效利用数据库管理系统的优化器,使用最佳的数据访问路径。
- 避免过度使用索引。大量的数据修改会给索引维护带来压力,从而对整个系统的性能产生负面影响。
以上所讲的操作型系统都是以数据库系统为核心,而数据库系统为了保持ACID特性,本质上是单一集中式系统。在当今这个信息爆炸的时代,集中式数据库往往已无法支撑业务的需要(从某订票网站和某电商网站的超大瞬时并发量来看,这已是一个不争的事实)。这就给操作型系统带来新的挑战。分布式事务、去中心化、CAP与最终一致性等一系列新的理论和技术为解决系统扩展问题应运而生。这是一个很大的话题,要想说清楚需要很多的扩展知识和大量篇幅,故这里只是点到为止,不做展开。
1.2.2 分析型系统
在计算机领域,分析型系统是一种快速回答多维分析查询的实现方式。它也是更广泛范畴的所谓商业智能的一部分(商业智能还包含数据库、报表系统、数据挖掘、数据可视化等研究方向)。分析型系统的典型应用包括销售业务分析报告,市场管理报告,业务过程管理(Business Process Management,BPM),预算和预测,金融分析报告及其类似的应用。
分析型系统的数据库操作 在数据库层面,分析型系统操作被定义成少量的事务,复杂的查询,处理归档和历史数据。这些数据很少被修改,从数据库抽取数据是最多的操作,也是识别这种系统的关键特征。分析型数据库基本上都是读操作。
分析型系统的数据库设计 分析型系统的特征是相对少量的事务,但查询通常非常复杂并且会包含聚合计算,例如今年和去年同时期的数据对比、百分比变化趋势等等。分析型数据库中的数据一般来自于一个企业级数据仓库,是整合过的历史数据。对于分析型系统,吞吐量是一个有效的性能度量指标。
在数据库逻辑设计上,分析型数据库使用多维数据模型,通常是设计成星型模式或雪花模式。关于多维数据模型的概念及其相关内容,会在下一篇“数据仓库设计基础”中做详细说明。
在数据库物理设计上,依然以Oracle数据库为例,简要说明在设计分析型系统数据库时应该考虑的一些问题。
- 表分区。可以独立定义表分区的物理存储属性,将不同分区的数据存放到多个物理文件上,这样做一方面可以分散I/O,另一方面,当数据量非常大时,方便数据维护。再有利用分区消除查询数据时,不用扫描整张表,从而提高查询性能。
- 位图索引。当查询条件中包含低基数(不同值很少,例如性别)的列,尤其是包含有这些列上的or、and或not这样的逻辑运算时,或者从有大量行的表中返回大量的行时,应考虑位图索引。
- 物化视图。物化视图物理存储查询所定义的数据,能够自动增量刷新数据,并且可以利用查询重写特性极大地提高查询速度,是分析型系统常用的技术。
- 并行化操作。可以在查询大量数据时执行并行化操作,这样会导致多个服务器进程为同一个查询语句工作,使该查询得以快速完成,但是会耗费更多的资源。
随着数据的大量积累和大数据时代的到来,人们对于数据分析的依赖性越来越强,而分析型系统也随之越来越显示出重要。举一个简单的例子,在一家医院中,保存有20年的非常完整的病人信息。医院领导想看到关于最常见的疾病、成功治愈率、实习医生的实习天数等很多相关数据的详细报告。为了满足这个需求,应用分析型系统查询医院信息数据仓库,并通过复杂查询得到结果,然后将报告提交给领导做进一步分析。
1.2.3 操作型系统和分析型系统对比
操作型系统和分析型系统是两种不同种类的信息系统。它们都与数据库技术相关,数据库提供方法支持这两种系统的功能。操作型系统和分析型系统以完全不同的方式使用数据库,不仅如此,分析型系统更加注重数据分析和报表,而操作型系统的目标是一个伴有大量数据改变的事务优化系统。
对于学习数据科学及其相关技术的读者,了解这两种信息处理方式的区别至关重要。这也是理解商业智能、数据挖掘、数据仓库、数据模型、ETL处理和大数据等系统的基础。
通过前面对两种系统的描述,我们可以对比它们的很多方面。表1-1总结了两种系统的主要区别。后面我们进一步讨论每一个容易产生疑惑的对比项,以帮助你能够理解它。
对比项 | 操作型系统 | 分析型系统 |
---|---|---|
数据源 | 应用的操作信息,一般是最原始的数据 | 历史的、归档的数据,一般来源于数据仓库 |
侧重点 | 数据更新 | 信息的检索或报表 |
应用 | 管理系统、交易系统、在线应用等 | 报表系统、多维分析、决策支持系统等 |
用户 | 终端用户、普通雇员 | 管理人员、市场人员、数据分析师 |
任务 | 业务操作 | 数据分析 |
数据更新 | 插入、更新、删除数据,要求快速执行,立即返回结果 | 大量数据装载,花费时间很长 |
数据模型 | 实体关系模型 | 多维数据模型 |
设计方法 | 规范化设计,大量的表和表之间的关系 | 星型模式或雪花模式,少量的表 |
备份 | 定期执行全量或增量备份,不允许数据丢失 | 简单备份,数据可以重新装载 |
数据的时间范围 | 从天到年 | 几年或几十年 |
查询 | 简单查询,快速返回查询结果 | 复杂查询,执行聚合或汇总操作 |
速度 | 快,大表上需要建索引 | 相对较慢,需要更多的索引 |
所需空间 | 小,只存储操作数据 | 大,需要存储大量历史数据 |
表1-1 操作型系统和分析型系统对比
首先两种系统的侧重点不同。操作型系统更适合对已有数据的更新,所以是日常处理工作或在线系统的选择。相反,分析型系统提供在大量存储数据上的分析能力,所以这类系统更适合报表类应用。分析型系统通常是查询历史数据,这有助于得到更准确的分析报告。
其次因为这两种系统的目标完全不同,所以为了得到更好的性能,使用的数据模型和设计方法也不同。操作型系统数据库通常使用规范化设计,为普通查询和数据修改提供更好的性能。另一方面,分析型数据库具有典型的数据仓库组织形式。
基于这两个主要的不同点,我们可以推导出两种系统其它方面的区别。操作型系统上的查询更小,而分析型系统上执行的查询要复杂得多。所以通常操作型系统会比分析型系统快很多。
操作型系统的数据会持续更新,并且更新会立即生效。而分析型系统的数据更新,是由预定义的处理作业同时装载大量的数据集合,并且在装载前需要做数据转换,因此整个数据更新过程需要较长的执行时间。
由于操作型系统要做到绝对的数据安全和可用性,所以需要实施复杂的备份系统。基本的全量备份和增量备份都是必须要做的。而分析型系统只需要偶尔执行数据备份即可,这一方面是因为这类系统一般不需要保持持续运行,另一方面数据还可以从操作型系统重复装载。
两种系统的空间需求显然都依赖于它们所存储的数据量。分析型系统要存储大量的历史数据,因此需要更多的存储空间。
1.3 抽取-转换-装载
前面已经多次提到了ETL一词,它是Extract、Transform、Load三个英文单词首字母的简写,中文意为抽取、转换、装载。ETL是建立数据仓库最重要的处理过程,也是最体现工作量的环节,一般会占到整个数据仓库项目工作量的一半以上。
- 抽取——从操作型数据源获取数据。
- 转换——转换数据,使之转变为适用于查询和分析的形式和结构。
- 装载——将转换后的数据导入到最终的目标数据仓库。
建立一个数据仓库,就是要把来自于多个异构的源系统的数据集成在一起,放置于一个集中的位置用于数据分析。如果一开始这些源系统数据就是兼容的当然最好,但情况往往不是这样。ETL系统的工作就是要把异构的数据转换成同构的。如果没有ETL,不可能对异构的数据进行程序化的分析。
1.3.1 数据抽取
抽取操作从源系统获取数据给后续的数据仓库环境使用。这是ETL处理的第一步,也是最重要的一步。数据被成功抽取后,才可以进行转换并装载到数据仓库中。能否正确地获取数据直接关系到后面步骤的成败。数据仓库典型的源系统是事务处理应用,例如,一个销售分析数据仓库的源系统之一,可能是一个订单录入系统,其中包含当前销售订单相关操作的全部记录。
设计和建立数据抽取过程,在ETL处理乃至整个数据仓库处理过程中,一般是较为耗时的任务。源系统很可能非常复杂并且缺少相应的文档,因此只是决定需要抽取哪些数据可能就已经非常困难了。通常数据都不是只抽取一次,而是需要以一定的时间间隔反复抽取,通过这样的方式把数据的所有变化提供给数据仓库,并保持数据的及时性。除此之外,源系统一般不允许外部系统对它进行修改,也不允许外部系统对它的性能和可用性产生影响,数据仓库的抽取过程要能适应这样的需求。如果已经明确了需要抽取的数据,下一步就该考虑从源系统抽取数据的方法了。
数据抽取方法 对抽取方法的选择高度依赖于源系统和目标数据仓库环境的业务需要。一般情况下,不可能因为需要提升数据抽取的性能,而在源系统中添加额外的逻辑,也不能增加这些源系统的工作负载。有时,用户甚至都不允许增加任何“开箱即用”的外部应用系统,这叫做对源系统具有侵入性。下面分别从逻辑和物理两方面介绍数据抽取方法。
逻辑抽取 有两种逻辑抽取类型:全量抽取和增量抽取。
全量抽取 源系统的数据全部被抽取。因为这种抽取类型影响源系统上当前所有有效的数据,所以不需要跟踪自上次成功抽取以来的数据变化。源系统只需要原样提供现有的数据而不需要附加的逻辑信息(比如时间戳等)。一个全表导出的数据文件或者一个查询源表所有数据的SQL语句,都是全量抽取的例子。
增量抽取 只抽取某个事件发生的特定时间点之后的数据。通过该事件发生的时间顺序能够反映数据的历史变化,它可能是最后一次成功抽取,也可能是一个复杂的业务事件,如最后一次财务结算等。必须能够标识出特定时间点之后所有的数据变化。这些发生变化的数据可以由源系统自身来提供,例如能够反映数据最后发生变化的时间戳列,或者是一个原始事务处理之外的,只用于跟踪数据变化的变更日志表。大多数情况下,使用后者意味着需要在源系统上增加抽取逻辑。
在许多数据仓库中,抽取过程不含任何变化数据捕获技术。取而代之的是,把源系统中的整个表抽取到数据仓库过渡区,然后用这个表的数据和上次从源系统抽取得到的表数据作比对,从而找出发生变化的数据。虽然这种方法不会对源系统造成很大的影响,但显然需要考虑给数据仓库处理增加的负担,尤其是当数据量很大的时候。
物理抽取 依赖于选择的逻辑抽取方法,还有能够对源系统所做的操作和所受的限制,存在两种物理数据抽取机制:直接从源系统联机抽取或者间接从一个脱机结构抽取数据。这个脱机结构有可能已经存在,也可能得需要由抽取程序生成。
联机抽取 数据直接从源系统抽取。抽取进程或者直连源系统数据库访问它们的数据表,或者连接到一个存储快照日志或变更记录表的中间层系统。注意这个中间层系统并不需要必须和源系统物理分离。
脱机抽取 数据不从源系统直接抽取,而是从一个源系统以外的过渡区抽取。过渡区可能已经存在(例如数据库备份文件、关系数据库系统的重做日志、归档日志等),或者抽取程序自己建立。应该考虑以下的存储结构:
- 数据库备份文件。一般需要数据还原操作才能使用。
- 备用数据库。如Oracle的DataGuard和MySQL的数据复制等技术。
- 平面文件。数据定义成普通格式,关于源对象的附加信息(列名、数据类型等等)需要另外处理。
- 导出文件。关系数据库大都自带数据导出功能,如Oracle的exp/expdp程序和MySQL的mysqldump程序,都可以用于生成导出数据文件。
- 重做日志和归档日志。每种数据库系统都有自己的日志格式和解析工具。
变化数据捕获 抽取处理需要重点考虑增量抽取,也被称为变化数据捕获,简称CDC。假设一个数据仓库系统,在每天夜里的业务低峰时间从操作型源系统抽取数据,那么增量抽取只需要过去24小时内发生变化的数据。变化数据捕获也是建立实时数据仓库的关键技术。
当你能够识别并获得最近发生变化的数据时,抽取及其后面的转换、装载操作显然都会变得更高效,因为要处理的数据量会小很多。遗憾的是,很多源系统很难识别出最近变化的数据,或者必须侵入源系统才能做到。变化数据捕获是数据抽取中典型的技术挑战。
常用的变化数据捕获方法有时间戳、快照、触发器和日志四种。相信熟悉数据库的读者对这些方法都不会陌生。时间戳方法需要源系统有相应的数据列表示最后的数据变化。快照方法可以使用数据库系统自带的机制实现,如Oracle的物化视图技术,也可以自己实现相关逻辑,但会比较复杂。触发器是关系数据库系统具有的特性,源表上建立的触发器会在对该表执行insert、update、delete等语句时被触发,触发器中的逻辑用于捕获数据的变化。日志可以使用应用日志或系统日志,这种方式对源系统不具有侵入性,但需要额外的日志解析工作。关于这四种方案的特点,将会在本专题后面的“数据抽取”部分具体说明。
1.3.2 数据转换
数据从操作型源系统获取后,需要进行多种转换操作。如统一数据类型、处理拼写错误、消除数据歧义、解析为标准格式等等。数据转换通常是最复杂的部分,也是ETL开发中用时最长的一步。数据转换的范围极广,从单纯的数据类型转化到极为复杂的数据清洗技术。
在数据转换阶段,为了能够最终将数据装载到数据仓库中,需要在已经抽取来的数据上应用一系列的规则和函数。有些数据可能不需要转换就能直接导入到数据仓库。
数据转换一个最重要的功能是清洗数据,目的是只有“合规”的数据才能进入目标数据仓库。这步操作在不同系统间交互和通信时尤其必要,例如,一个系统的字符集在另一个系统中可能是无效的。另一方面,由于某些业务和技术的需要,也需要进行多种数据转换,例如下面的情况:
- 只装载特定的数据列。例如,某列为空的数据不装载。
- 统一数据编码。例如,性别字段,有些系统使用的是1和0,有些是‘M’和‘F’,有些是‘男’和‘女’,统一成‘M’和‘F’。
- 自由值编码。例如,将‘Male’改成‘M’。
- 预计算。例如,产品单价 * 购买数量 = 金额。
- 基于某些规则重新排序以提高查询性能。
- 合并多个数据源的数据并去重。
- 预聚合。例如,汇总销售数据。
- 行列转置。
- 将一列转为多列。例如,某列存储的数据是以逗号作为分隔符的字符串,将其分割成多列的单个值。
- 合并重复列。
- 预连接。例如,查询多个关联表的数据。
- 数据验证。针对验证的结果采取不同的处理,通过验证的数据交给装载步骤,验证失败的数据或直接丢弃,或记录下来做进一步检查。
1.3.3 数据装载
ETL的最后步骤是把转换后的数据装载进目标数据仓库。这步操作需要重点考虑两个问题,一是数据装载的效率问题,二是一旦装载过程中途失败了,如何再次重复执行装载过程。
即使经过了转换、过滤和清洗,去掉了部分噪声数据,但需要装载的数据量还是很大的。执行一次数据装载可能需要几个小时的时间,同时需要占用大量的系统资源。要提高装载的效率,加快装载速度,可以从以下几方面入手。首先保证足够的系统资源。数据仓库存储的都是海量数据,所以要配置高性能的服务器,并且要独占资源,不要与别的系统共用。在进行数据装载时,要禁用数据库约束(唯一性、非空性,检查约束等)和索引,当装载过程完全结束后,再启用这些约束,重建索引,这种方法会很大地提高装载速度。在数据仓库环境中,一般不使用数据库来保证数据的参考完整性,即不使用数据库的外键约束,它应该由ETL工具或程序来维护。
数据装载过程可能由于多种原因而失败,比如装载过程中某些源表和目标表的结构不一致而导致失败,而这时已经有部分表装载成功了。在数据量很大的情况下,如何能在重新执行装载过程时只装载失败的部分是一个不小的挑战。对于这种情况,实现可重复装载的关键是要记录下失败点,并在装载程序中处理相关的逻辑。还有一种情况,就是装载成功后,数据又发生了改变(比如有些滞后的数据在ETL执行完才进入系统,就会带来数据的更新或新增),这时需要重新再执行一遍装载过程,已经正确装载的数据可以被覆盖,但相同数据不能重复新增。简单的实现方式是先删除再插入,或者用replace into、merge into等类似功能的操作。
装载到数据仓库里的数据,经过汇总、聚合等处理后交付给多维立方体或数据可视化、仪表盘等报表工具、BI工具做进一步的数据分析。
1.3.4 开发ETL系统的方法
ETL系统一般都会从多个应用系统整合数据,典型的情况是这些应用系统运行在不同的软硬件平台上,由不同的厂商所支持,各个系统的开发团队也是彼此独立的,随之而来的数据多样性增加了ETL系统的复杂性。
开发一个ETL系统,常用的方式是使用数据库标准的SQL及其程序化语言,如Oracle的PL/SQL和MySQL的存储过程、用户自定义函数(UDF)等。还可以使用Kettle这样的ETL工具,这些工具都提供多种数据库连接器和多种文件格式的处理能力,并且对ETL处理进行了优化。使用工具的最大好处是减少编程工作量,提高工作效率。如果遇到特殊需求或特别复杂的情况,可能还是需要使用Shell、Java、Python等编程语言开发自己的应用程序。
ETL过程要面对大量的数据,因此需要较长的处理时间。为了提高ETL的效率,通常这三步操作会并行执行。当数据被抽取时,转换进程同时处理已经收到的数据。一旦某些数据被转换过程处理完,装载进程就会将这些数据导入目标数据仓库,而不会等到前一步工作执行完才开始。
1.4 数据仓库架构
前面三个小节介绍了数据仓库、操作型系统、分析型系统、ETL等概念,也指出了分析型系统的数据源一般来自数据仓库,而数据仓库的数据来自于操作型系统。本小节从技术角度讨论数据仓库的组成和架构。
1.4.1 基本架构
“架构”是什么?这个问题从来就没有一个准确的答案。在软件行业,一种被普遍接受的架构定义是指系统的一个或多个结构。结构中包括软件的构建(构建是指软件的设计与实现),构建的外部可以看到属性以及它们之间的相互关系。这里参考此定义,把数据仓库架构理解成构成数据仓库的组件及其之间的关系,那么就有了下面的数据仓库架构图。
图1-1 数据仓库架构
下面详细说明图1-1中的各个组件及其所起的作用。
图中显示的整个数据仓库环境包括操作型系统和数据仓库系统两大部分。操作型系统的数据由各种形式的业务数据组成,这其中可能有关系数据库、TXT或CSV文件、HTML或XML文档,还可能存在外部系统的数据,比如网络爬虫抓取来的互联网数据等,数据可能是结构化、半结构化、非结构化的。这些数据经过抽取、转换和装载(ETL)过程进入数据仓库系统。
这里把ETL过程分成了抽取和转换装载两个部分。抽取过程负责从操作型系统获取数据,该过程一般不做数据聚合和汇总,但是会按照主题进行集成,物理上是将操作型系统的数据全量或增量复制到数据仓库系统的RDS中。转换、装载过程将对数据进行清洗、过滤、汇总、统一格式化等一系列转换操作,使数据转为适合查询的格式,然后装载进数据仓库系统的TDS中。传统数据仓库的基本模式是用一些过程将操作型系统的数据抽取到文件,然后另一些过程将这些文件转化成MySQL或Oracle这样的关系数据库的记录。最后,第三部分过程负责把数据导入进数据仓库。
RDS(RAW DATA STORES)是原始数据存储的意思。将原始数据保存到数据仓库里是个不错的想法。ETL过程的bug或系统中的其它错误是不可避免的,保留原始数据使得追踪并修改这些错误成为可能。有时数据仓库的用户会有查询细节数据的需求,这些细节数据的粒度与操作型系统的相同。有了RDS,这种需求就很容易实现,用户可以查询RDS里的数据而不必影响业务系统的正常运行。这里的RDS实际上是起到了操作型数据存储(Operational Data Store,ODS)的作用,关于ODS相关内容本小节后面会有详细论述。
TDS(TRANSFORMED DATA STORES)意为转换后的数据存储。这是真正的数据仓库中的数据。大量的用户会在经过转换的数据集上处理他们的日常查询。如果前面的工作做得好,这些数据将被以保证最重要的和最频繁的查询能够快速执行的方式构建。
这里的原始数据存储和转换后的数据存储是逻辑概念,它们可能物理存储在一起,也可能分开。当原始数据存储和转换后的数据存储物理上分开时,它们不必使用同样的软硬件。传统数据仓库中,原始数据存储通常是本地文件系统,原始数据被组织进相应的目录中,这些目录是基于数据从哪里抽取或何时抽取建立(例如以日期作为文件或目录名称的一部分);转换后的数据存储一般是某种关系数据库。
自动化调度组件的作用是自动定期重复执行ETL过程。不同角色的数据仓库用户对数据的更新频率要求也会有所不同,财务主管需要每月的营收汇总报告,而销售人员想看到每天的产品销售数据。作为通用的需求,所有数据仓库系统都应该能够建立周期性自动执行的工作流作业。传统数据仓库一般利用操作系统自带的调度功能(如Linux的cron或Windows的计划任务)实现作业自动执行。
数据目录有时也被称为元数据存储,它可以提供一份数据仓库中数据的清单。用户通过它应该可以快速解决这些问题:什么类型的数据被存储在哪里,数据集的构建有何区别,数据最后的访问或更新时间等。此外还可以通过数据目录感知数据是如何被操作和转换的。一个好的数据目录是让用户体验到系统易用性的关键。
查询引擎组件负责实际执行用户查询。传统数据仓库中,它可能是存储转换后数据的Oracle、MySQL等关系数据库系统内置的查询引擎,还可能是以固定时间间隔向其导入数据的OLAP立方体,如Essbase cube。
用户界面指的是最终用户所使用的接口程序。可能是一个GUI软件,如BI套件的中的客户端软件,也可能就是一个浏览器。
1.4.2 主要数据仓库架构
在数据仓库技术演化过程中,产生了几种主要的架构方法,包括数据集市架构、Inmon企业信息工厂架构、Kimball数据仓库架构和混合型数据仓库架构。
数据集市架构 数据集市是按主题域组织的数据集合,用于支持部门级的决策。有两种类型的数据集市:独立数据集市和从属数据集市。
独立数据集市集中于部门所关心的单一主题域,数据以部门为基础部署,无需考虑企业级别的信息共享与集成。例如,制造部门、人力资源部门和其它部门都各自有他们自己的数据集市。独立数据集市从一个主题域或一个部门的多个事务系统获取数据,用以支持特定部门的业务分析需要。一个独立数据集市的设计既可以使用实体关系模型也可以使用多维模型。数据分析或商业智能工具直接从数据集市查询数据,并将查询结果显示给用户。一个典型的独立数据集市架构如图1-2所示。
图1-2 独立数据集市架构
因为一个部门的业务相对于整个企业要简单,数据量也小得多,所以建立部门的独立数据集市具有周期短、见效快的特点。如果从企业整体的视角来观察这些数据集市,你会看到每个部门使用不同的技术,建立不同的ETL过程,处理不同的事务系统,而在多个独立的数据集市之间还会存在数据的交叉与重叠,甚至会有数据不一致的情况。从业务角度看,当部门的分析需求扩展,或者需要分析跨部门或跨主题域的数据时,独立数据市场会显得力不从心。而当数据存在歧义,比如同一个产品,在A部门和B部门的定义不同时,将无法在部门间进行信息比较。
另外一种数据集市是从属数据集市。如Bill Inmon所说,从属数据集市的数据来源于数据仓库。数据仓库里的数据经过整合、重构、汇总后传递给从属数据集市。从属数据集市的架构如图1-3所示。
图1-3 从属数据集市架构
建立从属数据集市的好处主要有:
- 性能:当数据仓库的查询性能出现问题,可以考虑建立几个从属数据集市,将查询从数据仓库移出到数据集市。
- 安全:每个部门可以完全控制他们自己的数据。
- 数据一致:因为每个数据集市的数据来源都是同一个数据仓库,有效消除了数据不一致的情况。
Inmon企业信息工厂架构 Inmon企业信息工厂架构如图1-4所示,我们来看图中的组件是如何协同工作的。
图1-4 Inmon企业信息工厂架构
- 应用系统:这些应用是组织中的操作型系统,用来支撑业务。它们收集业务处理过程中产生的销售、市场、材料、物流等数据,并将数据以多种形式进行存储。操作型系统也叫源系统,为数据仓库提供数据。
- ETL过程:ETL过程从操作型系统抽取数据,然后将数据转换成一种标准形式,最终将转换后的数据装载到企业级数据仓库中。ETL是周期性运行的批处理过程。
- 企业级数据仓库:是该架构中的核心组件。正如Inmon数据仓库所定义的,企业级数据仓库是一个细节数据的集成资源库。其中的数据以最低粒度级别被捕获,存储在满足三范式设计的关系数据库中。
- 部门级数据集市:是面向主题数据的部门级视图,数据从企业级数据仓库获取。数据在进入部门数据集市时可能进行聚合。数据集市使用多维模型设计,用于数据分析。重要的一点是,所有的报表工具、BI工具或其它数据分析应用都从数据集市查询数据,而不是直接查询企业级数据仓库。
Kimball 数据仓库架构 Kimball 数据仓库架构如图1-5所示。
图1-5 Kimball数据仓库架构
对比上一张图可以看到,Kimball与Inmon两种架构的主要区别在于核心数据仓库的设计和建立。Kimball的数据仓库包含高粒度的企业数据,使用多维模型设计,这也意味着数据仓库由星型模式的维度表和事实表构成。分析系统或报表工具可以直接访问多维数据仓库里的数据。在此架构中的数据集市也与Inmon中的不同。这里的数据集市是一个逻辑概念,只是多维数据仓库中的主题域划分,并没有自己的物理存储,也可以说是虚拟的数据集市。
混合型数据仓库架构 混合型数据仓库架构如图1-6所示。
图1-6 混合型数据仓库架构
所谓的混合型结构,指的是在一个数据仓库环境中,联合使用Inmon和Kimball两种架构。从架构图可以看到,这种架构将Inmon方法中的数据集市部分替换成了一个多维数据仓库,而数据集市则是多维数据仓库上的逻辑视图。使用这种架构的好处是,既可以利用规范化设计消除数据冗余,保证数据的粒度足够细,又可以利用多维结构更灵活地在企业级实现报表和分析。
1.4.3 操作数据存储
操作数据存储又称为ODS,是Operational Data Store的简写,其定义是这样的:一个面向主题的、集成的、可变的、当前的细节数据集合,用于支持企业对于即时性的、操作性的、集成的全体信息的需求。对比1.1节中数据仓库的定义不难看出,操作型数据存储在某些方面具有类似于数据仓库的特点,但在另一些方面又显著不同于数据仓库。
- 像数据仓库一样,是面向主题的。
- 像数据仓库一样,其数据是完全集成的。
- 数据是当前的,这与数据仓库存储历史数据的性质明显不同。ODS具有最少的历史数据(一般是30天到60天),而尽可能接近实时地展示数据的状态。
- 数据是可更新的,这是与静态数据仓库又一个很大的区别。ODS就如同一个事务处理系统,当新的数据流进ODS时,受其影响的字段被新信息覆盖。
- 数据几乎完全是细节数据,仅具有少量的动态聚集或汇总数据。通常将ODS设计成包含事务级的数据,即包含该主题域中最低粒度级别的数据。
- 在数据仓库中,几乎没有针对其本身的报表,报表均放到数据集市中完成;与此不同,在ODS中,业务用户频繁地直接访问ODS。
在一个数据仓库环境中,ODS具有如下几个作用:
- 充当业务系统与数据仓库之间的过渡区。数据仓库的数据来源复杂,可能分布在不同的数据库,不同的地理位置,不同的应用系统之中,而且由于数据形式的多样性,数据转换的规则往往极为复杂。如果直接从业务系统抽取数据并做转换,不可避免地会对业务系统造成影响。而ODS中存放的数据从数据结构、数据粒度、数据之间的逻辑关系上都与业务系统基本保持一致,因此抽取过程只需简单的数据复制而基本不再需要做数据转换,大大降低了复杂性,同时最小化对业务系统的侵入。
- 转移部分业务系统细节查询的功能。某些原来由业务系统产生的报表、细节数据的查询能够在ODS中进行,从而降低业务系统的查询压力。
- 完成数据仓库中不能完成的一些功能。数据仓库用户有时会要求查询最低粒度级别的细节数据,而数据仓库中存储的数据一般都是聚合或汇总过的数据,并不存储每笔交易产生的细节数据。这时就需要把细节数据查询的功能转移到ODS来完成,而且ODS的数据模型按照面向主题的方式组织的,可以方便地支持多维分析。即数据仓库从宏观角度满足企业的决策支持要求,而ODS层则从微观角度反映细节交易数据或者低粒度的数据查询要求。
1.5 实时数据仓库
上一节介绍的架构已经有几十年的历史,经过了长时间的验证和打磨,已被证明是适合于构建企业级数据仓库的经典解决方案。但是,近年来随着业务领域的不断拓展,尤其像互联网、无线终端APP等行业应用的激增,产生的数据量呈指数级增长,对海量数据的处理需求也提出了新的挑战。具体到数据仓库,尤其突出的一点是人们对数据分析的实时性要求越来越高,从而衍生出所谓实时数据仓库的概念。为解决数据实时性问题,也涌现出一批相关的技术。
本节将解释什么是流式处理,然后讨论实时计算的基本概念和适用场景,它们都与实时数据仓库的实施密不可分。最后从技术实现的角度介绍几种流行的实时数据仓库架构。
1.5.1 流式处理
人们对数据流并不陌生,数据从业务系统产生,经过一系列转换进入数据仓库,再进入分析系统提供报表、仪表盘展现分析结果,最终经过数据挖掘和机器学习以辅助决策,整个过程就形成了一个数据流。当然除了直觉以外,严格的定义更有意义。数据流是无边界数据集的抽象表示。无边界意味着无限和持续增长,无边界数据集之所以是无限的,是因为随着时间的推移,新的记录会不断加入进来。这个定义已经被包括Google和Amazon在内的大部分公司所采纳。
除无边界外,数据流还有其它一些属性:有序、不可变、可重放。数据的产生总有先后顺序,这是数据流与数据库表的不同点之一,数据库表里的记录是无序的。数据一旦产生就不能被改变。假设你熟悉数据库的二进制日志(binlog)、预写日志(Write Ahead Log,WAL)和重做日志(redo log)的概念,那么就会知道,如果往数据库表插入一条记录,然后将其删除,表里就不会再有这条记录,但日志里包含了插入和删除两个事务。可重放是数据流非常有价值的一个属性。对于大多数业务来说,重放发生在几天前(甚至几个月前)的原始数据流是一个很重的需求。可能是为了尝试使用新的分析方法纠正过去的错误,或是为了进行审计。
知道什么是数据流以后,是时候了解“流式处理”的真正含义了。流式处理是指实时处理一个或多个数据流。流式处理是一种编程范式,就像请求与响应范式和批处理范式那样。下面对这三种范式进行比较,以便更好地理解如何在软件架构中应用流式处理。
请求与响应 这是延迟最小的一种范式,响应时间处于亚毫秒到毫秒之间,而且响应时间一般非常稳定。这种处理方式一般是阻塞的,应用程序向处理系统发出请求,然后等待响应。在数据库领域,这种范式就是联机事务处理(OLTP)。
批处理 这种范式具有高延迟和高吞吐量的特点。处理系统按照预定的时间启动处理进程,比如每天凌晨两点开始启动,每小时启动一次等。它读取所有的输入数据(从上一次执行之后的所有可用数据),输出结果,然后等待下一次启动。处理时间从几分钟到几小时不等,并且用户从结果里读到的都是滞后数据。在数据库领域,它们就是传统的数据仓库或商业智能系统。它们每天装载巨大批次的数据,并生成报表,用户在下一次装载数据之前看到的都是相同的报表。从规模上来说,这种范式既高效又经济。但在近几年,为了能够更及时、高效地做出决策,业务要求在更短的时间内能够提供可用数据。这就给那些为探索规模经济而开发却无法提供低延迟报表的系统带来了巨大的压力。
流式处理 这种范式介于上述两种之间。某些业务不要求毫秒级的响应,不过也接受不了要等到第二天才知道结果。大部分业务流程都是持续进行的,只要业务报告保持更新,业务产品线更够保持响应,那么业务流程就可以进行下去,而无需等待特定的响应,也不要求在几毫秒内得到响应。
与前面介绍的数据仓库相比,重点是流式处理的整个处理过程必须是持续的。一个在每天凌晨两点启动的流程,从流里读取500条记录,生成结果,然后结束,这样的流程不是流式处理。对数据仓库来说,也许从粒度的角度理解流式处理更容易。回想1.1节中提及的粒度概念,如果能将数据更新保持在最低的事务粒度级别上,实际就是做了数据仓库的流式处理,也即所谓的实时数据仓库。实时数据处理没有调度开销,只涉及任务监控。
1.5.2 实时计算
要做到实时读写数据,必须采用有别于传统数据仓库的实现技术,实时计算的概念和技术引擎应运而生,它们是成功创建实时数据仓库的前提条件。实时计算一般针对海量数据处理,并且要求响应时间为秒级。由于大数据兴起之初,以Hadoop为代表的分布式框架并没有给出实时计算解决方案,随后便出现了Storm、Spark Streaming、Flink等实时计算框架,而Kafka、ES的兴起使得实时计算领域的技术越来越完善,而随着物联网、机器学习等技术的推广,实时流式计算将在这些领域得到充分应用。实时计算是流式处理的一种具体实现方式,因此必然具有无限数据、无界数据处理、低延迟等特征。
现在大数据应用比较火爆的领域,比如推荐系统在实践之初受技术所限,可能要一分钟、一小时、甚至更久才能对用户进行推荐,这远远不能满足需要,我们需要更快的完成对数据的处理,而不是进行离线的批处理。实时计算的应用场景主要包括实时智能推荐、实时欺诈检测、舆情分析、物联网、客服系统、实时机器学习等。
在某些场景中,数据的价值随着时间的推移而逐渐减少。所以在传统数据仓库的基础上,逐渐对数据的实时性提出了更高的要求。于是随之诞生了实时数据仓库,并且衍生出了两种主流技术架构:Lambda和Kappa。
1. Lambda架构
Lambda架构如图1-7所示,虚线上面表示数据逻辑处理流程,下面是一组具体实现组件。
图
1-7 Lambda架构
数据从底层的数据源开始,经过Kafka、Flume等数据组件进行收集,然后分成两条线进行计算:一条线是进入流式计算平台(例如 Storm、Flink或者SparkStreaming),去计算实时的一些指标;另一条线进入批量数据处理离线计算平台(例如Mapreduce、Hive,Spark SQL),去计算T 1的相关业务指标,这些指标通常需要隔日才见。
总体来说,Lambda架构就是为了计算一些实时指标,在原来离线数据仓库的基础上增加了一个实时计算的链路,并对数据源做流式改造,即把数据发送到消息队列,实时计算去订阅消息队列,直接完成指标增量的计算,推送到下游的数据服务中去,由数据服务层完成离线、实时结果的合并。
Lambda属于较早的一种架构方式,早期的流处理不如现在这样成熟,在准确性、扩展性和容错性上,流处理层无法直接取代批处理层,只能给用户提供一个近似结果,还不能为用户提供一个一致准确的结果。因此在Lambda架构中出现了批处理和流处理并存的现象。
在Lambda架构中,每层都有自己所肩负的任务。批处理层使用可处理大量数据的分布式处理系统预先计算结果。它通过处理所有的已有历史数据来实现数据的准确性。这意味着它是基于完整的数据集来重新计算的,能够修复任何错误,然后更新现有的数据视图。输出通常存储在只读数据库中,更新则采用全量替换方式,完全取代现有的预先计算好的视图。流处理层通过提供最新数据的实时视图来最小化延迟。流处理层所生成的数据视图可能不如批处理层最终生成的视图那样准确或完整,但它们几乎在收到数据后立即可用。而当同样的数据在批处理层处理完成后,在速度层的数据就可以被替代掉了。
Lambda架构经历多年的发展,其优点是稳定,对于实时计算部分的计算成本可控,批量处理可以用晚上的时间来整体批量计算,这样把实时计算和离线计算高峰分开,这种架构支撑了数据行业的早期发展,但是它也有一些致命缺点,并在当今时代越来越不适应数据分析业务的需求。
Lambda架构的缺点如下:
- 使用两套大数据处理引擎:维护两个复杂的分布式系统,成本非常高。
- 批量计算在计算窗口内无法完成:当数据量越来越大,经常发现夜间只有4、5个小时的时间窗口,已经无法完成白天20多个小时累计的数据,保证早上准时出数据已成为每个大数据团队头疼的问题。
- 数据源变化都要重新开发,开发周期长:每次需求变更后,业务逻辑的变化都需要针对ETL和Streaming做开发修改,整体开发周期很长,业务反应不够迅速。
- 资源占用增多:同样的逻辑计算两次,整体资源占用会增多(多出实时计算这部分)。
导致Lambda 架构的缺点根本原因是要同时维护两套系统:批处理层和速度层。我们已经知道,在架构中加入批处理层是因为从批处理层得到的结果具有高准确性,而加入速度层是因为它在处理大规模数据时具有低延时性。那我们能不能改进其中某一层的架构,让它具有另外一层架构的特性呢?例如,改进批处理层的系统让它具有更低的延迟,又或者是改进速度层的系统,让它产生的数据视图更具准确性和更加接近历史数据呢?另外一种在大规模数据处理中常用的架构——Kappa,便是在这样的思考下诞生的。
2. Kappa架构
Kappa架构可以被认为是Lambda架构的简化版,只是去除掉了Lambda架构中的离线批处理部分,如图1-8所示。
图
1-8 Kappa架构
这种架构只关注流式计算,数据以流的方式被采集,实时计算引擎将计算结果放入数据服务层以供查询。Kappa架构的兴起主要有两个原因:
- 消息队列(如Kafka)支持数据持久化,可以保存更长时间的历史数据,以替代Lambda架构中批处理层数据仓库部分。流处理引擎以一个更早的时间作为起点开始消费,起到了批处理的作用。
- 流处理引擎解(如Flink)决了事件乱序下计算结果的准确性问题。
Kappa架构相对更简单,实时性更好,所需的计算资源远小于Lambda架构,最大的问题是流式重新处理历史的吞吐能力会低于批处理,但这个可以通过增加计算资源来弥补。随着实时处理的需求在不断增长,更多的企业开始使用Kappa架构,但这不意味着Kappa架构能够取代Lambda架构。Lambda和Kappa架构都有各自的适用领域,对于流处理与批处理分析流程比较统一,且允许一定的容错,用Kappa比较合适,少量关键指标,例如交易金额、业绩统计等使用Lambda架构进行批量计算,增加一次校对过程。还有一些比较复杂的场景,批处理与流处理产生不同的结果,如使用不同的机器学习模型、专家系统,或者实时计算难以处理的复杂计算,可能更适合Lambda架构。
1.5.3 实时数据仓库解决方案
从传统的经验来讲,数据仓库有一个很重要的功能是记录数据变化历史。通常,数据仓库都希望从业务上线的第一天开始有数据,然后一直记录到现在。但实时处理技术,又是强调当前处理状态的一门技术,所以当这两个相对对立的方案重叠在一起的时候,它注定不是用来解决一个比较广泛问题的方案。于是,我们把实时数据仓库建设的目的定位为解决由于传统数据仓库数据时效性低解决不了的问题。
实时数据仓库也引入了类似于离线数据仓库的分层理念,主要是为了提高模型的复用率,同时兼顾易用性、一致性以及计算成本。通常离线数据仓库采用空间换取时间的方式,所以层级划分比较多从而提高数据计算效率。实时数据仓库的分层架构在设计上考虑到时效性问题,分层设计尽量精简,避免数据在流转过程中造成的不必要的延迟响应,并降低中间流程出错的可能性。实时数据仓库分层架构如图1-9所示。
图1-9 实时数据仓库分层架构
- ODS层:以Kafka为支撑,将所有需要实时处理的相关数据放到Kafka队列中来实现贴源数据层。这一层是数据输入层,主要是埋点、流量、日志等消息数据的接入。
- DWD层(Data Warehouse Detail):实时计算订阅业务数据消息队列,然后通过数据清洗、多数据源连接、流式数据与离线维度信息等的组合,将一些相同粒度的业务系统、维表中的维度属性全部关联到一起,增加数据易用性和复用性,得到最终的实时明细数据。
- DIM层(Dimension):存放用于关联查询的维度信息,可以根据数据现状来选择存储介质,例如使用HBase或者MySQL。在实时ETL、实时统计,或者特征加工时需要进行流数据和静态维表数据关联处理,这一层非必须的。
- DWS层(Data WareHouse Service):轻度汇总层是为了便于面向即席查询(Ad-Hoc Query)或者实时OLAP分析构建的轻度汇总结果集合,适合数据维度、指标信息比较多的情况。为了方便根据自定义条件的快速筛选和指标聚合,推荐使用MPP类型数据库进行存储。此层可视场景情况决定是否构建。
- APP层:面向实时数据场景需求构建的高度汇总层,可以根据不同的数据应用场景决定使用存储介质或者引擎。APP层已经脱离了数据仓库,这里虽然作为一个独立分层,但实际APP层的数据已经分布存储在各种介质中供使用。
图1-10显示了一个简化的、落地的、基于MySQL、Canal、Kafka、Greenplum构建的实时数据仓库架构。本专题后面讨论的实践部分都基于此架构进行设计开发。
图1-10 基于MySQL、Canal、Kafka、Greenplum的实时数据仓库架构
真实的数据仓库项目中会涉及多种数据源,不同数据源产生的数据质量可能差别很大,数据库中的格式化数据可能直接导入大数据存储系统,而日志或爬虫产生的数据就需要进行大量的清洗、转化处理才能有效使用。几乎在所有领域的业务数据源中,关系数据库都占有绝对比重,而其中MySQL毋庸置疑是当今最流行的关系数据库系统。本专题将MySQL作为唯一数据源,一是出于简化目的,因为后面的实践均给出代码级别的实操,不可能面面俱到。二是MySQL具有典型性,搞定MySQL的数据采集就可以解决实际应用中的一大部分问题。
Canal Server从MySQL从库产生的binlog(开启log_slave_updates)抽取增量数据变更日志,这样做有两个好处。首先最重要的,它不会影响线上业务,因为Canal Server只是在从库创建一个Binlog Dump线程,对MySQL Server的影响微乎其微。其次,从库可以随时启停复制,这样可以很容易为下游组件确定一个增量数据同步起点,在进行首次全量数据同步时就可以有效利用这点实现。
Canal Server作为数据生产者将记录数据变化的binlog作为消息传递给Kafka。Kafka一方面可以将消息持久化存储,避免数据丢失,另一方面充当数据入仓前的缓冲区。Canal Adapter作为数据消费者从Kafka接收消息,然后将数据写入Greenplum。
数据进入Greenplum后,就可以利用它提供的UDF功能,执行复杂的ETL过程,使用RULE功能进行一些自动的、实时的、对用户透明的维度表和事实表数据装载。Greenplum是一种成熟的MPP架构的分布式数据库,提供了丰富全面的功能,并且性能优良,比较适合作为实时数据仓库的存储、数据处理和数据查询。作为数据库管理系统,还可以利用Greenplum统一管理元数据。
1-10所示架构具有门槛低、上手易、实施快的特点,整个构建过程只需要适当安装配置相关软件,再利用SQL即可完成,不需要其它任何编程工作。当然从来没有完美的架构,只有适合的解决方案。本架构明显的一个局限是只能处理MySQL一个数据源,而且始终以数据库提供的功能为核心。如果涉及非常复杂的数据处理逻辑,可能引入类似Flink的实时计算引擎,并在其上开发自己的应用程序是更好的选择。
小结
- 数据仓库是一个面向主题的、集成的、随时间变化的、非易失的数据集合,用于支持管理者的决策过程。
- 数据仓库中的粒度是指数据的细节或汇总程度,细节程度越高,粒度级别越低。
- 数据仓库的数据来自各个业务应用系统。
- 很多因素导致直接访问业务系统无法进行全局数据分析的工作,这也是需要一个数据仓库的原因所在。
- 操作型系统是一类专门用于管理面向事务的应用信息系统,而分析型系统是一种快速回答多维分析查询的实现方式,两者在很多方面存在差异。
- 构成数据仓库系统的主要组成部分有数据源、ODS、中心数据仓库、分析查询引擎、ETL、元数据管理和自动化调度。
- 主要的数据仓库架构有独立数据集市、从属数据集市、Inmon企业信息工厂、Kimball多维数据仓库、混合型数据仓库。
- ETL是建立数据仓库最重要的处理过程,也是最体现工作量的环节。
- 构建实时数据仓库的基础是流式处理与实时计算,Lambda和Kappa是两个实时计算架构。Lambda是早期架构,在传统离线批处理上增加了一条实时数据处理链路。Kappa架构是Lambda架构的简化版,只保留了Lambda中的实时处理部分。
- 实时数据仓库也引入了类似于离线数据仓库的分层理念,但更注重时效性,分层越少越好,减少分层也是为了减少中间流程出错的可能。