前言
Hadoop 在大数据技术体系中的地位至关重要, Hadoop 是大数据技术的基础.
这是一篇记录我自己学习的文章, Hadoop 的学习方法很多, 网上也有很多学习路线图.
hadoop 介绍
Hadoop 是一个能够对海量数据进行分布式处理的系统架构. 我采用的是 hadoop-2.8.0, 它主要包含 3 大块:
hdfs: 分布式存储系统 HDFS(Hadoop Distributed File System)分布式存储层
mapreduce: 分布式计算框架 MapReduce 分布式计算层
yarn: 资源管理系统 YARN(Yet Another Resource Negotiator)集群资源管理层
Hadoop 的核心是: HDFS 和 MapReduce.
分布式存储系统 HDFS
HDFS(Hadoop Distributed File System,Hadoop 分布式文件系统)是一个高度容错性的系统, 适合部署在廉价的机器上. HDFS 能提供高吞吐量的数据访问, 适合那些有着超大数据集 (largedata set) 的应用程序. HDFS 负责大数据的存储, 通过将大文件分块后进行分布式存储方式, 突破了服务器硬盘大小的限制, 解决了单台机器无法存储大文件的问题, HDFS 是个相对独立的模块, 可以为 YARN 提供服务, 也可以为 HBase 等其他模块提供服务.
核心
- NameNode
- DataNode
- SecondaryNameNode(NameNode 的快照)
HDFS 是一个主从结构, 一个 HDFS 集群由一个名字节点 (NameNode) 和多个数据节点 (DataNode) 组成.
HDFS 的优点(设计思想)
1. 高容错性 HDFS 认为所有计算机都可能会出问题, 为了防止某个主机失效读取不到该主机的块文件, 它将同一个文件块副本分配到其它某几个主机上, 如果其中一台主机失效, 可以迅速找另一块副本取文件. 数据自动保存多个节点; 备份丢失后, 自动恢复.
2. 海量数据的存储 非常适合上 T 级别的大文件或者一堆大数据文件的存储
3. 文件分块存储 HDFS 将一个完整的大文件平均分块 (通常每块 64M) 存储到不同计算机上, 这样读取文件可以同时从多个主机取不同区块的文件, 多主机读取比单主机读取效率要高得多得多.
4. 移动计算 在数据存储的地方进行计算, 而不是把数据拉取到计算的地方, 降低了成本, 提高了性能!
5. 流式数据访问 一次写入, 并行读取. 不支持动态改变文件内容, 而是要求让文件一次写入就不做变化, 要变化也只能在文件末添加内容.
6. 可构建在廉价的机器上 通过多副本提高可靠性, 提供了容错和恢复机制. HDFS 可以应用在普通 PC 机上, 这种机制能够让一些公司用几十台廉价的计算机就可以撑起一个大数据集群.
NameNode
作用
它是一个管理文件的命名空间
协调客户端对文件的访问
记录每个文件数据在各个 DataNode 上的位置和副本信息
文件解析
version: 是一个 properties 文件, 保存了 HDFS 的版本号
editlog: 任何对文件系统数据产生的操作, 都会被保存!
fsimage /.md5: 文件系统元数据的一个永久性的检查点, 包括数据块到文件的映射, 文件的属性等
seen_txid : 非常重要, 是存放事务相关信息的文件
什么是 FSImage 和 EditsLog
FsImage 和 Editlog 是 HDFS 的核心数据结构. 这些文件的损坏会导致整个集群的失效. 因此, 名字节点可以配置成支持多个 FsImage 和 EditLog 的副本. 任何 FsImage 和 EditLog 的更新都会同步到每一份副本中.
SecondaryNameNode
作用
Namenode 的一个快照, 周期性的备份 Namenode
记录 Namenode 中的 metadata 及其它数据
可以用来恢复 Namenode, 并不能替代 NameNode!
执行流程
SecondaryNameNode 节点会定期和 NameNode 通信, 请求其停止使用 EditLog, 暂时将新的写操作到一个新的文件 edit.new 上来, 这个操作是瞬间完成的.
SecondaryNameNode 通过 HTTP Get 方式从 NameNode 上获取到 FsImage 和 EditLog 文件并下载到本地目录
将下载下来的 FsImage 和 EditLog 加载到内存中这个过程就是 FsImage 和 EditLog 的合并(checkpoint)
合并成功之后, 会通过 post 方式将新的 FsImage 文件发送 NameNode 上.
SecondaryNamenode 会将新接收到的 FsImage 替换掉旧的, 同时将 edit.new 替换 EditLog, 这样 EditLog 就会变小.
DataNode
作用
真实数据的存储管理
一次写入, 多次读取(不修改)
文件由数据块组成, Hadoop2.x 的块大小默认是 128MB
将数据块尽量散布到各个节点
文件解析
blk_<id>:HDFS 的数据块, 保存具体的二进制数据
blk_<id>.meta: 数据块的属性信息: 版本信息, 类型信息
可以通过修改 hdfs-site.xml 的 dfs.replication 属性设置产生副本的个数! 默认是 3!
基本操作
MapReduce
MapReduce 分布式处理框架为海量的数据提供了计算. MapReduce 是一个计算框架, 它给出了一种数据处理的方式, 即通过 Map 阶段, Reduce 阶段来分布式地流式处理数据. 它只适用于大数据的离线处理, 对实时性要求很高的应用不适用.
简介
MapReduce 是一种分布式计算模型, 是 Google 提出的, 主要用于搜索领域, 解决海量数据的计算问题.
MR 有两个阶段组成: Map 和 Reduce, 用户只需实现 map()和 reduce()两个函数, 即可实现分布式计算.
MapReduce 执行流程
MapReduce 原理
MapReduce 的执行步骤
读取 HDFS 中的文件. 每一行解析成一个 < k,v>. 每一个键值对调用一次 map 函数. - <0,hello you> <10,hello me>
覆盖 map(), 接收 1 产生的 < k,v>, 进行处理, 转换为新的 < k,v > 输出. - <hello,1> <you,1> <hello,1> <me,1>
对 2 输出的 < k,v > 进行分区. 默认分为一个区.
对不同分区中的数据进行排序(按照 k), 分组. 分组指的是相同 key 的 value 放到一个集合中. - 排序后:<hello,1> <hello,1> <me,1> <you,1> ; 分组后:<hello,{1,1}><me,{1}><you,{1}>
(可选)对分组后的数据进行归约
多个 map 任务的输出, 按照不同的分区, 通过网络 copy 到不同的 reduce 节点上.(shuffle)
对多个 map 的输出进行合并, 排序. 覆盖 reduce 函数, 接收的是分组后的数据, 实现自己的业务逻辑 - <hello,2> <me,1> <you,1> 处理后, 产生新的 < k,v > 输出.
对 reduce 输出的 < k,v > 写到 HDFS 中.
MapReduce 原理总结
原语通常由若干条指令组成, 用来实现某个特定的操作. 通过一段不可分割的或不可中断的程序实现其功能. 且常驻内存. 但是这样一来, 如果原语执行需要的开销超过了机器能给予的开销, 则该原语在机器上无法执行, 通常解决该问题的办法是增加机器配置, 但计算机的配置在上层每提升一点所需要的资金都是翻倍的. 因此根据分布式文件系统的原理, MapReduce 诞生了. 它将原语分成了两个步骤即 map()和 reduce(), 同时两个阶段还可以分成多个模块在不同的机器上执行.
开始学习
上传 hadoop.tar.gz 到服务器并解压
配置 hadoop 环境变量
vi /etc/prifile
添加配置
- export HADOOP_HOME="/opt/modules/hadoop-2.8.0"
- export PATH=$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH
执行:
source /etc/profile
使得配置生效, 并验证参数
echo ${HADOOP_HOME}
配置 http://hadoop-env.sh , http://mapred-env.sh ,yarn-env.sh 文件的 JAVA_HOME 参数
修改 JAVA_HOME 参数为 java 的安装路径
如何查看 java 安装路径:
4. 配置 core-site.xml
以下操作都是在 hadoop 解压后的目录中操作
vi etc/hadoop/core-site.xml
其中:
fs.defaultFS - 配置的是 hdfs 的地址, 又为默认文件系统的名称. 一个 URI, 其方案和权限决定了 FileSystem 的实现. uri 的方案确定命名 FileSystem 实现类的 config 属性(fs.SCHEME.impl). uri 的权限用于确定文件系统的主机, 端口等. 如果是本地模式, 该配置可以如下:
- <configuration>
- <property>
- <name>fs.defaultFS</name>
- <value>hdfs://localhost:9000</value>
- </property>
- </configuration>
如果是全分布模式配置, 该配置可以如下:
- <configuration>
- <property>
- <name>fs.defaultFS</name>
- <value>hdfs://master:9000</value>
- </property>
- <property>
- <name>io.file.buffer.size</name>
- <value>131072</value>
- </property>
- <property>
- <name>hadoop.tmp.dir</name>
- <value>file:/home/hadoop/tmp</value>
- </property>
- <property>
- <name>hadoop.proxyuser.hduser.hosts</name>
- <value>*</value>
- </property>
- <property>
- <name>hadoop.proxyuser.hduser.groups</name>
- <value>*</value>
- </property>
- </configuration>
hadoop.tmp.dir - 配置的是 Hadoop 临时目录, 比如 HDFS 的 NameNode 数据默认都存放这个目录下, 查看 *-default.xml 等默认配置文件, 就可以看到很多依赖 ${hadoop.tmp.dir}的配置. 默认的 hadoop.tmp.dir 是 / tmp/hadoop-${ http://user.name }, 此时有个问题就是 NameNode 会将 HDFS 的元数据存储在这个 / tmp 目录下, 如果操作系统重启了, 系统会清空 / tmp 目录下的东西, 导致 NameNode 元数据丢失, 是个非常严重的问题, 所有我们应该修改这个路径.
更多配置属性介绍可以查看这里
5. 配置 hdfs-site.xml
vi etc/hadoop/hdfs-site.xml
dfs.replication - 配置的是 HDFS 存储时的备份数量, 因为这里是伪分布式环境只有一个节点, 所以这里设置为 1.
格式化 hdfs
hdfs namenode -format
格式化是对 HDFS 这个分布式文件系统中的 DataNode 进行分块, 统计所有分块后的初始元数据的存储在 NameNode 中. 格式化后, 查看 core-site.xml 里 hadoop.tmp.dir(本例是 / opt/data 目录)指定的目录下是否有了 dfs 目录, 如果有, 说明格式化成功.
ll /opt/data/tmp
注意:
格式化时, 这里注意 hadoop.tmp.dir 目录的权限问题, 应该 hadoop 普通用户有读写权限才行, 可以将 / opt/data 的所有者改为 hadoop.
sudo chown -R hadoop:hadoop /opt/data
查看 NameNode 格式化后的目录
ll /opt/data/tmp/dfs/name/current
fsimage - 是 NameNode 元数据在内存满了后, 持久化保存到的文件.
fsimage*.md5 - 是校验文件, 用于校验 fsimage 的完整性.
seen_txid - 是 hadoop 的版本
VERSSION - 文件中保存着 namespaceID:NameNode 的唯一 ID.clusterID: 集群 ID,NameNode 和 DataNode 的集群 ID 应该一致, 表明是一个集群.
启动 namenode,datanode,secondarynamenode
并通过 jps 命令查看是否启动
hdfs 上测试创建目录, 上传, 下载文件
创建目录
hdfs dfs -mkdir /demol
通过 hdfs 创建的目录我们直接用 ls 是查看不到的, 此时可以使用以下命令查看
hdfs dfs -ls /
上传本地文件到 HDFS 上
hdfs dfs -put {本地文件路径} /demol
这里我遇到了一个问题, 上传的时候提示我 datanode 没有启动, 后来我用 jps 命令查看了发现 datanode 自动关闭了, 这个问题的原因是因为 datanode 的 clusterID 和 namenode 的 clusterID 不匹配.
解决办法, 检查 hdfs-site.xml 和 core-site.xml 的配置, 如果没有错误, 则查看 tmp/dfs 下的 name 和 data 的 VERISON 中的集群 id 是否匹配, 如果不匹配则删除 datanode 中 current 下的文件然后重新启动; 或者直接修改集群 id
下载文件到本地
hdfs dfs -get {HDFS 文件路径}
配置 mapred-site.xml,yarn-site.xml
默认没有 mapred-site.xml 文件, 但是有个 mapred-site.xml.template 配置模板文件. 复制模板生成 mapred-site.xml
cp etc/hadoop/mapred-site.xml.template etc/hadoop/mapred-site.xml
添加配置如下:
- <property>
- <name>
- mapreduce.framework.name
- </name>
- <value>
- yarn
- </value>
- </property>
指定 mapreduce 运行在 yarn 框架上.
配置 yarn-site.xml, 添加配置如下:
- <property>
- <name>yarn.nodemanager.aux-services</name>
- <value>mapreduce_shuffle</value>
- </property>
- <property>
- <name>yarn.resourcemanager.hostname</name>
- <value>0.0.0.0</value>
- </property>
yarn.nodemanager.aux-services 配置了 yarn 的默认混洗方式, 选择为 mapreduce 的默认混洗算法.
yarn.resourcemanager.hostname 指定了 Resourcemanager 运行在哪个节点上.
更多属性查看
启动 resourcemanager,nodemanager
- yarn-daemon.sh start resourcemanager
- yarn-daemon.sh start nodemanager
通过 jsp 查看是否成功开启
运行 MapReduce Job
在 hadoop 的 share 目录里, 自带了一些 jar 包, 里面带有一些 mapreduce 实例的小例子, 位置在 share/hadoop/mapreduce/hadoop-mapreduce-examples-2.5.0.jar, 这里运行一个经典的单词统计实例
创建测试用的 input 文件
创建输入目录并将文件上传上去
- hdfs dfs -mkdir -p /wordcount/input
- hdfs dfs -put /opt/data/wc.input /wordcount/input
运行 wordcount mapreduce job
yarn jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.8.0.jar wordcount /wordcount/input /wordcount/output
查看结果目录
hdfs dfs -ls /wordcount/output
output 目录中有两个文件,_SUCCESS 文件是空文件, 有这个文件说明 Job 执行成功.
part-r-00000 文件是结果文件, 其中 - r - 说明这个文件是 Reduce 阶段产生的结果, mapreduce 程序执行时, 可以没有 reduce 阶段, 但是肯定会有 map 阶段, 如果没有 reduce 阶段这个地方有是 - m-.
一个 reduce 会产生一个 part-r - 开头的文件.
查看结果文件
总结
hdfs - 负责大数据文件的存储, 文件保存为 hadoop 二进制文件, 无法被直接查看, 保证了安全性. 其中的目录相当于虚拟目录.
yarn - 一个任务调度框架, mapreduce 在它上面运行. 同时它还可以运行 storm,spark 等
mapreduce - 计算框架, 给出数据处理方案, 然后通过 yarn 在多台机器上运行, 如果将每台机器看作一个 CPU, 那么该程序编写过程中要求能支持并行且不会导致数据混乱.
来源: https://juejin.im/post/5bc452b56fb9a05d171d6b10