Hadoop
大数据分布式存储和计算平台
一、大数据 特点
无法在一定时间范围内,使用常规软件工具进行 捕捉、管理、处理 的数据集合
- Volume 大量 : 采集、存储、计算 的数据量大
- Velocity 高速 : 要求尽可能实时完成处理
- Variety 多样 : 数据 格式、来源 多样化
- Veracity 真实 : 需确保数据的真实性,才能保证数据分析的正确性
- Value 低价值 : 数据价值密度低
二、技术框架
-
狭义的 Hadoop
-
HDFS : 分布式文档 系统
-
MapReduce : 分布式脱机计算 框架
-
Yarn : 作业调度 与 集群计算资源管理 框架
-
-
广义的 Hadoop
- 狭义的 Hadoop
- Flume : 日志数据采集 框架
- Flink : 流式数据 引擎
- Sqoop : 关系型数据库采集 框架
- Hive : 针对 HDFS 的计算 框架
- HBase : 基于 HDFS 的列式非关系型数据库
三、版本
- Apache Hadoop
- 优点
- 开源,享有全世界贡献
- 版本更新快
- 学习方便
- 缺点
- 版本维护、兼容性问题 处理困难
- 优点
- Cloudera (CDH)
- 收费
- 【建议】生产环境使用
- Hortonworks (HDP)
- 免费、开源
- 可在生产环境使用
四、Hadoop 优 / 缺点
-
优点
-
高可靠 - 存储、处理 数据 高可靠
○ 可靠性 : 服务连续无故障运行的时间
○ 可用性 : 服务可用时间 / 总时间 的百分比
○ 一个服务,可靠性很高,可以稳定运行10年,但是一旦服务中断,要用一年的时间来恢复,那么它的可用性只有90%
○ 一个服务,可靠性很差,运行10秒就会当机,但是恢复服务只需要1ms, 那么它的可用性是99.99%
-
高扩展 - 集群轻松 添加、删除 节点
-
高效性 - 可在节点间动态地移动数据,保证各节点负载均衡,处理速度提升
-
高容错 - 自动保存多个副本,任务失败自动重新分配
-
-
缺点
- 不适合低延迟数据访问
- 不能高效存储小文档
- 不支持任意修改文档
五、HDFS
○ Hadoop Distribute File System
○ 高可靠、高吞吐量的分布式文档系统
○ 负责 数据存储
1. 角色
-
NameNode (NN)
- 存储文档元数据
- 文档名
- 文档属性
- 各 文档块数据(Block) 所在的 DataNode
- 维护 HDFS 命名空间(Namespace)
- 维护副本策略
- 处理客户端读写请求
- 文档
- Fsimage
- 元数据镜像,通常称为检查点
- 记录所有 目录、文档 信息(Block数量、副本数量、权限)
- Edits
- Client 对 HDFS 所有的更新纪录
- seen_txid
- 内容只保存最后一个 Edits 文档名称的数字
- VERSION
- 纪录 NameNode 的版本号信息
- Fsimage
- 故障处理
- 将 2NN 的元数据拷贝到 NN 节点下 - 存在数据丢失风险
- 使用 Zookeeper 搭建 HDFS 高可用集群 - 一个 Active 的 NameNode,一个 Standby 的 NameNode
- 存储文档元数据
-
SecondaryNameNode (2NN)
-
辅助 NameNode
- 监控 HDFS 状态
- 定时获取 HDFS 元数据快照
-
元数据管理流程
-
第一阶段 : NameNode 启动
- 如 NN 是第一次启动,则将 NN 格式化后创建 Fsimage(镜像文档)、Edits(更新日志);否则直接加载 Fsimage、Edits 到内存
- Client 对元数据进行 增、删、改
- NN 在 Edit 增加更新纪录
- NN 在内存对数据进行 增、删、改
-
第二阶段 : Secondary NameNode 工作
CheckPoint 时机 : 1. 定时(默认 1 小时) 2. 操作次数(默认 100 万次)
-
2NN 向 NN 询问是否需要 CheckPoint,NN 直接返回结果
-
2NN 向 NN 请求运行 CheckPoint
-
NN 滚动正在运行的 Edits - 产生 002 Edit 文档,并保存 001 Edit 文档
-
NN 将 Fsimage、Edits 拷贝到 2NN
-
2NN 将 Fsimage、Edits 加载到内存合并
-
2NN 生成新的镜像文档 fsimage.chkpoint
-
2NN 将 fsimage.chkpoint 拷贝到 NN
-
NN 将 fsimage.chkpoint 重命名为 fsimage
-
-
-
-
DataNode (DN)
-
存储文档 Block
-
Block 校验
-
Block 读写
-
定期向 NameNode 汇报自己持有的 Block 信息
-
-
Client
-
文件上传时,负责将文档切分成 Block
-
与 NameNode 交互,获取文档位置信息
-
与 DataNode 交互,读写文档
-
管理或访问 HDFS
-
文件写入流程
-
Client 透过 Distributed FileSystem 向 NameNode 请求上传文档
-
NameNode 检查 目标文档是否已存在、父目录是否存在,响应是否可以上传
-
Client 向 NameNode 询问 第一个 Block 应该上传到哪几个 DataNode
-
NameNode 返回 3 个 DataNode 节点,dn1、dn2、dn3
-
Client 透过 FSDataOutputStream 向 dn1 请求上传文档;dn1 调用 dn2;dn2 调用 dn3;将通信管道创建完成
-
dn3、dn2、dn1 逐级应答 Client
-
Client 向 dn1 上传 第一个 Block,以 Packet 为单位,dn1 收到一个 Packet 就会传给 dn2,dn2 传给 dn3;dn1 每传一个 Packet 就会放入一个确认队列等待确认
-
当一个 Block 上传完成,Client 会再次请求 NameNode 上传 第二个 Block
-
-
文件读取流程
-
Client 向 NameNode 请求下载文档
-
NameNode 返回 文档元数据、文档 Block 所在的 DataNode 地址
-
Client 挑选一台 DataNode (先以就近原则,访问失败则随机),请求读取数据
-
DataNode 返回数据给 Client
Client 以 Packet 为单位接收数据,先在本地缓存,再写入目标文档
-
-
2. 概念
- 透过统一的命名空间目录树来定位文档
- 文档在物理上分块(Block)存储
- 【默认】Block 大小为 128M
- 【默认】副本数量 3 个
- 适合 一次写入,多次读出 的场景
- 不支持文档的随机修改 - 支持追加写入,不支持随机更新
- 不适合做为网盘原因
- 不方便修改
- 延迟高
- 网络开销大
- 安全模式
- 只接受读请求,不接受删除、修改请求
- 【默认】集群刚启动的 30 秒为安全模式
- 归档技术
- 解决大量小文档问题,避免 NN 内存资源浪费
- 使用 HAR 归档工具对文档进行压缩
六、MapReduce
○ 分布式脱机计算框架
○ 负责 制定计算逻辑
○ 核心思想 : 分而治之
1. 阶段
- Map : 分,并行处理输入数据,彼此间没有依赖关系 - Mapper类
- Reduce : 合,对 Map 阶段结果汇总 - Reducer类
将计算任务分成多个小任务,再将小任务结果合并
2. 类
-
Mapper 类
-
一行文本数据调用 map() 方法一次
-
map() 方法尽量不做聚合运算
-
-
Reducer 类
-
Mapper 输出数据的 Key 相同 → 同一个分区 → 运行同一个 reduce(key, values) 方法
-
Reduce Task 的数量决定了结果文档的数量 - 文档内数据有序
-
使用自定义分区器,可以将不同类型的数据交给不同的 Reduce Task
-
分区数量 与 Reduce Task 数量最好保持一致
-
分区数量 > 1,Reduce Task 数量 = 1 - 1 个结果文档,可用做全排序
-
分区数量 > Reduce Task 数量 - 输出多个空文档
-
分区数量 < Reduce Task 数量 - 报错
-
-
-
Driver 类
-
创建要提交给 Yarn 集群的 Job 对象
-
Job 对象
对 计算逻辑 的封装
-
输入数据路径
-
输出数据路径
-
相关参数
-
-
3. 串行化
○ 序列化 : 将 Java 对象转换为 二进制
○ 反序列化 : 将 二进制 转换回 Java 对象
-
Hadoop 自己实现序列化原因
- 紧凑 : 让数据更紧凑,充分利用网络带宽
- 快速 : 让 序列化、反序列化 开销更低
-
对应类型
-
boolean : BooleanWritable
-
byte : ByteWritable
-
int : IntWritable
-
float : FloatWritable
-
long : LongWritable
-
double : DoubleWritable
-
String : Text
-
map : MapWritable
-
array : ArrayWritable
-
自定义 Bean : 实现 Writeable 接口
-
序列化 与 反序列化 的 字段顺序 必须完全一样
-
如需作为 Mapper 类输出的 Key,需要实现 Comparable 接口,因为 Shuffle 过程需要排序
Shuffle : map() 方法之后,reduce() 方法之前的过程
-
-
4. 原理分析
-
Map 阶段
-
将 物理切片 Block 转换成 逻辑切片 Split (两者关系默认为一对一),有多少 Split 就会启动多少 MapTask
- Split 目的是为了确定一个 MapTask 要处理多大量的数据
- 物理切片、逻辑切片 的默认大小皆为 128M
- 如果一个文档仅比 128M 大一点点,也会被当成一个 Split
-
将 Split 交给 RecordReader对象(默认为 LineRecordReader) 读取,以 \n 作为分割符读取一行数据,返回 <key, value>。key 为每行首字符的偏移量,value 为这一行的文本内容
-
将 <key, value> 传入 Mapper ,调用 map() 方法 - 读取一行调用一次
-
map() 方法末尾,调用 context.write() 方法,对数据设置分区 - 【默认】分区按照 key Hash 后以 Reduce Task 数量取模,来确定该数据要给哪一个 Reducer 运行
-
将数据写入 环形收集区,当环形收集区数据达到域值(默认 80%),将启动溢写线程,对 key 进行排序
-
使用 Combiner 压缩数据,减少网络传输量
- 【注意】Combiner 处理过程不应影响最终结果,常用于 累加、最大值
- Combiner 父类是 Reducer
-
合并溢写文档 - 每次溢写都会在硬盘上生成临时文档,但最终输出的文档一个 MapTask 只能有一个
-
-
Reduce 阶段
-
使用 HTTP 请求拉取该 ReduceTask 对应的分区数据,将数据放入内存
-
当数据量超出内存域值,将溢写到硬盘,并使用 Combiner 压缩数据
-
合并溢写文档,并进行归并排序,生成最终文档
-
按照 Key 进行分组,将 Key 相同的数据传入同一个 reduce() 方法
5. 读取数据
-
【默认】TextInputFormat : 普通文本
-
KeyValueTextInputFormat : 按照指定分割符,将一行文本数据封装成 kv 类型
-
NLineInputFormat : 按照行数进行分片划分
-
CombineTextInputFormat : 合并小文档,避免启动过多 MapTask 任务
-
自定义 InputFormat
6. 输出数据
-
【默认】TextOutputFormat : 将每条纪录转为文本行,key、value 可以为任意类型,使用 toString() 方法输出
-
SequenceFileOutputFormat : 作为后续 MapReduce 的输入
-
自定义 OutputFormat
-
七、Yarn
○ 作业调度 与 集群资源管理 框架
○ 负责 协调计算资源
1. 角色
-
ResourceManager (RM)【母公司】
-
处理客户端请求
-
监控 ApplicationManager
-
监控 NodeManager
-
资源分配 与 调度
-
-
NodeManager (NM)【子公司】
-
单节点资源管理
-
处理来自 ResourceManager 的命令
-
-
ApplicationMaster (AM)【项目负责人】
-
向 ResourceManager 申请资源
-
向 NodeManager 发送进程启动脚本
-
监控、容错 MapTask、ReduceTask 任务
-
-
Container【工人】
-
对任务运行环境的抽象
-
运行任务
-
向 ApplicationMaster 回报任务进度
-
-
Client【顾客】
- 每 1 秒向 ApplicationMaster 询问任务进度
- 每 5 秒调用 waitForCompletion() 方法来检查任务是否完成
2. 作业提交过程
1. 作业提交
- Client 调用 job.waitForCompletion() 方法,向集群提交 MapReduce 作业
- Client 向 RM 申请一个 作业ID
- RM 向 Client 返回 作业ID 和 Job资源提交路径
- Client 提交 jar 包、切片信息、配置文档 到指定的资源提交路径
- 向 RM 申请运行 AM
2. 作业初始化
- RM 将申请运行 AM 请求初始化为 Task
- RM 将该 Task 分派给某个空闲的 NM
- 该 NM 创建 Container,并产生 AM
- 该 NM 下载 Job 资源到本地
3. 任务分配
- AM 向 RM 申请运行多个 MapTask 任务资源
- RM 将任务分派给另外两个 NM
- 两个 NM 创建 Container
4. 运行任务
- AM 向两个 NM 发送进程启动脚本
- 两个 NM 运行 MapTask 并对输出数据进行排序
- AM 等待所有 MapTask 运行完毕,向 RM 申请容器,运行 ReduceTask
- RM 将 ReduceTask 分派到另外的 NM 中
- ReduceTask 向 MapTask 获取对应的分区数据
- 运行完毕后 AM 会向 RM 申请注销自己
MapTask、ReduceTask 会将进度、状态返回给 AM
3. 调度策略
- FIFO 先进先出调度器
- 缺点 : 任务优先级只考虑时间因素,没有考虑更多条件
- 【默认】Capacity Scheduler 容量调度器
- 多个组共享集群,每个组能获得集群的一部分计算能力
- 每个组都有一个 FIFO 的队列维护任务顺序
- 【CDH版默认】Fair Scheduler 公平调度器
- 使用分组队列维护任务
- 当只有一个队列中有 1 任务时,该任务可抢占全部的集群资源
- 当 2 个队列都各有 1 个任务时,2 个任务各占 50% 集群资源
- 当 2 个队列分别有 1 个 和 2 个 任务时,任务各占 50%、25%、25% 的集群资源