《数据密集型应用系统设计》笔记-7-批处理系统

0.前言

常见的三种系统:

  • 在线服务系统:即服务等待客户端请求或指令,并尽快处理它,返回一个响应。在线服务系统也可简称在线系统。响应时间是服务性能的主要衡量指标,可用性也很重要。
  • 批处理系统:相比在线系统,也存在离线系统,它就是批处理系统。批处理系统接收大量的输入数据,运行一个作业来处理数据,并产生输出数据。批处理作业的主要性能衡量指标通常是吞吐量(处理一定大小的输入数据集所需要的时间)。本章即讨论批处理
  • 流处理系统:又称近实时系统。流处理介于离线和批处理之间。流处理是在批处理的基础上进行的,它具有相对较低的延迟。

MapReduce就是著名的批处理算法,包括Hadoop,CouchDB,MongoDB都实现了该算法。

1.使用Unix工具进行批处理

为什么要先介绍Unix批处理?
unix的思想和经验普遍见于大规模、异构分布式数据系统。unix通常只用简短的几条命令即可完成大量复杂的操作,因此值得学习研究。
日志分析示例:

cat nginx.log    |
awk '{print $7}' |
sort            |
uniq -c         |
sort -r -n      |
head -n 5

这条命令依次进行:

  1. 打开日志文件
  2. 按空格分割每一行,并取第7个字端
  3. 排序
  4. 去重并计数
  5. 按起始处的计数排序
  6. 输出前5行,即出现次数最多的字端。

试想一下如何使用Java代码实现该流程。
Linux的sort实用程序不仅针对多线程优化,也会灵活地将数据缓存至磁盘中,因此它可以处理比内存更大的数据集。sort程序的瓶颈可能是磁盘IO。

1.1Unix设计哲学

  1. 每个程序做好且只做一件事。如果要增加新特征,那么建立一个全新的程序,而不在旧程序上增加新特征。
  2. 期待每个程序的输出成为另一个尚未确定的程序的输入。不要将输出与无关信息混淆在一起。避免使用严格的表格状或二进制输入格式。不要使用交互式输入。
  3. 尽早尝试设计和构建软件。
  4. 优先使用工具来减轻编程任务(即使该工具目前不存在,需要花费时间构建)。

这种方法的特征:自动化、快速原型设计、增量式迭代、测试友好、模块化。
下面介绍unix程序的几个规则。

1.1.1统一接口

如果希望程序的输出可以作为另一个程序的输入,那么所有的程序需要共同兼容的接口。
在unix中,这个接口就是文件(文件描述符)。文件既可以是系统实际文件,也可以是通信通道(socket,stdin,stdout),设备驱动程序(/dev/audio)。unix将这些差异明显的不同事物都通过文件表示,不可思议。统一接口的例子:URL,HTTP。

awk,sort等unix程序将文件字节序列视为:由\n(换行符 ASCII 0x0A)字符分割的记录列表(ASCII记录分隔符0x1E或许是更好的选择,它本来为此设计)。对于怎样解析行数据则没有明确的定义,可以由用户指定。

{print $7}提取字段的缺点是缺少可读性(事实上shell脚本都不易阅读),也许使用{print $field_name}更合适。
类似UNIX一样能流畅连接多个程序的工具极少。即使是相同数据模型的数据库,迁移一张表都不是一件容易的事。集成性的却是导致了数据的巴尔干化(碎片化)。

1.1.2逻辑与布线分离

UNIX工具的另一个特点是使用标准输入和标准输出,即stdin,stdout。
如果不指定任何参数,那么stdin来自键盘,标准输出为屏幕。也可以将stdout重定向至文件或另一个程序的stdin。
输入/输出的布线连接与程序逻辑分开,更容易组合成更大的系统。用户可以自己编写程序(程序的输出是文件),并与操作系统提供的工具结合在一起。
但stdin,stdout也有局限性:它更适合级联形式的流水线,如果程序需要多个输入/输出时,问题变得很棘手。

1.1.3透明与测试

Unix工具成功的部分原因在于,它非常轻松地观察事情的进展:

  • unix命令的输入文件通常被视为不可变,因此可以随意运行命令,而不会损坏输入文件。
  • 可以在任何时候结束流水线,将输出管道输送到less,很方便调试
  • 可以将某阶段的输出写入文件,这样可以在此处继续运行下一阶段的任务

