<b>1.2数据平台</b>
<b></b>
数据平台是存放分析数据的平台,也是支持大多数数据分析和数据挖掘应用的底层平台,它使用了统一的数据清洗与处理规则,因而可以保证从基础平台上输出的数据内容是一致的。
传统的数据平台基本等同于大家熟悉的“数据仓库”,但互联网浪潮让人们对数据采集、存储和应用提出了越来越高的要求,传统数据仓库平台独力难支,因此“现代化”的数据平台是多种数据库产品的融合。图1-3是一个精简化的现代数据平台架构图。
图1-3 数据平台架构示意图
现代的数据平台融合了传统数据仓库、大数据平台、mpp数据库、nosql数据库等多种数据产品,这些数据库产品之间互为补充,组成统一的数据平台。
从传统的关系型数据库开始,数据库产品逐渐细分,这些细分产品在特定场景中比传统的关系型数据库表现出了更好的性能。图1-4展示了一些主流的数据库产品,注意到有很多数据库产品是“跨界”产品,例如,oracle同时属于关系型、分析型、操作型三类数据库。
图1-4 数据库产品图册
图1-4可为数据库选型提供参考。比如,如果希望寻找一款关系型数据库,既可以作为数据仓库底层数据库使用,也可以作为生产应用系统的数据库服务器(即操作型数据库)使用,那么从图1-4中可供选择的有oracle、db2、sql server等。
如果你希望从大量数据中发现隐含的关系网络,那么图1-4中的数据库是一个很好的选择,从图1-4的graph小框中可以发现有spark graphx、infinitegraph、neo4j等可供选择。
在一些大型企业的数据平台中,可能会出现teradata、greenplum、vertica的身影。这三种数据库属于mpp(massive parallel processing)数据库。虽然它们属于关系型数据库,但它们采用了一种与传统关系型数据库不同的存储方式,即列存储方式(oracle、db2、sql server等使用行存储方式)。这种列存储方式在面对大规模数据时,能表现出更好的效率,比如创建列索引、并行处理、集群操作等。
mpp数据库的问题在于其高昂的价格,这对于很多小型企业来说是一个“致命伤害”,目前国内使用该类产品的企业一般为大型企业。第1.2.4节会对mpp数据库做进一步介绍。
nosql数据库是伴随着互联网应用中崛起的新星。通过简化数据存取模式(相对rdbms而言),减少了数据库管理系统(dbms)的附加开销,专注于读/写效率的提升,非常适合对读取速度要求较高,且对数据不一致性有容忍的应用环境中。
归为newsql数据库之列的sql azure和mysql cluster是传统关系型数据库的云计算版本。目前该类数据库在国内企业的应用中尚不常见,但随着云计算的普及,预计国内一些大型企业有可能选用newsql数据库。
下面,我们对图1-3中组成数据平台的各主要模块分别进行介绍。
1.2.1 数据仓库平台
传统数据仓库平台,大多是基于关系型数据库搭建的。在windows服务器平台上,一般选用sql server、oracle、db2、mysql数据库中的一种或者两种混合搭建。
在linux服务器平台上,可选择的数据库有db2、oracle、mysql(虽然sql server正在准备发布linux版本)。数据仓库平台的建模过程已经有了完善的理论基础,并且目前市面上也有很多相关书籍,限于篇幅,本书不做详细介绍。数据仓库工程师可以参阅以下书籍。
《数据仓库》(《building the data warehouse》),机械工业出版社。
《数据库系统:数据库与数据仓库导论》(《database systems: introduction to databases and data warehouses》),机械工业出版社。
数据入口和出口
数据仓库本质上是解决大批量数据的入口和出口问题(简单来说,即数据写入数据仓库和从数据仓库中读取出来),并为大数据量的分析和应用提供基础支持。通常,在数据仓库设计时,虽然我们会尽其所能满足各种经典范式理论,但却忽略了一个简单且致命的问题:数据应该如何高效地进出数据仓库平台,并且对其他应用尽量透明呢?
很多数据仓库平台在运行初期看起来非常完美,但在持续运行一段时间后,各种问题逐渐显现出来,如数据库死锁、作业运行缓慢、etl过程卡死等。这种现象总是伴随着数据量的增长、数据仓库数据表的增加以及数据仓库访问用户的增加而出现,这是典型的数据入口和出口问题顽疾。
一个能够长期稳定提供“顺滑”数据服务的数据仓库才是一个“好”的数据仓库,而不仅仅是看这个数据仓库在设计时采用了什么数据库产品、满足了多少范式理论。
根据笔者的经验,“好”的数据仓库的入口和出口至少要关注两条规则,即数据的更新规则和存储规则。更新规则会影响数据的入口效率和出口效率,存储规则主要影响数据的出口效率。
(1)数据的更新规则
实际场景中,一个数据库中的数据表总是面临数据加载(load)的问题。比如一张交易明细表,每天凌晨需要将昨日的交易明细数据插入进去;而一张账户信息表,则需要将每天新增的账户信息插入及将状态改变的账户信息更新。
归纳起来,数据的更新规则分为两种:增量更新和全量更新。上面的交易明细表即是增量更新方式,每天将新增的数据插入;而账户信息表则可以采用全量更新的方式,每天将最新的账户信息表从数据源重新加载进来,并覆盖原有数据。图1-5展示了这两种更新方式。
图1-5 增量更新与全量更新
需要明确的是,在数据仓库中进行的数据更新一般是大数据量的数据更新,这与生产应用系统中的单条数据更新在处理方式上有很大的不同。在数据仓库场景中你将会面临百万(条)或者千万(条)级别的数据量,如果使用sql中的insert(或update)语句,则insert语句带来的事务管理、日志记录等会严重降低数据库性能,并且整个插入过程的耗时巨大,导致数据表长时间不可用。
通常在面临大批量数据更新时,正确的做法是使用批量导入命令进行批量导入操作,并尽可能避免update操作。我们将在第2章详细介绍批量导入命令。
但是使用批量导入命令面临的主要问题是“部分提交”的问题,因为数据库管理系统(dbms)通常不将批量导入命令置于dbms的事务控制范畴之中,这意味着整个批量导入过程并不验证数据库范式,也不记录操作日志,因此,如果批量导入中途出现异常,那么之前导入的数据将无法回滚。
比如,一个信用卡中心每天的交易明细数据有900万条,在往交易明细表中批量导入该批数据的时候,由于网络问题导致数据库连接中断,此时500万条记录已经导入交易明细表中且无法回滚,这就出现了“部分提交”问题。
这种情况是一个让人郁闷的问题,因为必须将导入的500万条数据删除(delete),然后重新运行批量导入命令。而从一个庞大的数据表中删除500万条数据简直是一种灾难,相信经历过的人肯定不想再来一次。
当全量更新时,除了“部分提交”的问题,还可能面临“数据断档”的问题。因为在全量更新时,首先需要将原表中的数据清空,之后再将新数据批量导入至清空后的表中。从数据清空到新数据全部导入,这个过程即为“数据断档”,因为在这个过程中数据表是无法对外提供服务的。
“部分提交”和“数据断档”是数据仓库运行过程中经常遇到的问题。一种可行的方案是增加中间表,即数据先完整导入中间表,然后再从中间表插入目标表,如图1-6所示。
图1-6 通过中间表进行批量加载
在图1-6中,原来交易明细表的增量更新拆分为以下两步。
1)清空“交易明细中间表”,并将t-1日交易数据全量更新至“交易明细中间表”中。
2)将“交易明细中间表”中的数据全部insert into到“交易明细表”中。
上述两个步骤中,假设步骤1)出现问题,则清空“交易明细中间表”后重新执行步骤1);而如果步骤2)出现问题,则数据库通过自动回滚会将已经insert的数据回滚掉,不会出现数据不完整的情况。
在图1-6中,对于全量更新的账户表,拆分为以下三步完成。
1)清空“账户中间表”,并将t-1日账户数据全量更新至“账户中间表”。
2)drop掉原账户表(t-2日账户数据)。
3)将“账户中间表”重命名为“账户表”,实现数据切换。
上述三个步骤,规避了“部分提交”的问题,同时在数据加载至中间表的过程中,原“账户信息表(t-2日数据)”仍可以正常提供数据服务(只不过数据并不是那么“新鲜”),因此解决了数据空档期的问题。
通过中间表,上述的增量更新、全量更新出现问题后,可以简单地通过重新执行解决,因此可以方便地通过程序自动完成上述过程。这种自动化过程规避了人工操作风险,降低了数据仓库维护成本,使数据仓库更加“顺滑”。第3章将详细介绍如何采用这种理念实现数据的增量更新和全量更新。
(2)数据的存储规则
数据仓库在运行初期一般都表现良好,这是因为运行初期的数据量、用户数、作业数量等均比较少,数据服务器本身的硬件性能可足以支撑这些业务。但是,随着数据量、用户数、作业数量的逐步增长,数据仓库的运行效率会逐渐降低。需要运维人员通过技术手段进行持续优化(如分区、创建索引、优化作业脚本等)。除此之外,数据的存储规则也是需要重点对待的事情。
对于一个每日增量更新的表,如上述交易明细表,其每天新增的数据量是非常惊人的,如某商业银行信用卡每天交易数据达860万条,这些数据每天导入到交易明细表中,每年的交易数据可以达到3tb左右,传统关系型数据库这种大表的检索效率是非常低的,更不用说在这种大表上进行更新、删除等操作了。
经过分析发现,数据仓库用户使用的交易明细数据90%集中在近三个月,而60%的作业仅使用近一个月的交易数据。因此,可以将交易明细数据分表存储,即一个月的交易数据存放在一个表中,并以月份为表名后缀,这样每个月的交易明细数据仅为250gb,通过适当的索引优化,传统关系型数据库在数tb级别仍然可以支持90%的业务场景。
图1-7中,原交易明细数据表按月拆分成小表,并使用yyyymm格式日期作为表名后缀。拆分成小表后,如果是访问最近一个月的交易明细数据,则直接访问表trx_dtl_yyyymm即可;而如果想访问最近三个月的交易数据,则通过视图v_trx_dtl_r3m访问即可。这样,在存储空间几乎不变的情况下,大幅度提高读取效率,从而使整个数据仓库的出口变得“顺滑”;另外,按月存储的交易明细表由于体积小,能更方便进行优化管理(如创建索引、迁移数据等),间接提高了数据仓库的入口效率。
图1-7 分表存储
拆分成小表后,由于表的命名规则固定(原表名+月份后缀),因此整个拆分表以及组合成视图的过程均可以通过脚本作业自动完成,提高了管理效率且节省了人力成本。
总体来说,在面对增量更新的“大表”时,数据的存储规则是“大表拆小表,小表组视图”,基本依据在于小表的访问效率高于大表的。
而对于全量更新的“大表”,也可以借鉴“大表拆小表”的方式。比如对于全量的账户信息表,可以根据账户状态将表分为多张小表,也可以根据账户号按一定的规则进行切分得到小表,总之需要根据实际情况,将大表切分成合适的小表,以提高访问效率。
尽管有诸多的优化方法,传统数据仓库在面临大数据量的时候,仍然无法规避存储空间和计算效率的问题,这要求我们在传统数据仓库解决方案之外寻求突破。
1.2.2 大数据平台
大数据的发展异常迅猛,各种开源或商用平台层出不穷,在选择大数据产品的时候,应该本着务实的原则,从实际情况出发选择真正需要的功能,毕竟技术的核心价值是帮助我们解决问题,一味追求新潮技术并不可取。
大数据平台的基础是分布式:分布式存储和分布式计算,它们分别用于解决单机数据库面临的两大困境,即数据量的问题和计算效率的问题,如图1-8所示。单机数据库由于无法支持分布式,所以其存储容量和计算能力的瓶颈难以突破,而大数据平台通过分布式扩展轻易解决了这两个问题。
图1-8 大数据平台的基础:分布式
分布式与扩展性密不可分,当存储和计算能力不足时,显而易见的方案就是增加集群中的机器,在存储价格和cpu价格日益下降而人力成本日益上涨的今天,这比从优化传统数据库系统着手要简单高效,且成本更低。这也是为什么说“能通过增加机器解决的问题都不是问题”的原因。
目前实际应用中的大数据平台基本是以开源的hadoop平台为核心,不同厂商在此基础上进行封装和扩展,形成自己的产品线。比较知名的商用大数据平台产品有:cloudera 的cdh,华为的fusioninsight。
图1-9为大数据平台的核心组件。其底层基础模块hdfs(hadoop distribute file system,hadoop分布式文件系统)用于提供分布式存储能力;mapreduce分布式计算框架用于提供分布式计算能力。hdfs可支持多种组件,包括hive数据仓库、数据挖掘、流处理等,其外围的zookeeper负责集群之间的协作管理,使众多的机器可以成为统一的集群,flume和sqoop则是大数据平台数据的入口和出口,负责与其他系统的数据交互。
图1-9 大数据平台的核心组件
需要注意的是,hadoop的核心模块提供的是离线、批量的计算,本身并不适合强实时环境,这也是为什么把hadoop归为分析系统的原因。不过,很多实时计算的组件经常与hadoop结合使用,如spark、storm、mahout等,这使得扩展后的hadoop平台具备了一定的实时处理能力。
下面让我们快速认识hadoop的核心组件。
1. hdfs
hdfs(hadoop distributed file system,hadoop分布式文件系统)是hadoop平台的文件基础,就如windows环境的ntfs (new technology file system)、linux环境的ext文件系统(extended file system)一样。
你可能并不需要关心hdfs的技术细节,但需要了解hdfs的主要设计理念是针对超大文件存储(几百mb~pb级别),一次写入、多次读取。它不适合用在低延迟的场景,也不适合存储大量小文件,这是因为hdfs文件的元数据(文件基本信息,如文件名称、路径、存放的datanode节点信息等)是存放在namenode的内存中的,大量的小文件会消耗namenode的内存,而且会影响mapreduce对文件的处理效率。
建立在hdfs之上的hive数据仓库也是针对大数据量的数据分析工具的,在数据量未达到一定规模时,hive并不能体现出效率优势(在小数据量时,hive的效率远低于传统关系型数据库的)。这里有一个经验值,当一个表中的数据达到数百gb的时候,使用关系型数据库进行读/写、join、sum、group by等操作时会耗费大量时间,运行一段sql脚本可能需要数个小时,这时hive将体现出绝对的优势。
可以使用hadoop shell命令进行hdfs文件的交互式操作。hadoop shell命令与linux的shell命令非常相似,多数情况下只需要在linux shell命令前加上“hadoop fs”即可。常用的命令列举如表1-1所示。
表1-1 hadoop shell常用命令
hadoop shell命令 说 明
hadoop fs -cat uri 将路径指定文件的内容输出到stdout
hadoop fs -cp uri [uri …] <dest> 将文件从源路径复制到目标路径。这个命令允许有多个源路径,此时目标路径必须是一个目录
hadoop fs -copyfromlocal <localsrc> uri 从本地文件系统中复制单个或多个源路径到hdfs文件系统
hadoop fs -copytolocal uri <localdst> 从hdfs文件系统中复制单个或多个源路径到本地文件系统
hadoop fs -rm uri [uri …] 删除指定的文件。只删除非空目录和文件
hadoop fs -rmr uri [uri …] 递归版本
hadoop fs -test -[ezd] uri -e 检查文件是否存在。如果存在,则返回0
-z 检查文件是否是0字节。如果是,则返回0
-d 如果路径是一个目录,则返回1;否则返回0
表1-1中的这些命令可以方便我们操作hdfs中的文件,第3章将使用java调用hadoop shell命令的方式实现多线程批量导入数据至hive数据仓库。详细的hadoop shell命令可访问官方网站:http://hadoop.apache.org/docs/r1.0.4/cn/hdfs shell.html。
2. maprecude
mapreduce是hadoop平台的分布式计算框架,采用“分而治之”的思想,把对大规模数据集的操作分发给多个节点共同完成,然后通过整合各个节点的中间结果,得到最终结果。
mapreduce是一个简单易用的编程模型,这个模型包括两个部分:map过程和reduce过程,由map和reduce两个函数分别实现。
map函数接受一个键–值对,经过处理产生一组中间键–值对。mapreduce框架会将map函数产生的键–值对里键相同的值传递给一个reduce函数。
reduce函数接受一个键及相关的一组值,将这组值进行合并产生一组规模更小的值(通常只有一个或没有值)。
深入了解mapreduce的实现方式,对理解大数据平台的设计理念很有帮助,虽然类sql语言hive已经代办了mapreduce的大部分工作,但是本书建议读者能够理解mapreduce的原理和简单实现,这样对于深入理解大数据大有帮助。
关于mapreduce的更多内容可以参考《hadoop权威指南(第3版)》(《hadoop: the definitive guide,3rd edition》),清华大学出版社。
3. hbase
hbase是基于hdfs的列式存储分布式数据库,属于nosql中的big tables范畴(见图1-4)。hbase号称“能够提供高可靠性、高性能、列存储、可伸缩、实时读/写的数据库系统”,因此在一些时效要求相对较高的场景,会出现hbase应用的身影。
但是需要注意的是,hbase是基于hdfs文件存储的,而hdfs并不是针对低延时的场景设计的,因此hbase本身的实时性能并不高,所以它比较适用于“异步的、准实时、高维度”的场景中。在后面第三部分中介绍的“实时数据营销平台”即使用了hbase作为数据存储。
如果你已经对hbase比较了解,则可以跳过本节下面的内容。
(1)hbase的概念视图与物理视图
通过概念视图和物理视图,可以帮助我们快速理解hbase的列存储模式。首先看一下hbase的概念视图,如图1-10所示。
图1-10 hbase的概念视图
从图1-10中可以看到hbase的几个关键概念,即row key、time stamp和column family。
row key是hbase的标识行字段,相同的row key在数据逻辑上属于同一行,图1-10中的数据均属于row key=“charles”这一行。
time stamp是hbase的时间戳,在写入数据时自动记录。因此hbase可以自动记录列的历史版本,在需要保存历史变动记录的场景里,这个特征非常有用。图1-10中的finance:balance列即有三个版本t5、t3、t2,在读取数据时,hbase默认读取最新版本。
column family是hbase的列族,hbase按照列族组织物理存储。每个列族可以随意增加列,因此hbase的列一般表示为“列族名称:列名称”方式。图1-10中列族finance含有一个列html,写作finance:balance;列族status含有两个列,分别是weight和height。
在图1-10的概念视图里,尽管表可以看成是一个稀疏的行的集合,但在物理上,它是按列族分列存储的。图1-11是hbase的物理视图。
图1-11 hbase的物理视图
注意到图1-10中的空白格在物理上是不存储的,因为根本没有必要存储。因此,若要获取t8时间的finance:balance,结果就是空;同样,若获取t5时间的status:height,结果也是空。
(2)hbase的读/写操作
hbase在实际应用中一般用作准实时分布式数据库,在数据量较小的时候表现并不突出,但在数据量巨大时的点写入和点查询性能均高于关系型数据库的。
hbase的另一个优势在于,可以几乎无限制地进行列的扩展,这非常适用于替代传统关系数据库的“大宽表”,因此用于客户标签体系(客户会拥有成千上万个的标签,并且是一个非常稀疏的数据表)的存储表是非常合适的,在后面第三部分的介绍中,将会使用hbase作为用户标签系统的数据表。
hbase表可以通过hbase shell进行交互读/写。代码清单1-1的hbase shell脚本创建了一个hbase表,并向其中插入了数据,然后读取了相关信息。
更多关于hbase shell命令的使用方法可参考hbase官网。
代码清单 1-1
#创建表clt_tag,两个列族,即base_info和trx_info
create 'clt_tag','base_info','trx_info'
#往表clt_tag中插入数据,rowkey=10001,列族base_info增加一个列name,值为queziyang
put 'clt_tag','10001','base_info:name','queziyang'
#往表clt_tag中插入数据,rowkey=10001,列族base_info增加一个列age,值为31
put 'clt_tag','10001','base_info:age','31'
#往表clt_tag中插入数据,rowkey=10001,列族trx_info增加一个列total_amt,值为1500.3
put 'clt_tag','10001','trx_info:total_amt','1500.3'
#读取clt_tag中rowkey=10001、列base_info:name的数据
get 'clt_tag','10001','base_info:name'
(3)hbase的批量读/写
hbase适用于点读/写场景,在进行大批量数据操作的时候会面临一些问题。同时,存在这样一种情况:hbase用于点查询数据库,但是数据本身需要定期更新,例如每天晚上需要将数千万条数据更新至hbase表中,以便第二天进行查询。在后面第三部分介绍的实时客户标签系统中,就需要每天将更新后的用户标签批量导入至hbase表中,因此hbase面临批量更新的问题。
由于hbase的更新等同于插入,因此批量更新方式即批量导入的方式。比较高效的批量更新操作,一般通过mapreduce程序直接生成hbase存储文件hfile,然后将生成的hfile加载到hbase表中。具体参阅第2章批量导入hbase的章节。
关于hbase的更详细内容,可以参考《hbase权威指南》(《hbase: the definitive guide》),人民邮电出版社。
4. hive
hive是hadoop平台的数据仓库工具,它将hdfs文件直接映射为数据表,并提供类sql(hive sql,hql)语句进行数据表操作。hql在执行时转化为mapreduce作业,在实际的数据批量操作场景中,hive可以完成绝大部分本来需要mapreduce程序完成的任务,因此hive的出现降低了mapreduce的使用成本,仅仅通过撰写简单的hql语句就可以享受到mapreduce的强大功能,如图1-12所示。hive是使用hadoop大数据平台数据仓库的必备技能。
hive作为大数据平台数据仓库工具,同传统数据仓库平台一样需要有统一的设计原则。在设计大数据平台数据仓库系统时,可以借鉴传统数据仓库的设计理念,把hive表看成是关系型数据库的表。
同传统数据仓库一样,hive数据仓库中表的数据加载同样分为增量更新和全量更新的情况,但由于hive本身的分布式特点,其数据表的存放规则与传统数据仓库的有所不同。
(1)hive分区表与增量更新
hive数据仓库与传统关系型数据仓库一样,也需要解决数据的出口与入口问题,不过由于hive数据本身基于hdfs分布式存储,因此我们更关注hive数据仓库制定数据的更新规则。回忆关系型数据仓库的更新规则:增量更新与全量更新,这两条规则也可以用于hive数据仓库。
图1-12 hql转为mapreduce作业
增量更新可以使用hive的分区表来“完美”解决。hive的分区表类似于关系数据库的表分区,即根据分区键将数据分散在不同的分区(partition),通过并行读取提高效率。hive的分区表可以方便指定每个分区的hdfs路径,因此可以通过程序自动完成,代码清单1-2给出的脚本作为示例创建了一个分区表,并指定了load_day作为分区键。
代码清单 1-2
create table adobe_log_app(
id int,
name string,
age int,
tel string
)
partitioned by(load_day string)
row format delimited
fields terminated by '\t'
stored as textfile;
alter table adobe_log_app add partition (load_day='20150927') location
'/hive/data/adobe_log_app/20150927';
“alter”命令往表adobe_log_app中增加了一个分区,并通过location指定了该分区的hdfs路径。显然,通过程序只需要将表名、分区键值作为参数传入,即可以实现增量数据的自动加载,其过程如图1-13所示。
图1-13 hive增量更新过程
第3章将依据图1-13所示的流程实现hive表的增量更新。
(2)hive外部表与全量更新
hive的全量更新可以使用hive外部表(external table)实现。hive外部表在创建表的时候会同时指定数据文件路径,该文件路径一般处于hive默认数据文件路径之外,这也是hive外部表名称的由来。
hive外部表通过在创建表的脚本中指定external关键字和location关键字(指定数据文件的存放路径)实现,代码清单1-3是创建外部表的示例脚本。
代码清单 1-3
create external table clt_act_info(
act_id bigint,
act_typ string,
limit int,
...
stored as textfile
location '/hive/data/clt_act_info';
hive外部表进行全量更新时,分为三个步骤:①删除原数据所在的hdfs目录(location所指目录);②创建新的hdfs目录(目录的路径与原目录保持一致);③将新数据文件复制到新的hdfs目录。图1-14展示了其整个过程。
5. spark
spark是基于内存的类mapreduce通用并行框架,它拥有mapreduce所具有的优点,并且抛弃了mapreduce的文件中转功能,不需要读/写hdfs,因此spark能更好地适用于数据挖掘与机器学习等需要多次迭代的计算场景。
spark包含四大主要组件,即spark sql、spark streaming、mllib(machine learning)、graphx,如图1-15所示。
图1-14 利用hive外部表实现数据的全量更新
图1-15 spark的主要组件
spark sql同hive sql一样,都是类sql语言,spark sql是基于spark进行分布式计算的,而hive sql是基于mapreduce进行分布式计算的。由于spark计算框架是内存实现,因此理论上spark sql的速度要比hive sql的快,当然其对内存的要求也比hive sql的高。
spark streaming是spark的流数据处理组件,它将流式计算分解成一系列短小的批处理作业,也就是把输入数据按照batch size(如1秒)分成一段一段的数据,对每一小段的数据进行处理,整个过程可以看成是一连串非常小的批处理过程。streaming流处理一般使用消息队列(如kafka)作为输入端,实时收取消息队列中订阅的消息并进行处理。spark streaming能够与kafka完美对接,有兴趣的读者可以参阅官网文档。
mllib是spark的机器学习组件,它提供协同过滤、回归、聚类、分类、人工神经网络等主流机器学习算法,这些算法都提供了api接口,可以方便通过java或python进行编程调用,因此非常容易结合大数据平台使用。
graphx是spark的图计算和图挖掘引擎,图计算在目前的关系网络分析中受到越来越多的重视。关系网络涉及多个主体之间的复杂联系,如果使用关系型数据库或者主流的数据分析工具(如sas、r、python)实现对整个关系网络的描述,已经是一件非常困难的事情,更不用说进一步的分析和计算了。graphx融合了图并行以及数据并行的优势,虽然与单纯的计算机段的性能相比不如graphlab等的计算框架,但是如果从整个图处理流水线的视角(图构建、图合并以及最终结果的查询)看,那么性能就具有明显的优势。另外,由于spark还提供了流处理、机器学习等组件,这为企业在构建大数据平台时提供了一站式服务,预计spark graphx的应用将在大数据平台中占据主导。后面的第三部分将使用graphx实现一个关系网络案例。
1.2.3 mpp数据库
mpp数据库即大规模并行处理数据库,它是一种分布式关系型数据库。mpp数据库继承了传统关系型数据库的用户友好的交互界面,同时提供了大数据平台具有的分布式存储和计算的功能。
图1-4中的greenplum和vertica即属于mpp数据库。greenplum号称支持50pb(1pb=1000tb)级海量数据的存储功能,目前国内的大众点评、阿里巴巴、华泰保险、中国远洋等均使用了该产品。
vertica在facebook上的成功应用使得最近几年在国内市场有了快速增长。vertica使用标准的sql语句,因此对于熟悉传统关系型数据库的用户来说,学习成本非常低。另外vertica的架构非常适合云计算,包括虚拟化、分布式多节点运行等,并且可以和hadoop/mapreduce集成,因此非常利于市场推广,目前国内的招商银行已经引入该产品。
mpp数据库在架构上可以分为master-slave架构(这其实也是hadoop的架构)和share-nothing架构(无共享节点架构)两种,如图1-16所示。greenplum属于master-slave架构,但其随后的产品可能转换为无共享节点架构,vertica属于无共享节点架构。
图1-16 mpp的两种架构
在master-slave架构中,master有可能成为系统瓶颈,但是master节点本身并不负责计算,仅用于slave节点之间的控制以及交互数据的转发,因此在实际使用中,master成为瓶颈的场景并不常见。
在无共享节点架构中,各个处理单元都有自己私有的cpu、内存、硬盘等资源,不存在共享资源,各节点之间通过协议进行通信,各节点独自处理自己的数据,处理后的结果可能向上层汇总或在节点间流转。
mpp数据库定位于高端数据分析市场,因此价格比较昂贵,且对硬件有特殊要求(例如teradata采用软硬件一体销售策略)。另外,虽然mpp数据库一般都支持使用标准sql语句,但很多传统关系型数据库的功能并不完全支持(例如vertica本身没有存储过程)。因此,在构建数据平台时需要根据公司的实际情况设计合理的产品选型方案—让需求选择技术,而不是让技术选择需求。
1.2.4 nosql数据库
nosql即not only sql,是对非关系型数据库的泛称(参考图1-4)。nosql数据库不遵循传统关系型数据库的acid原则,并且抛弃了磁盘存储,转而走向了内存存储。nosql数据库大多应用于分布式应用系统中。
相对于传统关系型数据库的acid理论,nosql理论基础主要基于cap原则(也叫cap定理,见图1-17)。cap定理中的c、a、p分别指 consistency(一致性)、 availability(可用性)、partition tolerance(分区容错性)。nosql理论对分布式系统中的三个特性进行了如下归纳。
1)一致性(c)。一致性被称为原子对象,任何的读/写都应该看起来是“原子”的。写后面的读一定能读到前面写的内容,所有的读/写请求都好像被全局排序。
2)可用性(a)。对任何非失败节点都应该在有限时间内给出请求的回应(请求的可终止性)。
3)分区容错性(p)。允许节点之间丢失任意多的消息,当网络分区发生时,节点之间的消息可能会完全丢失。
cap定理由eric brewer教授提出,并由lynch等人于2002年证明了brewer的猜想。cap定理告诉我们,一个分布式系统不可能同时满足一致性、可用性和分区容错性这三个需求,最多只能同时满足两个。
图1-17 cap定理
根据cap定理,可以根据不同的应用场景选取其中的两个作为设计方向。目前,nosql数据库作为实时应用系统数据库一般遵循ap原则。满足ap原则的nosql数据库一般采用key-value内存数据库,如redis(参考图1-4)。
但cap定理正在面临诸多质疑。cap的概念定义比较模糊,而且cap没有考虑不同的基础架构、不同的应用场景、不同的网络基础和用户需求,而c、a、p在这些不同场景中的含义可能完全不同,这种无差异化的定义直接导致了概念的不明确,同时也成为cap被质疑的源头。
不过,cap定理仍然有显著的指导意义,它至少告诉我们在设计分布式系统和选择nosql数据库产品时需要考虑的基本方向,它还提醒我们分布式系统与传统系统架构存在的差异性,你必须根据实际的应用慎重选择分布式框架。