批处理
使用Unix工具的批处理
分析简单日志
-
以分析网站URL统计量并倒序排序为例
-
命令链与自定义程序
- 借助SHELL命令链或脚本语言均可用来分析日志
-
排序 VS 内存中的聚合
- 对于上述统计网站的例子,如果URL种类很少,则使用内存中的聚合较合适
- GNU Coreutils(Linux)中的sort 程序通过溢出至磁盘的方式来自动应对大于内存的数据集,并能同时使用多个CPU核进行并行排序,可对大数据集进行处理
Unix哲学
-
统一的接口
- 使用文件描述符在管道中进行输入输出交互
-
逻辑与布线相分离
- 程序与输入输出管道相分离
- stdin stdout的限制:同时多输入、多输出困难
-
透明度和实验
MapReduce和分布式文件系统
常见分布式文件系统:HDFS GlusterFS QFS
MapReduce作业执行
-
mapper reducer基本概念
-
分布式执行MapReduce
- 在MapReduce中,mapper reducer基于JAVA,Mongodb CouchDB则基于javascript
-
MapReduce工作流
Reduce端连接与分组
-
MapReduce没有索引的概念,为何?
- 多数应用需要聚合全量数据
-
示例:分析用户活动事件
- 如果在分析中需要关联其它表,建议从数据库的副本提取数据,并将其放入分布式文件系统中,还要保证A、B表的相关记录能够在同一地方MapReduce
-
排序合并连接
- 概念:设有两个表A、B,对A表的按JOIN列从小到大排序,B表同样按JOIN列从小到大排序,以A表作为驱动表,从A表的第一行开始,在B表JOIN列找对应值,由于JOIN列已经排序,则可以避免Simple Nested-Loop每次都需要从头开始遍历JOIN的问题
- 在Reducer中,对采取已经进行分区和排序的A、B表数据进行JOIN
-
把相关数据放在一起
-
GROUP BY
-
处理倾斜
- 在PIG中,倾斜连接方法道德进行抽样处理,确定哪些键是热键,然后随机地将热键关联记录分发至几个Reducer,但需要将数据连接另一侧的数据均发送至多个Reducer
Map端连接
-
广播散列连接(Map端JOIN)
- 对于大数据集JOIN 小数据集的情况,通常将小数据集广播至各节点的内存散列表中
- 或者将较小数据集存储在本地磁盘上的只读索引,而索引中经常使用的部分将保留在操作系统的页面缓存
-
分区散列连接
-
在HIVE中称为bucketed map join,如果A表的bucket数量与B表的bucket数量成倍数关系,则可以使用bucketed map join,如图所示表,加了分桶如果在user_id列上进行JOIN,则相比没有加分桶JOIN会更高效
-
-
Map端合并连接
- 当输入数据集体以相同的方式分区与相同的键排序,则mapper可以按键递增的顺序依次读取两个输入文件(双指针递增)进行JOIN
-
MapReduce工作流与Map端连接
批处理工作流的输出(批处理输出的应用)
-
建立搜索索引
-
Hadoop Mapreduce仍然是建立Lucene索引的好方法,存在索引一旦创建便不可修改的问题
- 定期全量更新
- 增量建立索引,并在后台异步合并压缩段文件
-
-
键值存储作为批处理输出
- 构建机器学习系统,如分类器、推荐系统供前端用户查询
- 如果在MapReduce作业中直接基于用户查询的数据库运算,则有可能会出现数据库负载过重导致系统性能变差。
-
批处理输出的哲学
Hadoop与分布式数据库的对比
-
存储多样性
- HADOOP存储基于HDFS,存储文件类型可以是文本、图像等各种数据;而MPP数据库需要对数据和查询模式进行仔细的前期建模。
-
处理模型多样性
- MPP数据仅能做SQL查询而HADOOP可进行多种处理如构建机器学习与推荐系统
- HADOOP可同时兼容OLTP与MPP数据库,如Hbase Impala
-
针对频繁故障设计
- 批处理对故障不太敏感,即使失败了也不会影响用户,还可自动重试;而MPP查询作业通常运行几秒或几分钟,出现错误后会提示用户重新提交查询
- MapReduce可容忍单个Map或Reduce任务的失败,还可从失败的断点恢复继续运行。(如此设计主要来源于Google,Google的数据中心运行了在线生产服务与离线批处理作业,每个任务都有分配的CPU、内存与磁盘资源,其中高优先级的任务可以终止同一台机器上的低优先级的任务,而低优先级的任务可以使用集群其它的机器资源,以提高集群资源利用率。总结:不是因为硬件很不可靠,而是因为任意终止进程的自由有利于提高计算集群中的资源利用率。)
- 开源集群调度器中,YARN,Mesos或Kubernetes不支持通用优先级抢占
MapReduce之后
物化(持久化)中间状态
-
Mapreduce物化的不足
- Mapreduce作业只有在前驱作业都完成后才能启动,多节点时数据倾斜会拖慢工作流
- Mapper通常是多余的,如果Mapper与Reducer有相同的分区和排序,则不用shuffle
- 运算的中间数据通常会同步至多个复制节点,会造成中间数据的冗余
-
数据流引擎
-
如Spark Tez Flink
-
相比MapReduce的优点
-
排序仅在需要排序的地方进行,而非每个Map与Reduce阶段出现
-
没有不必要的Map任务,因为Mapper任务可以和前一Reducer任务合并
-
由于数据流所有连接与数据依赖都显式可见,因此可以使用调度器优化,将前后依赖数据的运算放在同一台机器上,避免网络传输
-
宽依赖
- 宽依赖仍然需要shuffle,无法避免网络传输
-
窄依赖
- 由于分区依赖的确定性,窄依赖的处理可以在一个线程内完成
-
-
算子可以在前驱数据准备好后立即执行,无需等待前驱阶段全部完成后再开始
-
多阶段运算JVM无需重启,节约开销
-
中间状态不落盘,运算效率高
-
-
Tez需要依赖于YARN shuffle服务来实现节点间数据的实际复制,而Spark和Flink则是包含了独立网络通信层,调度器,及用户向API的大型框架
-
-
容错
-
如果一台机器发生故障,且该台的中间状态丢失,则从先前的中间状态或原始输入数据进行重新运算
- Spark使用RDD跟踪数据的谱系
- Flink对算子状态存档
-
当算子中采用了如哈希表迭代(不能保证输出结果的顺序性)、随机逄法、依赖外部数据源或时钟,重新计算会产生不同的结果,此时需要消除这些不确定因素,如使用固定的种子生成伪随机数
-
-
关于物化的讨论
- 排序算子一般需要等待该阶段所有计算完成后才能进行下一阶段
- 作业的输入与输出一般仍是持久化到文件系统,而中间状态无需写入文件系统
图与迭代处理
-
Pregel处理模型
-
初始消息分发
- 在集群中选出一台Master,多台Worker
- 由Master将图划分为多个分区并分发至各Worker,每个Worker保存所有分区信息
- Master将输入划分多个部分,并分发给worker,如果Worker拿到的是属于自己分区的数据,则更新本节点数据,否则将数据分发到对应的顶点ID上
- 当所有数据加载完成,标记节点状态为Active状态
-
超步运算
- 1.Master向Worker发起开始超步运算指令
- 2.各节点进行S-1步运算
- 3.各节点进行消息传播,消息将会在S+1步被接收
- 4.各节点在S+1步获取由边传播过来的消息,如果没有消息,则置本节点状态为Inactive
- 5.重复2-4步骤,直至所有节点均变为Inacive后将结果返回Master
-
-
容错
- 基于每步运算完成后在磁盘上的持久化
-
并行执行
- 实践中,顶的分配以随机方式进行,而不按照顶点的相关性,将相关的顶点分为一组
高级API和语言
-
向声明式查询语言的转变
- Hive,Spark和Flink基于代价的查询优化器可以自动选择连接器(JOIN)
- 相比传统Mapreduce,声明式语言可以在优化器层面提升程序性能。比如如果只需要提取数据表中的某些字段,基于Mapreduce的程序可能需要在读取回调程序中过滤,而声明式语言在借助数据库本身特性(如Hbase的列式存储),可以在IO层面减少了访问数据量读取,提升性能。
-
专业化的不同领域