unix工具简单,且非常容易测试。但是它的最大局限时只能在一台机器上运行,而这正是像Hadoop这样的工具的工作场景。

2.MapReduce与分布式文件系统

MapReduce有些类似分布在数千台机器上的UNIX工具。它的特点与UNIX工具类似:直接、蛮力、有效,需要一个或多个输入,并产生一个或多个输出。
MapReduce通常不修改输入,输出文件以序列方式一次性写入。
Unix工具使用stdin和stdout作为输出和输出。MapReduce作业在分布式文件系统上读写文件。在Hadoop的MapReduce实现中,该文件系统被称为HDFS(Hadoop Distributed File System,一个Google文件系统GFS的开源实现版本)。
除HDFS外,还有其他分布式文件系统:GlusterFS,Quantcast File System(QFS)。对象存储服务(如Amazon S3,Azure Blob,OpenStack Swift)同分布式文件系统也有相似之处。
硬件特征
共享磁盘式文件系统:网络连接存储(NAS),存储区域网络(SAN)。HDFS基于无共享原则。共享式磁盘存储由集中式存储设备实现,通常使用定制硬件和特殊网络基础设施(光纤通道)。无共享方法不需要特殊硬件,只需要通过传统数据中心网络连接的计算机。
网络结构
HDFS在每台机器上运行一个守护进程,并开放网络服务以云系其他节点访问文件。名为NameNode的中央服务器会跟踪哪个文件存储在哪台机器上。
容错
文件被复制到多台机器上,或者使用像Reed-Solomon代码这样的纠删码方案(比副本技术开销更低)。单节点文件系统使用的技术是RAID(一种磁盘级别的数据冗余方案)。
实践
目前最大的HDFS集群有上万台机器,总容量达到几百PB。

2.1MapReduce作业执行

MapReduce是一个编程框架模型。作业需要实现两个回调函数:Mapper与Reducer.
Mapper
每个输入记录都会调用一次mapper程序,其任务是从输入记录中提取关键字和值。每个记录都是独立处理的。运行完Mapper以后,就可以收集属于同一个关键字的所有值,这一操作由框架内部实现。
Reducer
使用迭代器调用reducer以使用键值对集合。Reducer可以生成输出记录。

基本过程:

  1. Mapper收集键值对数据。mapper一次处理一条数据。
  2. 排序键值对数据
  3. Reducer处理排序好的数据。reducer一次处理一条数据。
2.1.1MapReduce的分布式执行

MapReduce与Unix管道的主要区别在:它可以跨多台机器并行执行计算,且不必编写代码来指示如何并行化。mapper和reducer一次只处理一条记录,它们不需要知道输入来自哪里或输出到什么地方,由框架内部处理跨机器的数据流动。
mapper和reducer的实现:可以使用unix工具或者传统编程语言实现。Hadoop MapReduce中,mapper和reducer都是实现特定接口的Java类。在MongoDB和CouchDB中,mapper和reducer是JavaScript函数。

分布式执行流程:

  1. 指定输入:HDFS的一个目录。
  2. 为了并行化而进行分区:输入目录的每个文件或文件块都被视为一个单独的分区,由一个单独的map任务处理
  3. 一个输入文件的大小通常是几百M字节。MapReduce调度器会尝试在输入文件副本的某台机器上运行mapper任务(该原理被称为将计算靠近数据),避免将输入文件的进行复制,减少了网络负载。
  4. mapper代码是由开发人员编写,因此MapReduce框架需要将mapper代码(如Java程序的JAR文件)复制到文件所在的节点上
  5. 启动每个节点上的mapper任务。mapper任务的数量由输入文件块的数量决定。
  6. Reduce任务也被分割成块。Reduce任务的数量由开发者配置。为了确保相同关键字的所有键值对都在相同的reducer任务中,框架使用关键字的hashcode来确定哪个reduce任务接收特定的键值对(基于关键字哈希值分区)。
  7. 键值对需要进行排序。由于下一步是执行reduce任务,所以需要对数据集进行排序和分区。分区的依据就是步骤6中的reduce的分区。排序是分阶段进行:第一阶段,每个mapper任务节点对键值对进行分块,分块内部进行排序并写入mapper节点的本地磁盘;第二阶段,合并所有节点上的输出的分块信息(位于相同分区的键值对合并到一起)。
  8. 步骤7中排序的第二阶段实际上是在reducer任务读取mapper输出文件的过程中完成的:每个reducer节点连接到对应的mapper节点(包含reducer任务关键字的节点),获取mapper的输出文件。这一过程称为shuffle(其实没有随机性)。reducer获取完任务以后会进行合并,同时保持数据的排序。
  9. reducer通过关键字和迭代器进行调用,输出记录,写入分布式文件系统的文件。这一步是为了方便级联多个MapReduce作业。
2.1.2MapReduce工作流

单个MapReduce作业可以解决的问题范围有限。通常是级联多个MapReduce作业为一个工作流。一个作业的输出成为另一个作业的输入。Hadoop MapReduce框架并未对工作流有特殊的支持,链接的方式是通过目录名隐式完成的。从MapReduce框架看,工作流的每一个作业都是单独的作业。
unix的命令流水线是直接将一个进程的输出作为输入传至另一个进程,只需要很小的内存缓冲区。链接方式的MapReduce作业流显然不这么高效,它更像是一系列的命令。
MapReduce工作流只有在前一个作业完成时才能进行下一个作业,为了处理作业之间的依赖关系,已有各种Hadoop工作调度器:Oozie,Azkaban,Luigi,Airflow,Pinball.
MapReduce的一些高级工具:Pig,Hive,Cascading,Crunch,FlumeJava。

2.2Reduce端的join与分组

为什么需要join?
通常一条记录会与另一条记录存在关联。如果有代码需要访问该关联两边的记录,就需要join操作。反规范化可以减少join需求,但会带来额外的依赖。反规范化:表t1与表t2,将t1的部分字段同时写入t2,就违反了规范化。此时查询t2有可能不需要join操作。反规范化会带来额外的依赖,不利于系统维护。例如现有两张表:pay,pay_order_detail;pay_order_detail存储订单明细,而pay存储支付状态等信息。如果将支付状态信息同时写入pay_order_detail,那么pay就与pay_order_detail在任何情况下都需要同时更新,引入了新的依赖。实际上即使没有支付状态,pay_order_detail依然可以正常运作。
如果数据库设计到join操作,通常会对多个索引进行查找。但MapReduce没有索引的概念,它如何运作呢?答案是:它会读取文件的全部内容(类似全表扫描),因为分析查询通常需要计算大量记录的聚合,所以扫描整个数据集是合理的。

reduce端join:一组mapper处理t1,一组mapper处理t2。在rudecer进行"shuffle"时将相关数据放在一起,实现了join操作。
如何处理数据倾斜(热点)?
某些关键字是热点数据,那么处理该热点的reducer会拖慢整个作业的速度。不同的工具有不同的处理方法:

  • Pig首先会运行一个抽样作业,确定哪些属于热键。在执行join时,mapper将与热键有关的记录发送至随机选择的若干个reducer中的一个(不按照哈希值确定)。假设t1 join t2,那么这里是指将t1里的热键数据随机发送,t2的热键相关数据发送到所有相关的reducer。所以这里并行的代价是将一部分热键数据复制到多个reducer
  • Crunch需要指定热键。其他与Pig类似
  • Hive需要在表格元数据中明确指定热键,并将热键相关的记录与其余文件分开存放,它使用map端join

2.3map端join操作

reduce端join的优缺点:
优点:不需要mapper做任何操作,它只需要收集数据;
缺点:reducer需要进行额外的排序以及复制输入操作,非常昂贵。由于reducer的个数是人为指定,它的硬件配置并不能确保同数据集大小相匹配(mapper端通常是匹配的)。

2.3.1广播哈希join

基本流程:

  1. mapper读取数据集:t1 join t2,一般人为数据集大小 t1 >> t2。先读取小数据集t2。
  2. 准备加载大数据集t1的每个mapper1读取整个小数据集,即加载小数据集t2的mapper2的数据被广播至大数据集,小数据集在mapper1内存中的数据结构是哈希表。
  3. (join操作)mapper1加载大数据集t1时,查找哈希表中每个关键字记录。

还有一种变化是小数据集保存在本地磁盘的只读索引中(位于操作系统页面缓存),也具有良好的随机访问性能,且不要求数据都读入内存。
广播哈希算法的实现有:Pig中replicated join,Hive MapJoin,Cascading ,Crunch。它也用于数据仓库查询引擎,如Impala。

2.3.2分区哈希join

广播哈希join的缺点是:mapper1组内需要读取所有mapper2的数据。如果可以知道每个mapper1关键字特征,那么只需要读取对应的t2记录。
区分关键字特征的方法就是分区。如果读取t1时采用分区读取,那么就可以确定特定关键字位于哪个mapper1。采用这种方法需要读取t1和t2的mapper具有相同的数量,如mapper1_4只需要读取mapper2_4。如果数量不一致,那么无法同时确定某一个key在两组mapper的位置。
分区哈希join对输入数据要求较高,所以它需要先执行一个MapReduce作业规范数据集。
分区哈希join在Hive中称为bucketed map join。

2.3.3map端合并join

如果输入数据集满足:

  1. 以相同方式进行分区
  2. 以相同的方式基于关键字排序

那么mapper可以按照关键字升序增量读取两个输入文件,并执行join操作。这就是在map端合并join。那么为什么不在生成数据的作业中进行join操作呢?因为不执行join操作,该数据集还可以用于其他目的。这也符合unix工具的单一职责哲学。

数据集的物理布局非常重要。在Hadoop生态系统中,关于数据集分区的元数据经常在HCatalog和Hive metastore中维护。

2.4批处理工作流的输出

批处理工作流的输出通常是由工作流的用途决定,它有几个常见的用途。

2.4.1生成搜索索引

Google最初使用MapReduce的目的是为其搜索引擎建立索引。Hadoop MapReduce仍然是构建Lucence/Solr索引的好方法。
全文搜索索引的工作方法:索引是一个文件,数据结构以词典的形式存在,可以在其中有效地查找特定key和包含key的所有文档ID列表。
对固定文档构建全文搜索索引的方法:mapper根据需要对文档分区,reducer构建其分区索引并写入分布式文件系统。索引文件一旦创建就不可变,如果索引的文档集合发生更改,可以定期重新运行整个索引工作流,完成之后批量替换之前的索引文件。如果要增量建立索引,方法是生成新的段文件,并进行异步合并压缩。

2.4.2输出键值

批处理的另一个常见用途是构建机器学习系统,如分类器(垃圾邮件过滤,异常检测,图像识别)和推荐系统(可能认识的人/可能感兴趣的产品)。这种批处理作业的输出通常是某种数据库文件
为什么不采用直接写入数据库的方式?
为每个记录发送一条网络请求的性能较差;MapReduce作业会影响数据库的IO性能;MapReduce作业通常希望提供一个干净的“全有/全无”的保证,它不希望影响输入,也不希望只有一部分输出(这种情况下会重试作业)。直接发送每一条记录显然会产生副作用,因为无法保证作业是否会被重试。
MapReduce作业的数据库文件支持:Voldemort,Terrapin,ElephantDB,HBase批量加载。

2.4.3批量输出的哲学

UNIX设计哲学倡导明确的数据流:一个程序读取输入并写回输出,这个过程中,输入保持不变,并且没有副作用(相对输入文件而言)。MapReduce作业的输出处理遵循相同的原理:将输入视为不可变,避免副作用(如对外部数据库写入),性能良好,且更易维护:

  • 如果代码存在问题,只需要重新运行作业即可,自动重试总是安全的。而具有读写事务的数据库就不具有这样的属性。
  • 易于回滚的特性更有利于快速开发新功能。一般的OLTP系统,发生错误即意味着不可挽回的损失。
  • 逻辑(mapper/reducer代码)与连线(输入/输出目录配置)分离。

UNIX工具大都假定输入不是结构化的数据,因此可能需要大量的输入解析工作(awk|{print $7})。在Hadoop中,通过使用更多结构化的文件格式,可以消除一些低价值的语法转换:Avro和Parquet(列式存储)通常用于提供高效的基于模式的编码,并支持模式的不断演变。

2.5对比Hadoop与分布式数据库

Hadoop与大规模并行处理(MPP)数据库的最大区别是MPP数据库专注于在一个机器集群上并行执行SQL查询分析,而MapReduce和HDFS的结合则更像是一个可以运行任意程序的通用操作系统。

2.5.1存储多样性

数据库要求根据特定模型来构造数据,而分布式文件系统中的文件只是字节序列。
数据库的数据是模式化的数据,质量更高,但它一般只适合特定的业务场景(且性能极高)。而不加修饰的原始数据可以适应多种业务场景。每一种业务场景都可以对原始数据进行独特的解析工作(寿司原则)。原始数据的另一个好处是解释数据变为单边的"消费者"的问题,而数据库在读写两端都需要进行数据模式转换,不容易进行数据演变。
Hadoop经常被用于实现ETL过程:来自事务处理系统的数据以某种原始形式转储到HDFS中,然后编写MapReduce作业进行数据清理,将其转换为关系表单,并将其导入MPP数据仓库进行分析。数据建模位于一个单独步骤中,与数据收集是分离的。

2.5.2处理模型的多样性(用途的多样性)

MPP数据库属于一体化、紧密集成的软件系统,包括磁盘存储布局、查询计划、调度、执行。都可以针对数据库的特定需求进行调整和优化。因此,数据库的性能非常好。
MapReduce作业可以处理更具一般性的数据处理模型。Hive项目可以在HDFS和MapReduce上建立一个SQL查询执行引擎,将一般的文件转化了数据库视图,可以使用SQL语言进行查询。
不同的处理模型可以都在一个共享的机器集群中运行,系统非常灵活。
Hadoop生态系统包括可以随机访问的OLTP数据库,如HBase,及MPP模式的分析数据库,如Impala。HBase和Impala都不使用MapReduce,但都使用HDFS,因此他们可以共存并被集成到同一个系统中。

2.5.3故障恢复的设计

MapReduce作业倾向于将数据及时写入硬盘,遇到故障以任务级的粒度重试。这与Google最初的MapReduce硬件环境有关:MapReduce作业与在线生产服务共享机器资源,MapReduce的优先级较低,资源紧张时,系统可能会终止作业。Google采用这个方式能够充分利用机器资源,节省成本,且不会对在线生产服务造成不当的影响。
在不被经常终止的集群环境中,MapReduce的故障恢复设计则显得有些低效。

3.超越MapReduce

MapReduce在20世纪末开始流行并被大量炒作,但它只是分布式系统的许多可能编程模型中的一个。
MapReduce易于理解,结构清晰。但它难以直接使用。针对直接使用困难,在MapReduce上创建了各种高级编程模型(Pig,Hive,Cascading,Crunch)进一步封装抽象。

3.1中间状态实体化

在MapReduce工作流中,将中间状态写入文件的过程称为实体化(物化)。UNIX管道不会进行实体化。对于一些工作流,实体化是没有必要的,此时实体化带来的只是(重复性的读写)无效工作。

3.1.1数据流引擎

Spark,Tez,Flink是信的分布式批处理引擎,他们设计有很多不同,但有一个共同点:它们把整个工作流作为一个作业来处理,而不是分解成独立的子作业。
由于通过若干个处理阶段明确地建模数据流,所以这些系统被称为数据流引擎。
它们的工作方式:和MapReduce一样,通过反复调用用户自定义的函数来在单个县城上一次处理一条记录。对输入进行分区来并行工作,并将一个功能的输出复制到网络上,成为另一个功能的输入。
它们与MapReduce的不同点是,逻辑上不需要严格交替map和reduce的角色,而是以更灵活的方式进行组合:函数运算符。数据流引擎提供多种方式来布线(连接一个输出到另一个输入):

  • 通过关键字对记录进行重新分区和排序(像MapReduce的shuffle阶段一样)
  • 读取若干个输入,以相同的方式进行分区,但忽略排序。
  • 对于广播哈希join,可以将一个运算符的输出发送到join运算符的所有分区

这种风格源于Dryad和Nephele(研究系统),与MapReduce模型相比,它有几个优点:

  • 排序等计算昂贵的任务只在实际需要的地方进行,而不是map和reduce阶段默认发生
  • 没有不必要的map任务。MapReduce中就存在没有必要的mapper,实际都可以合并到reducer中
  • 由于工作流中的所有join和数据依赖性都是明确声明,因此调度器可以进行本地优化。
  • 将运算符之间的中间状态保存在内存中或写入本地磁盘。这比写入HDFS,需要更少的IO
  • 运算符可以在输入准备就绪后立即开始执行,不需要等待前一个阶段全部完成
  • MapReduce为每个任务启动一个新的JVM,而数据流引擎可以重用现有的JVM进程,减少启动开销

MapReduce工作流可以很容易迁移到Tez或Spark,只需要更改配置,而无需修改代码。
Tez是一个轻量级库,依靠YARN的shuffle服务来实现节点之间的数据复制。Spark和Flink包含网络通信层、调度器和面向用户API的大型框架。

3.1.2容错

MapReduce实体化中间状态,所以MapReduce中容错相当容易。
Spark、Flink、Tez避免将中间状态写入HDFS,为了实现重新计算,框架需要追踪给定数据是如何计算的,使用了哪个输入分区、应用了哪个运算符。Spark使用RDD(Resilient Distributed Dataset,弹性分布式数据集)来追踪。Flink对运算状态建立检查点。

计算的确定性:如果给定输入,运算符是否始终产生相同的输出?如果部分输入已经发送给下游,这个问题就很关键。如果不能确定重新计算以后的结果是否确定,那么下游的运算符也应该终止重试。为了避免这种级联故障,最好让运算符具有确定性。但非确定性行为可能无处不在(如某些工具内部接口是否使用了随机性接口)。使用固定的种子产生伪随机数可以消除一部分不确定性因素:Java Random(seed)可以产生固定的随机数序列。

3.2图与迭代处理

批处理环境查看图,其目标是在整个图上执行某种离线处理或分析。这种需求经常出现在机器学习应用程序(如推荐引擎)或排名系统中。例如最著名的图分析算法之一是PageRank,它试图根据链接至某网页的其他网页来评估该网页的受欢迎成都。它是确定网络搜索引擎结果的呈现顺序的标准之一。
读取图的方法通常是以迭代方式读取图的边。但是这种重复直到完成的想法不能用普通的MapReduce表示,它需要以迭代方式实现:

  1. 外部调度程序运行批处理来执行算法的一个步骤
  2. 当批处理过程完成时,调度器检查遍历是否完成
  3. 若尚未完成,则调度程序返回到步骤1

这种方法非常低效,因为MapReduce没有考虑迭代性,总是读取整个输入数据集。

3.2.1Pregel处理模型

Pregel是google的Pregel论文,是一种对图数据批处理优化。计算的批量同步并行模型(bulk synchronous parallel,BSP).典型系统包括Apache Giraph,Spark GraphX API和Flink Gelly API。
Pregel模型:它也希望将相同关键字记录集中在一起:一个顶点可以"发送消息"给另一个顶点,消息沿着图的边被发送。在每次迭代中,为每个顶点调用函数,将所有发送至该顶点的消息传递给它,就像调用reducer一样。顶点的状态保存在内存中,因此数据集会越来越大。这与分布式Actor model的参与者模型有些类似。

3.2.2容错

在每次迭代结束时定期快照所有顶点的状态,即进行持久化。

3.2.3并行执行

编程模型一次仅处理一个顶点,好处是顶点能够运行在任意节点上,缺点是可能会带来很多跨机器通信的开销,尤其是中间状态的数据集往往比原始图数据更大。出于这样的原因,使用单机处理也是一个可行的选择(如GraphChi)。有效的并行化图算法是一个正在研究中的领域。

3.3高级API语言

原始的MapReduce作业编写相当费力,因此出现了各种高级API语言。
高级数据流API很多灵感来自FlumeJava
高级接口允许交互式使用,可以在shell中逐步编写分析代码,并临时运行以观察结果。

3.3.1转向声明式查询语言

原始的MapReduce作业中join操作可能会对批处理作业性能产生很大影响。而声明式join操作则可以由查询优化器自行决定如何执行。
除了join操作,其他声明性特征也具有同样的优势。如果回调函数只包含一个简单的过滤条件,那么在处理每条记录时就多处相当多的CPU开销。如果以声明式表示简单过滤和map操作,那么查询优化器可以直接优化,而不必读取过多数据。
Hive,Spark DataFrames和Impala也使用向量化执行(参阅内存带宽与向量化处理):在对CPU高速缓存很有的内部循环中迭代数据,避免函数调用。Spark生成JVM字节码,Impala使用LLVM为这些内部循环生成本机代码。
声明式特征与高级API结合,使得批处理框架更像MPP,同时它具备能运行任意代码和读取任意格式数据的可扩展性,这是MPP不具备的灵活性。

3.3.2不同领域的专业化

标准处理模式不断反复运行的情形极其常见,因此有必要实现可重用的通用构建模块。
统计数值算法,这是机器学习应用所需要的。如Mahout在MapReduce、Spark、Flink上实现了用于机器学习的各种算法。MADlib在关系型MPP数据库(Apache HAWQ)中实现了类似的功能。

4.小结

分布式批处理引擎有一个有意限制的编程模型:回调函数被设定为无状态,不修改输入数据。
批处理的显著特点是:输入数据的大小甚至特征都已经确定(有界),而流处理的输入则是无界的,永无止境的数据流。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值