Hadoop

  • 1. 大数据导论
    • 1.1 大数据概念
    • 1.2 大数据特点
    • 1.3 大数据应用场景
    • 1.4 大数据部门组织结构
  • 2. Hadoop简介与大数据生态
    • 2.1 Hadoop的介绍
    • 2.2 Hadoop三大发行版本
    • 2.3 Hadoop组成
      • 2.3.1HDFS架构概述
      • 2.3.2 YARN架构概述
      • 2.3.3 MapReduce架构概述
    • 2.4 大数据技术生态体系
  • 3. Hadoop运行环境搭建
    • 3.1 模板虚拟机环境准备
    • 3.2 克隆虚拟机
    • 3.3 安装JDK
    • 3.4 安装Hadoop
    • 3.5 Hadoop目录结构
  • 4. Hadoop运行模式
    • 4.1 本地运行模式(官方wordcount)
    • 4.2 完全分布式运行模式
      • 4.2.1 虚拟机准备
      • 4.2.2 编写集群分发脚本xsync
      • 4.2.3 SSH无密登录配置
      • 4.2.4 集群配置
      • 4.2.5 群起集群
      • 4.2.6 集群启动/停止方式总结
      • 4.2.7 配置历史服务器
      • 4.2.8 配置日志的聚集
      • 4.2.9 编写hadoop集群常用脚本
      • 4.2.10 集群时间同步
  • 5. HDFS
    • 5.1 HDFS概述
      • 5.1.1 HDFS产出背景及定义
      • 5.1.2 HDFS优缺点
      • 5.1.3 HDFS组成架构
      • 5.1.4 HDFS文件块大小
    • 5.2 HDFS的Shell操作
      • 5.2.1 基本语法
      • 5.2.2 命令大全
      • 5.2.3 常用命令实操
    • 5.3 HDFS客户端操作
      • 5.3.1 准备Windows关于Hadoop的开发环境
      • 5.3.2 HDFS的API操作
    • 5.4 HDFS的数据流
      • 5.4.1 HDFS写数据流程
      • 5.4.2 网络拓扑-节点距离计算
      • 5.4.3 机架感知(副本存储节点选择)
      • 5.4.4 HDFS读数据流程
    • 5.5 NameNode和SecondaryNameNode
      • 5.5.1 NN和2NN工作机制
      • 5.5.2 Fsimage和Edits解析
      • 5.5.3 CheckPoint时间设置
      • 5.5.4 NameNode故障处理
      • 5.5.5 集群安全模式
      • 5.5.6 NameNode多目录配置
    • 5.6 DataNode
      • 5.6.1 DataNode工作机制
      • 5.6.2 数据完整性
      • 5.6.3 掉线时限参数设置
      • 5.6.4 服役新数据节点
      • 5.6.5 退役旧数据节点
      • 5.6.5 DataNode多目录配置
  • 6. MapReduce
    • 6.1 MapReduce概述
      • 6.1.1 MapReduce定义
      • 6.1.2 MapReduce优缺点
      • 6.1.3 MapReduce核心思想
      • 6.1.4 MapReduce进程
      • 6.1.5 官方WordCount源码
      • 6.1.6 常用数据序列化类型
      • 6.1.7 MapReduce编程规范
      • 6.1.8 WordCount案例
    • 6.2 Hadoop序列化
      • 6.2.1 序列化概述
    • 6.3 MapReduce框架原理
      • 6.3.1 InputFormat数据输入
        • 切片与MapTask并行度决定机制
        • Job提交流程源码详解
        • FileInputFormat切片机制
        • TextInputFormat
        • CombineTextInputFormat切片机制
      • 6.3.2 MapReduce工作流程
      • 6.3.3 Shuffle机制
        • Partition分区
        • WritableComparable排序
        • Combiner合并
      • 6.3.4 MapTask工作机制
      • 6.3.5 ReduceTask工作机制
      • 6.3.6 OutputFormat数据输出
      • 6.3.7 Join多种应用
      • 6.3.8 计数器应用
  • 7. Yarn资源调度器
    • 7.1 Yarn基本架构
    • 7.2 Yarn工作机制
    • 7.3 资源调度器
    • 7.4 容量调度器多队列提交案例
  • 8. Hadoop数据压缩
    • 8.1 概述
      • 压缩策略和原则
      • MR支持的压缩编码
    • 8.2 压缩方式选择
    • 8.3 压缩位置选择
    • 8.4 压缩参数配置
  • 9. Hadoop优化
    • 9.1 MapReduce 跑的慢的原因
    • 9.2 MapReduce优化方法
    • 9.3 Hadoop小文件优化方法
      • Hadoop小文件弊端
      • Hadoop小文件解决方案
  • 10. Hadoop新特性
    • 10.1 Hadoop2.x新特性
      • 集群间数据拷贝
      • 小文件存档
      • 回收站
    • 10.2 Hadoop3.x新特性
      • 多NN的HA架构
      • 纠删码
  • 11. Hadoop HA高可用
    • 11.1 HA概述
    • 11.2 HDFS-HA工作机制
    • 11.3 YARN-HA工作机制
    • 11.4 HDFS Federation架构设计

1. 大数据导论

1.1 大数据概念

大数据(big data),指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。主要解决,海量数据的存储和海量数据的分析计算问题。

数据存储最小的基本单位是bit,按顺序给出所有单位:bit、Byte、KB、MB、GB、TB、PB、EB、ZB、YB、BB、NB、DB。

1Byte= 8bit 1K = 1024Byte 1MB = 1024K 1G = 1024M

1T = 1024G 1P = 1024T 1E = 1024P 1Z = 1024E

1Y = 1024Z 1B = 1024Y 1N = 1024B 1D = 1024N

1986年,全球只有0.02EB也就是约21000TB的数据量,而到了2007年,全球就是280EB也就是约300000000TB的数据量,翻了14000倍。

而最近,由于移动互联网及物联网的出现,各种终端设备的接入,各种业务形式的普及,平均每40个月,全球的数据量就会翻倍!如果这样说还没有什么印象,可以再举个简单的例子,在2012年,每天会产生2.5EB的数据量。基于IDC的报告预测,从2013年到2020年,全球数据量会从4.4ZB猛增到44ZB!而到了2025年,全球会有163ZB的数据量!

由此可见,截至目前,全球的数据量已经大到爆了!而传统的关系型数据库根本处理不了如此海量的数据!

1.2 大数据特点

1)Volume(大量):

截至目前,人类生产的所有印刷材料的数据量是200PB,而历史上全人类总共说过的话的数据量大约是5EB。当前,典型个人计算机硬盘的容量为TB量级,而一些大企业的数据量已经接近EB量级。

2)Velocity(高速):

这是大数据区分于传统数据挖掘的最显著特征。根据IDC的“数字宇宙”的报告,预计到2020年,全球数据使用量将达到35.2ZB。在如此海量的数据面前,处理数据的效率就是企业的生命。

3)Variety(多样):

这种类型的多样性也让数据被分为结构化数据和非结构化数据。相对于以往便于存储的以数据库/文本为主的结构化数据,非结构化数据越来越多,包括网络日志、音频、视频、图片、地理位置信息等,这些多类型的数据对数据的处理能力提出了更高要求。

4)Value(低价值密度):

价值密度的高低与数据总量的大小成反比。

1.3 大数据应用场景

1)O2O:百度大数据+平台通过先进的线上线下打通技术和客流分析能力,助力商家精细化运营,提升销量。

2)零售:探索用户价值,提供个性化服务解决方案;贯穿网络与实体零售,携手创造极致体验。经典案例,子尿布+啤酒。

3)商品广告推荐:给用户推荐访问过的商品广告类型

4) 房产:大数据全面助力房地产行业,打造精准投策与营销,选出更合适的地,建造更合适的楼,卖给更合适的人。

5)保险:海量数据挖掘及风险预测,助力保险行业精准营销,提升精细化定价能力。

6)金融:多维度体现用户特征,帮助金融机构推荐优质客户,防范欺诈风险。

7)人工智能

1.4 大数据部门组织结构

2. Hadoop简介与大数据生态

2.1 Hadoop的介绍

Hadoop最早起源于Nutch。Nutch的设计目标是构建一个大型的全网搜索引擎,包括网页抓取、索引、查询等功能,但随着抓取网页数量的增加,遇到了严重的可扩展性问题——如何解决数十亿网页的存储和索引问题。

2003年、2004年谷歌发表的两篇论文为该问题提供了可行的解决方案。
分布式文件系统(GFS),可用于处理海量网页的存储
分布式计算框架MAPREDUCE,可用于处理海量网页的索引计算问题。

Nutch的开发人员完成了相应的开源实现HDFS和MAPREDUCE,并从Nutch中剥离成为独立项目HADOOP,到2008年1月,HADOOP成为Apache顶级项目.

狭义上来说,hadoop就是单独指代hadoop这个软件,

  • HDFS :分布式文件系统
  • MapReduce : 分布式计算系统
  • Yarn:分布式样集群资源管理

广义上来说,hadoop指代大数据的一个生态圈,包括很多其他的软件

2.2 Hadoop三大发行版本

Hadoop三大发行版本:Apache、Cloudera、Hortonworks。
Apache版本最原始(最基础)的版本,对于入门学习最好。
Cloudera内部集成了很多大数据框架。对应产品CDH。
Hortonworks文档较好。对应产品HDP。

1)Apache Hadoop
官网地址:http://hadoop.apache.org/releases.html
下载地址:https://archive.apache.org/dist/hadoop/common/

2)Cloudera Hadoop
官网地址:https://www.cloudera.com/downloads/cdh/5-10-0.html
下载地址:http://archive-primary.cloudera.com/cdh5/cdh/5/
(1)2008年成立的Cloudera是最早将Hadoop商用的公司,为合作伙伴提供Hadoop的商用解决方案,主要是包括支持、咨询服务、培训。
(2)2009年Hadoop的创始人Doug Cutting也加盟Cloudera公司。Cloudera产品主要为CDH,Cloudera Manager,Cloudera Support
(3)CDH是Cloudera的Hadoop发行版,完全开源,比Apache Hadoop在兼容性,安全性,稳定性上有所增强。Cloudera的标价为每年每个节点10000美元。
(4)Cloudera Manager是集群的软件分发及管理监控平台,可以在几个小时内部署好一个Hadoop集群,并对集群的节点及服务进行实时监控。

3)Hortonworks Hadoop
官网地址:https://hortonworks.com/products/data-center/hdp/
下载地址:https://hortonworks.com/downloads/#data-platform
(1)2011年成立的Hortonworks是雅虎与硅谷风投公司Benchmark Capital合资组建。
(2)公司成立之初就吸纳了大约25名至30名专门研究Hadoop的雅虎工程师,上述工程师均在2005年开始协助雅虎开发Hadoop,贡献了Hadoop80%的代码。
(3)Hortonworks的主打产品是Hortonworks Data Platform(HDP),也同样是100%开源的产品,HDP除常见的项目外还包括了Ambari,一款开源的安装和管理系统。
(4)Hortonworks目前已经被Cloudera公司收购。

2.3 Hadoop组成

2.3.1HDFS架构概述

1)NameNode(nn):存储文件的元数据,如文件名,文件目录结构,文件属性(生成时间、副本数、文件权限),以及每个文件的块列表和块所在的DataNode等。

2)DataNode(dn):在本地文件系统存储文件块数据,以及块数据的校验和。

3)Secondary NameNode(2nn):每隔一段时间对NameNode元数据备份。

2.3.2 YARN架构概述

2.3.3 MapReduce架构概述

MapReduce将计算过程分为两个阶段:Map和Reduce
1)Map阶段并行处理输入数据
2)Reduce阶段对Map结果进行汇总

2.4 大数据技术生态体系


1)Sqoop:Sqoop是一款开源的工具,主要用于在Hadoop、Hive与传统的数据库(MySql)间进行数据的传递,可以将一个关系型数据库(例如 :MySQL,Oracle 等)中的数据导进到Hadoop的HDFS中,也可以将HDFS的数据导进到关系型数据库中。

2)Flume:Flume是一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统,Flume支持在日志系统中定制各类数据发送方,用于收集数据;

3)Kafka:Kafka是一种高吞吐量的分布式发布订阅消息系统;

4)Spark:Spark是当前最流行的开源大数据内存计算框架。可以基于Hadoop上存储的大数据进行计算。

5)Flink:Flink是当前最流行的开源大数据内存计算框架。用于实时计算的场景较多。

6)Oozie:Oozie是一个管理Hdoop作业(job)的工作流程调度管理系统。

7)Hbase:HBase是一个分布式的、面向列的开源数据库。HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库。

8)Hive:Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的SQL查询功能,可以将SQL语句转换为MapReduce任务进行运行。 其优点是学习成本低,可以通过类SQL语句快速实现简单的MapReduce统计,不必开发专门的MapReduce应用,十分适合数据仓库的统计分析。

9)ZooKeeper:它是一个针对大型分布式系统的可靠协调系统,提供的功能包括:配置维护、名字服务、分布式同步、组服务等。

3. Hadoop运行环境搭建

3.1 模板虚拟机环境准备

1)准备一台模板虚拟机,虚拟机配置要求如下:
注:本文Linux系统环境以CentOS-7.5-x86-1804为例说明
Windows版本: Windows 10, 64-bit (Build 19043.1466) 10.0.19043
VMWare WorkStation 版本:VMware® Workstation 15 Pro
模板虚拟机:CentOS-7.5-x86-1804, 内存4G,硬盘50G,安装必要环境,为安装hadoop做准备(虚拟机内存大小设置根据自己电脑决定,建议学习大数据电脑内存16G及以上)

yum install -y epel-release
yum install -y psmisc nc net-tools rsync vim lrzsz ntp libzstd openssl-static tree iotop git

使用yum安装需要虚拟机可以正常上网,yum安装前可以先测试下虚拟机联网情况

ping www.baidu.com

2)关闭防火墙,关闭防火墙开机自启

systemctl stop firewalld
systemctl disable firewalld

3)创建wangxin用户,并修改wangxin用户的密码(用户名和密码可以自己指定,此处是为了举例)

useradd wangxin
passwd ******

4)配置wangxin用户具有root权限,方便后期加sudo执行root权限的命令

[root@hadoop100 ~]$ vim /etc/sudoers
修改/etc/sudoers文件,找到下面一行(91行),在root下面添加一行,如下所示:
## Allow root to run any commands anywhere
root    ALL=(ALL)     ALL
wangxin   ALL=(ALL)     NOPASSWD:ALL

5)在/opt目录下创建文件夹,并修改所属主和所属组
(1)在/opt目录下创建module、software文件夹

[root@hadoop100 ~]$ mkdir /opt/module
[root@hadoop100 ~]$ mkdir /opt/software

(2)修改module、software文件夹的所有者和所属组均为wangxin用户

[root@hadoop100 ~]$ chown wangxin:wangxin /opt/module
[root@hadoop100 ~]$ chown wangxin:wangxin /opt/software

(3)查看module、software文件夹的所有者和所属组

[root@hadoop100 ~]$ cd /opt/
[root@hadoop100 opt]$ ll

6)卸载虚拟机自带的open JDK

[root@hadoop100 ~]$ rpm -qa | grep -i java | xargs -n1 rpm -e --nodeps

7)重启虚拟机

[root@hadoop100 ~]$ reboot

3.2 克隆虚拟机

1)利用模板机hadoop100,克隆三台虚拟机:hadoop102 hadoop103 hadoop104

2)修改克隆机IP,以下以hadoop102举例说明
(1)修改克隆虚拟机的静态IP

[root@hadoop100 ~]$ vim /etc/sysconfig/network-scripts/ifcfg-ens33

改成

DEVICE=ens33
TYPE=Ethernet
ONBOOT=yes
BOOTPROTO=static
NAME="ens33"
IPADDR=192.168.1.102
PREFIX=24
GATEWAY=192.168.1.2
DNS1=192.168.1.2

注意:以上配置只是举例说明,IP地址之类配置可自行设置其他

(2)查看Linux虚拟机的虚拟网络编辑器,编辑->虚拟网络编辑器->VMnet8

(3)查看Windows系统适配器VMware Network Adapter VMnet8的IP地址

(4)保证Linux系统ifcfg-ens33文件中IP地址、虚拟网络编辑器地址和Windows系统VM8网络IP地址相同。

3)修改克隆机主机名,以下以hadoop102举例说明
(1)修改主机名称,两种方法二选一

[root@hadoop100 ~]$ hostnamectl --static set-hostname hadoop102

或者修改/etc/hostname文件

[root@hadoop100 ~]$ vim /etc/hostname
hadoop102

(2)配置linux克隆机主机名称映射hosts文件,打开/etc/hosts

[root@hadoop100 ~]$ vim /etc/hosts

添加如下内容

192.168.1.100 hadoop100
192.168.1.101 hadoop101
192.168.1.102 hadoop102
192.168.1.103 hadoop103
192.168.1.104 hadoop104
192.168.1.105 hadoop105
192.168.1.106 hadoop106
192.168.1.107 hadoop107
192.168.1.108 hadoop108

4)重启克隆机hadoop102

[root@hadoop100 ~]$ reboot

5)修改windows的主机映射文件(hosts文件)
(1)如果操作系统是window7,可以直接修改
(a)进入C:\Windows\System32\drivers\etc路径
(b)打开hosts文件并添加如下内容,然后保存

192.168.1.100 hadoop100
192.168.1.101 hadoop101
192.168.1.102 hadoop102
192.168.1.103 hadoop103
192.168.1.104 hadoop104
192.168.1.105 hadoop105
192.168.1.106 hadoop106
192.168.1.107 hadoop107
192.168.1.108 hadoop108

(2)如果操作系统是window10,先拷贝出来,修改保存以后,再覆盖即可
(a)进入C:\Windows\System32\drivers\etc路径
(b)拷贝hosts文件到桌面
(c)打开桌面hosts文件并添加如下内容

192.168.1.100 hadoop100
192.168.1.101 hadoop101
192.168.1.102 hadoop102
192.168.1.103 hadoop103
192.168.1.104 hadoop104
192.168.1.105 hadoop105
192.168.1.106 hadoop106
192.168.1.107 hadoop107
192.168.1.108 hadoop108

(d)将桌面hosts文件覆盖C:\Windows\System32\drivers\etc路径hosts文件

3.3 安装JDK

在虚拟机hadoop102下操作
1)卸载现有JDK

[wangxin@hadoop102 ~]$ rpm -qa | grep -i java | xargs -n1 sudo rpm -e --nodeps

2)用XShell工具将JDK导入到opt目录下面的software文件夹下面

3)在Linux系统下的opt目录中查看软件包是否导入成功

[wangxin@hadoop102 ~]$ ls /opt/software/

看到如下结果:

hadoop-3.1.3.tar.gz  jdk-8u212-linux-x64.tar.gz

4)解压JDK到/opt/module目录下

[wangxin@hadoop102 software]$ tar -zxvf jdk-8u212-linux-x64.tar.gz -C /opt/module/

5)配置JDK环境变量
(1)新建/etc/profile.d/my_env.sh文件

[wangxin@hadoop102 ~]$ sudo vim /etc/profile.d/my_env.sh

添加如下内容

#JAVA_HOME
export JAVA_HOME=/opt/module/jdk1.8.0_212
export PATH=$PATH:$JAVA_HOME/bin

(2)保存后退出

:wq

(3)source一下/etc/profile文件,让新的环境变量PATH生效

[wangxin@hadoop102 ~]$ source /etc/profile

6)测试JDK是否安装成功

[wangxin@hadoop102 ~]$ java -version

如果能看到以下结果,则代表Java安装成功。
java version “1.8.0_212”
注意:重启(如果java -version可以用就不用重启)

[wangxin@hadoop102 ~]$ sudo reboot

3.4 安装Hadoop

在虚拟机hadoop102下进行操作
Hadoop下载地址:https://archive.apache.org/dist/hadoop/common/hadoop-3.1.3/

1)用XShell工具将hadoop-3.1.3.tar.gz导入到opt目录下面的software文件夹下面

2)进入到Hadoop安装包路径下

[wangxin@hadoop102 ~]$ cd /opt/software/

3)解压安装文件到/opt/module下面

[wangxin@hadoop102 software]$ tar -zxvf hadoop-3.1.3.tar.gz -C /opt/module/

4)查看是否解压成功

[wangxin@hadoop102 software]$ ls /opt/module/
hadoop-3.1.3

5)将Hadoop添加到环境变量
(1)获取Hadoop安装路径

[wangxin@hadoop102 hadoop-3.1.3]$ pwd
/opt/module/hadoop-3.1.3

(2)打开/etc/profile.d/my_env.sh文件

sudo vim /etc/profile.d/my_env.sh

在my_env.sh文件末尾添加如下内容:(shift+g)

#HADOOP_HOME
export HADOOP_HOME=/opt/module/hadoop-3.1.3
export PATH=$PATH:$HADOOP_HOME/bin
export PATH=$PATH:$HADOOP_HOME/sbin

(3)保存后退出

:wq

(4)让修改后的文件生效

[wangxin@hadoop102 hadoop-3.1.3]$ source /etc/profile

6)测试是否安装成功

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop version
Hadoop 3.1.3

7)重启(如果Hadoop命令不能用再重启)

[wangxin@hadoop102 hadoop-3.1.3]$ sync
[wangxin@hadoop102 hadoop-3.1.3]$ sudo reboot

3.5 Hadoop目录结构

1)查看Hadoop目录结构

[wangxin@hadoop102 hadoop-3.1.3]$ ll
总用量 52
drwxr-xr-x. 2 wangxin wangxin  4096 5月  22 2017 bin
drwxr-xr-x. 3 wangxin wangxin  4096 5月  22 2017 etc
drwxr-xr-x. 2 wangxin wangxin  4096 5月  22 2017 include
drwxr-xr-x. 3 wangxin wangxin  4096 5月  22 2017 lib
drwxr-xr-x. 2 wangxin wangxin  4096 5月  22 2017 libexec
-rw-r--r--. 1 wangxin wangxin 15429 5月  22 2017 LICENSE.txt
-rw-r--r--. 1 wangxin wangxin   101 5月  22 2017 NOTICE.txt
-rw-r--r--. 1 wangxin wangxin  1366 5月  22 2017 README.txt
drwxr-xr-x. 2 wangxin wangxin  4096 5月  22 2017 sbin
drwxr-xr-x. 4 wangxin wangxin  4096 5月  22 2017 share

2)重要目录
(1)bin目录:存放对Hadoop相关服务(HDFS,YARN)进行操作的脚本
(2)etc目录:Hadoop的配置文件目录,存放Hadoop的配置文件
(3)lib目录:存放Hadoop的本地库(对数据进行压缩解压缩功能)
(4)sbin目录:存放启动或停止Hadoop相关服务的脚本
(5)share目录:存放Hadoop的依赖jar包、文档、和官方案例

4. Hadoop运行模式

Hadoop运行模式包括:本地模式、伪分布式模式以及完全分布式模式。
Hadoop官方网站:http://hadoop.apache.org/

4.1 本地运行模式(官方wordcount)

1)创建在hadoop-3.1.3文件下面创建一个wcinput文件夹

[wangxin@hadoop102 hadoop-3.1.3]$ mkdir wcinput

2)在wcinput文件下创建一个word.txt文件

[wangxin@hadoop102 hadoop-3.1.3]$ cd wcinput

3)编辑word.txt文件

[wangxin@hadoop102 wcinput]$ vim word.txt

在文件中输入如下内容

hadoop yarn
hadoop mapreduce
wangxin
wangxin

保存退出::wq

4)回到Hadoop目录/opt/module/hadoop-3.1.3

5)执行程序

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar wordcount wcinput wcoutput

6)查看结果

[wangxin@hadoop102 hadoop-3.1.3]$ cat wcoutput/part-r-00000

看到如下结果:

wangxin 2
hadoop  2
mapreduce       1
yarn    1

4.2 完全分布式运行模式

4.2.1 虚拟机准备

详见3.1,3.2两章。

4.2.2 编写集群分发脚本xsync

1)scp(secure copy)安全拷贝
(1)scp定义:
scp可以实现服务器与服务器之间的数据拷贝。(from server1 to server2)
(2)基本语法

scp    -r     $pdir/$fname           $user@hadoop$host:$pdir/$fname
命令   递归    要拷贝的文件路径/名称     目的用户@主机:目的路径/名称

(3)案例实操
前提:在 hadoop102 hadoop103 hadoop104 都已经创建好的 /opt/module
/opt/software 两个目录, 并且已经把这两个目录修改为wangxin:wangxin

sudo chown wangxin:wangxin -R /opt/module

(a)在hadoop102上,将hadoop102中/opt/module/jdk1.8.0_212目录拷贝到hadoop103上。

[wangxin@hadoop102 ~]$ scp -r /opt/module/jdk1.8.0_212  wangxin@hadoop103:/opt/module

(b)在hadoop103上,将hadoop102中/opt/module/hadoop-3.1.3目录拷贝到hadoop103上。

[wangxin@hadoop103 ~]$ scp -r wangxin@hadoop102:/opt/module/hadoop-3.1.3 /opt/module/

(c)在hadoop103上操作,将hadoop102中/opt/module目录下所有目录拷贝到hadoop104上。

[wangxin@hadoop103 opt]$ scp -r wangxin@hadoop102:/opt/module/* wangxin@hadoop104:/opt/module

2)rsync远程同步工具
rsync主要用于备份和镜像。具有速度快、避免复制相同内容和支持符号链接的优点。
rsync和scp区别:用rsync做文件的复制要比scp的速度快,rsync只对差异文件做更新。scp是把所有文件都复制过去。
(1)基本语法

rsync    -av       $pdir/$fname      $user@hadoop$host:$pdir/$fname
命令   选项参数   要拷贝的文件路径/名称    目的用户@主机:目的路径/名称

选项参数说明
选项 功能
-a 归档拷贝
-v 显示复制过程

(2)案例实操
(a)把hadoop102机器上的/opt/software目录同步到hadoop103服务器的/opt/software目录下

[wangxin@hadoop102 opt]$ rsync -av /opt/software/* wangxin@hadoop103:/opt/software

3)xsync集群分发脚本
(1)需求:循环复制文件到所有节点的相同目录下
(2)需求分析:
(a)rsync命令原始拷贝:

rsync  -av     /opt/module        root@hadoop103:/opt/

(b)期望脚本:
xsync要同步的文件名称
(c)说明:在/home/wangxin/bin这个目录下存放的脚本,wangxin用户可以在系统任何地方直接执行。

(3)脚本实现
(a)在/home/wangxin/bin目录下创建xsync文件

[wangxin@hadoop102 opt]$ cd /home/wangxin
[wangxin@hadoop102 ~]$ mkdir bin
[wangxin@hadoop102 ~]$ cd bin
[wangxin@hadoop102 bin]$ vim xsync

在该文件中编写如下代码

#!/bin/bash
#1. 判断参数个数
if [ $# -lt 1 ]
thenecho Not Enough Arguement!exit;
fi
#2. 遍历集群所有机器
for host in hadoop102 hadoop103 hadoop104
doecho ====================  $host  ====================#3. 遍历所有目录,挨个发送for file in $@do#4. 判断文件是否存在if [ -e $file ]then#5. 获取父目录pdir=$(cd -P $(dirname $file); pwd)#6. 获取当前文件的名称fname=$(basename $file)ssh $host "mkdir -p $pdir"rsync -av $pdir/$fname $host:$pdirelseecho $file does not exists!fidone
done

(b)修改脚本 xsync 具有执行权限

[wangxin@hadoop102 bin]$ chmod +x xsync

(c)将脚本复制到/bin中,以便全局调用

[wangxin@hadoop102 bin]$ sudo cp xsync /bin/

(d)测试脚本

[wangxin@hadoop102 ~]$ xsync /home/wangxin/bin
[wangxin@hadoop102 bin]$ sudo xsync /bin/xsync

4.2.3 SSH无密登录配置

1)配置ssh
(1)基本语法
ssh另一台电脑的ip地址
(2)ssh连接时出现Host key verification failed的解决方法

[wangxin@hadoop102 ~]$ ssh hadoop103

出现:

The authenticity of host '192.168.1.103 (192.168.1.103)' can't be established.
RSA key fingerprint is cf:1e:de:d7:d0:4c:2d:98:60:b4:fd:ae:b1:2d:ad:06.
Are you sure you want to continue connecting (yes/no)?

(3)解决方案如下:直接输入yes

2)无密钥配置
(1)免密登录原理

(2)生成公钥和私钥:

[wangxin@hadoop102 .ssh]$ ssh-keygen -t rsa

然后敲(三个回车),就会生成两个文件id_rsa(私钥)、id_rsa.pub(公钥)

(3)将公钥拷贝到要免密登录的目标机器上

[wangxin@hadoop102 .ssh]$ ssh-copy-id hadoop102
[wangxin@hadoop102 .ssh]$ ssh-copy-id hadoop103
[wangxin@hadoop102 .ssh]$ ssh-copy-id hadoop104

注意:
还需要在hadoop103上采用wangxin账号配置一下无密登录到hadoop102、hadoop103、hadoop104服务器上。
还需要在hadoop104上采用wangxin账号配置一下无密登录到hadoop102、hadoop103、hadoop104服务器上。
还需要在hadoop102上采用root账号,配置一下无密登录到hadoop102、hadoop103、hadoop104;

3).ssh文件夹下(~/.ssh)的文件功能解释
known_hosts 记录ssh访问过计算机的公钥(public key)
id_rsa 生成的私钥
id_rsa.pub 生成的公钥
authorized_keys 存放授权过的无密登录服务器公钥

4.2.4 集群配置

1)集群部署规划
注意:NameNode和SecondaryNameNode不要安装在同一台服务器
注意:ResourceManager也很消耗内存,不要和NameNode、SecondaryNameNode配置在同一台机器上。

2)配置文件说明
Hadoop配置文件分两类:默认配置文件和自定义配置文件,只有用户想修改某一默认配置值时,才需要修改自定义配置文件,更改相应属性值。
(1)默认配置文件:
要获取的默认文件 文件存放在Hadoop的jar包中的位置

(2)自定义配置文件:
core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml四个配置文件存放在$HADOOP_HOME/etc/hadoop这个路径上,用户可以根据项目需求重新进行修改配置。

(3)常用端口号说明

3)配置集群
(1)核心配置文件
配置core-site.xml

[wangxin@hadoop102 ~]$ cd $HADOOP_HOME/etc/hadoop
[wangxin@hadoop102 hadoop]$ vim core-site.xml

文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?><configuration><!-- 指定NameNode的地址 --><property><name>fs.defaultFS</name><value>hdfs://hadoop102:9820</value></property><!-- 指定hadoop数据的存储目录 --><property><name>hadoop.tmp.dir</name><value>/opt/module/hadoop-3.1.3/data</value></property><!-- 配置HDFS网页登录使用的静态用户为wangxin --><property><name>hadoop.http.staticuser.user</name><value>wangxin</value></property><!-- 配置该wangxin(superUser)允许通过代理访问的主机节点 --><property><name>hadoop.proxyuser.wangxin.hosts</name><value>*</value></property><!-- 配置该wangxin(superUser)允许通过代理用户所属组 --><property><name>hadoop.proxyuser.wangxin.groups</name><value>*</value></property><!-- 配置该wangxin(superUser)允许通过代理的用户--><property><name>hadoop.proxyuser.wangxin.groups</name><value>*</value></property>
</configuration>

(2)HDFS配置文件
配置hdfs-site.xml

[wangxin@hadoop102 hadoop]$ vim hdfs-site.xml

文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?><configuration><!-- nn web端访问地址--><property><name>dfs.namenode.http-address</name><value>hadoop102:9870</value></property><!-- 2nn web端访问地址--><property><name>dfs.namenode.secondary.http-address</name><value>hadoop104:9868</value></property>
</configuration>

(3)YARN配置文件
配置yarn-site.xml

[wangxin@hadoop102 hadoop]$ vim yarn-site.xml

文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?><configuration><!-- 指定MR走shuffle --><property><name>yarn.nodemanager.aux-services</name><value>mapreduce_shuffle</value></property><!-- 指定ResourceManager的地址--><property><name>yarn.resourcemanager.hostname</name><value>hadoop103</value></property><!-- 环境变量的继承 --><property><name>yarn.nodemanager.env-whitelist</name><value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME</value></property><!-- yarn容器允许分配的最大最小内存 --><property><name>yarn.scheduler.minimum-allocation-mb</name><value>512</value></property><property><name>yarn.scheduler.maximum-allocation-mb</name><value>4096</value></property><!-- yarn容器允许管理的物理内存大小 --><property><name>yarn.nodemanager.resource.memory-mb</name><value>4096</value></property><!-- 关闭yarn对物理内存和虚拟内存的限制检查 --><property><name>yarn.nodemanager.pmem-check-enabled</name><value>false</value></property><property><name>yarn.nodemanager.vmem-check-enabled</name><value>false</value></property>
</configuration>

(4)MapReduce配置文件
配置mapred-site.xml

[wangxin@hadoop102 hadoop]$ vim mapred-site.xml

文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?><configuration><!-- 指定MapReduce程序运行在Yarn上 --><property><name>mapreduce.framework.name</name><value>yarn</value></property>
</configuration>

4)在集群上分发配置好的Hadoop配置文件

[wangxin@hadoop102 hadoop]$ xsync /opt/module/hadoop-3.1.3/etc/hadoop/

5)去103和104上查看文件分发情况

[wangxin@hadoop103 ~]$ cat /opt/module/hadoop-3.1.3/etc/hadoop/core-site.xml
[wangxin@hadoop104 ~]$ cat /opt/module/hadoop-3.1.3/etc/hadoop/core-site.xml

4.2.5 群起集群

1)配置workers

[wangxin@hadoop102 hadoop]$ vim /opt/module/hadoop-3.1.3/etc/hadoop/workers

在该文件中增加如下内容:

hadoop102
hadoop103
hadoop104

注意:该文件中添加的内容结尾不允许有空格,文件中不允许有空行。
同步所有节点配置文件

[wangxin@hadoop102 hadoop]$ xsync /opt/module/hadoop-3.1.3/etc

2)启动集群
(1)如果集群是第一次启动,需要在hadoop102节点格式化NameNode(注意格式化NameNode,会产生新的集群id,导致NameNode和DataNode的集群id不一致,集群找不到已往数据。如果集群在运行过程中报错,需要重新格式化NameNode的话,一定要先停止namenode和datanode进程,并且要删除所有机器的data和logs目录,然后再进行格式化。)

[wangxin@hadoop102 ~]$ hdfs namenode -format

(2)启动HDFS

[wangxin@hadoop102 hadoop-3.1.3]$ sbin/start-dfs.sh

(3)在配置了ResourceManager的节点(hadoop103)启动YARN

[wangxin@hadoop103 hadoop-3.1.3]$ sbin/start-yarn.sh

(4)Web端查看HDFS的NameNode
(a)浏览器中输入:http://hadoop102:9870
(b)查看HDFS上存储的数据信息

(5)Web端查看YARN的ResourceManager
(a)浏览器中输入:http://hadoop103:8088
(b)查看YARN上运行的Job信息

3)集群基本测试
(1)上传文件到集群
上传小文件

[wangxin@hadoop102 ~]$ hadoop fs -mkdir /input
[wangxin@hadoop102 ~]$ hadoop fs -put $HADOOP_HOME/wcinput/word.txt /input

上传大文件

[wangxin@hadoop102 ~]$ hadoop fs -put  /opt/software/jdk-8u212-linux-x64.tar.gz  /

(2)上传文件后查看文件存放在什么位置
(a)查看HDFS文件存储路径

[wangxin@hadoop102 subdir0]$ pwd
/opt/module/hadoop-3.1.3/data/dfs/data/current/BP-938951106-192.168.10.107-1495462844069/current/finalized/subdir0/subdir0

(b)查看HDFS在磁盘存储文件内容

[wangxin@hadoop102 subdir0]$ cat blk_1073741825
hadoop yarn
hadoop mapreduce
wangxin
wangxin

(3)拼接

-rw-rw-r--. 1 wangxin wangxin 134217728 5月  23 16:01 blk_1073741836
-rw-rw-r--. 1 wangxin wangxin   1048583 5月  23 16:01 blk_1073741836_1012.meta
-rw-rw-r--. 1 wangxin wangxin  63439959 5月  23 16:01 blk_1073741837
-rw-rw-r--. 1 wangxin wangxin    495635 5月  23 16:01 blk_1073741837_1013.meta
[wangxin@hadoop102 subdir0]$ cat blk_1073741836>>tmp.tar.gz
[wangxin@hadoop102 subdir0]$ cat blk_1073741837>>tmp.tar.gz
[wangxin@hadoop102 subdir0]$ tar -zxvf tmp.tar.gz

(4)下载

[wangxin@hadoop104 software]$ hadoop fs -get /jdk-8u212-linux-x64.tar.gz ./

(5)执行wordcount程序

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar wordcount /input /output

4.2.6 集群启动/停止方式总结

1)各个服务组件逐一启动/停止
(1)分别启动/停止HDFS组件

hdfs --daemon start/stop namenode/datanode/secondarynamenode

(2)启动/停止YARN

yarn --daemon start/stop  resourcemanager/nodemanager

2)各个模块分开启动/停止(配置ssh是前提)常用
(1)整体启动/停止HDFS

start-dfs.sh/stop-dfs.sh

(2)整体启动/停止YARN

start-yarn.sh/stop-yarn.sh

4.2.7 配置历史服务器

为了查看程序的历史运行情况,需要配置一下历史服务器。具体配置步骤如下:
1)配置mapred-site.xml

[wangxin@hadoop102 hadoop]$ vim mapred-site.xml

在该文件里面增加如下配置。

<!-- 历史服务器端地址 -->
<property><name>mapreduce.jobhistory.address</name><value>hadoop102:10020</value>
</property><!-- 历史服务器web端地址 -->
<property><name>mapreduce.jobhistory.webapp.address</name><value>hadoop102:19888</value>
</property>

2)分发配置

[wangxin@hadoop102 hadoop]$ xsync $HADOOP_HOME/etc/hadoop/mapred-site.xml

3)在hadoop102启动历史服务器

[wangxin@hadoop102 hadoop]$ mapred --daemon start historyserver

4)查看历史服务器是否启动

[wangxin@hadoop102 hadoop]$ jps

5)查看JobHistory
http://hadoop102:19888/jobhistory

4.2.8 配置日志的聚集

日志聚集概念:应用运行完成以后,将程序运行日志信息上传到HDFS系统上。
日志聚集功能好处:可以方便的查看到程序运行详情,方便开发调试。
注意:开启日志聚集功能,需要重新启动NodeManager 、ResourceManager和HistoryServer。

开启日志聚集功能具体步骤如下:
1)配置yarn-site.xml

[wangxin@hadoop102 hadoop]$ vim yarn-site.xml

在该文件里面增加如下配置。

<!-- 开启日志聚集功能 -->
<property><name>yarn.log-aggregation-enable</name><value>true</value>
</property>
<!-- 设置日志聚集服务器地址 -->
<property>  <name>yarn.log.server.url</name>  <value>http://hadoop102:19888/jobhistory/logs</value>
</property>
<!-- 设置日志保留时间为7天 -->
<property><name>yarn.log-aggregation.retain-seconds</name><value>604800</value>
</property>

2)分发配置

[wangxin@hadoop102 hadoop]$ xsync $HADOOP_HOME/etc/hadoop/yarn-site.xml

3)关闭NodeManager 、ResourceManager和HistoryServer

[wangxin@hadoop103 ~]$ stop-yarn.sh
[wangxin@hadoop102 ~]$ mapred --daemon stop historyserver

4)启动NodeManager 、ResourceManage和HistoryServer

[wangxin@hadoop103 ~]$ start-yarn.sh
[wangxin@hadoop102 ~]$ mapred --daemon start historyserver

5)删除HDFS上已经存在的输出文件

[wangxin@hadoop102 ~]$ hadoop fs -rm -r /output

6)执行WordCount程序

[wangxin@hadoop102 ~]$ hadoop jar  $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar
wordcount /input /output

7)查看日志,
http://hadoop102:19888/jobhistory

4.2.9 编写hadoop集群常用脚本

1)查看三台服务器java进程脚本:jpsall

[wangxin@hadoop102 ~]$ cd /home/wangxin/bin
[wangxin@hadoop102 ~]$ vim jpsall

然后输入

#!/bin/bash
for host in hadoop102 hadoop103 hadoop104
doecho =============== $host ===============ssh $host jps $@ | grep -v Jps
done

保存后退出,然后赋予脚本执行权限

[wangxin@hadoop102 bin]$ chmod +x jpsall

2)hadoop集群启停脚本(包含hdfs,yarn,historyserver):myhadoop.sh

[wangxin@hadoop102 ~]$ cd /home/wangxin/bin
[wangxin@hadoop102 ~]$ vim myhadoop.sh

然后输入

#!/bin/bash
if [ $# -lt 1 ]
thenecho "No Args Input..."exit ;
fi
case $1 in
"start")echo " =================== 启动 hadoop集群 ==================="echo " --------------- 启动 hdfs ---------------"ssh hadoop102 "/opt/module/hadoop-3.1.3/sbin/start-dfs.sh"echo " --------------- 启动 yarn ---------------"ssh hadoop103 "/opt/module/hadoop-3.1.3/sbin/start-yarn.sh"echo " --------------- 启动 historyserver ---------------"ssh hadoop102 "/opt/module/hadoop-3.1.3/bin/mapred --daemon start historyserver"
;;
"stop")echo " =================== 关闭 hadoop集群 ==================="echo " --------------- 关闭 historyserver ---------------"ssh hadoop102 "/opt/module/hadoop-3.1.3/bin/mapred --daemon stop historyserver"echo " --------------- 关闭 yarn ---------------"ssh hadoop103 "/opt/module/hadoop-3.1.3/sbin/stop-yarn.sh"echo " --------------- 关闭 hdfs ---------------"ssh hadoop102 "/opt/module/hadoop-3.1.3/sbin/stop-dfs.sh"
;;
*)echo "Input Args Error..."
;;
esac

保存后退出,然后赋予脚本执行权限

[wangxin@hadoop102 bin]$ chmod +x myhadoop.sh

3)分发/home/wangxin/bin目录,保证自定义脚本在三台机器上都可以使用

[wangxin@hadoop102 ~]$ xsync /home/wangxin/bin/

4.2.10 集群时间同步

时间同步的方式:找一个机器,作为时间服务器,所有的机器与这台集群时间进行定时的同步,比如,每隔十分钟,同步一次时间。

配置时间同步具体实操:
1)时间服务器配置(必须root用户)
(0)查看所有节点ntpd服务状态和开机自启动状态

[wangxin@hadoop102 ~]$ sudo systemctl status ntpd
[wangxin@hadoop102 ~]$ sudo systemctl is-enabled ntpd

(1)在所有节点关闭ntpd服务和自启动

[wangxin@hadoop102 ~]$ sudo systemctl stop ntpd
[wangxin@hadoop102 ~]$ sudo systemctl disable ntpd

(2)修改hadoop102的ntp.conf配置文件(要将hadoop102作为时间服务器)

[wangxin@hadoop102 ~]$ sudo vim /etc/ntp.conf

修改内容如下
a)修改1(授权192.168.1.0-192.168.1.255网段上的所有机器可以从这台机器上查询和同步时间)
#restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
为restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap

b)修改2(集群在局域网中,不使用其他互联网上的时间)
server 0.centos.pool.ntp.org iburst
server 1.centos.pool.ntp.org iburst
server 2.centos.pool.ntp.org iburst
server 3.centos.pool.ntp.org iburst

#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst

c)添加3(当该节点丢失网络连接,依然可以采用本地时间作为时间服务器为集群中的其他节点提供时间同步)
server 127.127.1.0
fudge 127.127.1.0 stratum 10

(3)修改hadoop102的/etc/sysconfig/ntpd 文件

[wangxin@hadoop102 ~]$ sudo vim /etc/sysconfig/ntpd

增加内容如下(让硬件时间与系统时间一起同步)
SYNC_HWCLOCK=yes

(4)重新启动ntpd服务

[wangxin@hadoop102 ~]$ sudo systemctl start ntpd

(5)设置ntpd服务开机启动

[wangxin@hadoop102 ~]$ sudo systemctl enable ntpd

2)其他机器配置(必须root用户)
(1)在其他机器配置10分钟与时间服务器同步一次

[wangxin@hadoop103 ~]$ sudo crontab -e

编写定时任务如下:

*/10 * * * * /usr/sbin/ntpdate hadoop102

(2)修改任意机器时间

[wangxin@hadoop103 ~]$ sudo date -s "2017-9-11 11:11:11"

(3)十分钟后查看机器是否与时间服务器同步

[wangxin@hadoop103 ~]$ sudo date

5. HDFS

5.1 HDFS概述

5.1.1 HDFS产出背景及定义

HDFS产生背景
随着数据量越来越大,在一个操作系统存不下所有的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS只是分布式文件管理系统中的一种。

HDFS定义
HDFS(Hadoop Distributed File System),它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。

HDFS的使用场景:适合一次写入,多次读出的场景,且不支持文件的修改。适合用来做数据分析,并不适合用来做网盘应用。

5.1.2 HDFS优缺点

优点:

1)高容错性
(1)数据自动保存多个副本。它通过增加副本的形式,提高容错性
(2)某一个副本丢失以后,它可以自动恢复

2)适合处理大数据
(1)数据规模:能够处理数据规模达到GB、TB、甚至PB级别的数据
(2)文件规模:能够处理百万规模以上的文件数量,数量相当之大

3)可构建在廉价机器上,通过多副本机制,提高可靠性

缺点:
1)不适合低延时数据访问,比如毫秒级的存储数据,是做不到的
2)无法高效的对大量小文件进行存储
(1)存储大量小文件的话,它会占用NameNode大量的内存来存储文件目录和块信息。这样是不可取的,因为NameNode的内存总是有限的
(2)小文件存储的寻址时间会超过读取时间,它违反了HDFS的设计目标。
3)不支持并发写入、文件随机修改
(1)一个文件只能有一个写,不允许多个线程同时写;
(2)仅支持数据append(追加),不支持文件的随机修改。

5.1.3 HDFS组成架构


1)NameNode(nn):就是Master,它是一个主管、管理者。
(1)管理HDFS的名称空间;
(2)配置副本策略;
(3)管理数据块(Block)映射信息;
(4)处理客户端读写请求。

2)DataNode:就是Slave。NameNode下达命令,DataNode执行实际的操作。
(1)存储实际的数据块
(2)执行数据块的读/写操作。

3)Client:就是客户端。
(1)文件切分。文件上传HDFS的时候,Client将文件切分成一个一个的Block,然后进行上传;
(2)与NameNode交互,获取文件的位置信息;
(3)与DataNode交互,读取或者写入数据;
(4)Client提供一些命令来管理HDFS,比如NameNode格式化;
(5)Client可以通过一些命令来访问HDFS,比如对HDFS增删查改操作;

4)Secondary NameNode:并非NameNode的热备。当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务。
(1)辅助NameNode,分担其工作量,比如定期合并Fsimage和Edits,并推送给NameNode ;
(2)在紧急情况下,可辅助恢复NameNode。

5.1.4 HDFS文件块大小

HDFS中的文件在物理上是分块存储(Block),块的大小可以通过配置参数( dfs.blocksize)来规定,默认大小在Hadoop2.x版本中是128M,老版本中是64M。


为什么块的大小不能设置太小,也不能设置太大?
(1)HDFS的块设置太小,会增加寻址时间,程序一直在找块的开始位置
(2)如果块设置的太大,从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时间。导致程序在处理这块数据时,会非常慢。
总结:HDFS块的大小设置主要取决于磁盘传输速率。

5.2 HDFS的Shell操作

5.2.1 基本语法

hadoop fs 具体命令 OR hdfs dfs 具体命令
两个是完全相同的。

5.2.2 命令大全

[wangxin@hadoop102 hadoop-3.1.3]$ bin/hadoop fs[-appendToFile <localsrc> ... <dst>][-cat [-ignoreCrc] <src> ...][-checksum <src> ...][-chgrp [-R] GROUP PATH...][-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...][-chown [-R] [OWNER][:[GROUP]] PATH...][-copyFromLocal [-f] [-p] <localsrc> ... <dst>][-copyToLocal [-p] [-ignoreCrc] [-crc] <src> ... <localdst>][-count [-q] <path> ...][-cp [-f] [-p] <src> ... <dst>][-createSnapshot <snapshotDir> [<snapshotName>]][-deleteSnapshot <snapshotDir> <snapshotName>][-df [-h] [<path> ...]][-du [-s] [-h] <path> ...][-expunge][-get [-p] [-ignoreCrc] [-crc] <src> ... <localdst>][-getfacl [-R] <path>][-getmerge [-nl] <src> <localdst>][-help [cmd ...]][-ls [-d] [-h] [-R] [<path> ...]][-mkdir [-p] <path> ...][-moveFromLocal <localsrc> ... <dst>][-moveToLocal <src> <localdst>][-mv <src> ... <dst>][-put [-f] [-p] <localsrc> ... <dst>][-renameSnapshot <snapshotDir> <oldName> <newName>][-rm [-f] [-r|-R] [-skipTrash] <src> ...][-rmdir [--ignore-fail-on-non-empty] <dir> ...][-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>]][-setrep [-R] [-w] <rep> <path> ...][-stat [format] <path> ...][-tail [-f] <file>][-test -[defsz] <path>][-text [-ignoreCrc] <src> ...][-touchz <path> ...][-usage [cmd ...]]

5.2.3 常用命令实操

2.3.1 准备工作
1)启动Hadoop集群(方便后续的测试)

[wangxin@hadoop102 hadoop-3.1.3]$ sbin/start-dfs.sh
[wangxin@hadoop103 hadoop-3.1.3]$ sbin/start-yarn.sh

2)-help:输出这个命令参数

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -help rm

2.3.2 上传
1)-moveFromLocal:从本地剪切粘贴到HDFS

[wangxin@hadoop102 hadoop-3.1.3]$ touch a.txt
[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs  -moveFromLocal  ./a.txt  /test

2)-copyFromLocal:从本地文件系统中拷贝文件到HDFS路径去

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -copyFromLocal README.txt /

3)-appendToFile:追加一个文件到已经存在的文件末尾

[wangxin@hadoop102 hadoop-3.1.3]$ touch b.txt
[wangxin@hadoop102 hadoop-3.1.3]$ vi b.txt

输入

Hello, Hadoop!
[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -appendToFile b.txt /test/a.txt

4)-put:等同于copyFromLocal

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -put ./b.txt /user/wangxin/test/

2.3.3 下载
1)-copyToLocal:从HDFS拷贝到本地

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -copyToLocal /test/a.txt ./

2)-get:等同于copyToLocal,就是从HDFS下载文件到本地

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -get /test/a.txt ./

3)-getmerge:合并下载多个文件,比如HDFS的目录 /user/wangxin/test下有多个文件:log.1, log.2,log.3,…

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -getmerge /user/wangxin/test/* ./logs.txt

2.3.4 HDFS直接操作
1)-ls: 显示目录信息

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -ls /

2)-mkdir:在HDFS上创建目录

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -mkdir -p /monash/FIT

3)-cat:显示文件内容

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -cat /test/b.txt

4)-chgrp 、-chmod、-chown:Linux文件系统中的用法一样,修改文件所属权限

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs  -chmod  666  /test/a.txt
[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs  -chown  wangxin:wangxin   /test/b.txt

5)-cp :从HDFS的一个路径拷贝到HDFS的另一个路径

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -cp /test/b.txt /copys.txt

6)-mv:在HDFS目录中移动文件

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -mv /copys.txt /monash/FIT

7)-tail:显示一个文件的末尾1kb的数据

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -tail /sanguo/shuguo/kongming.txt

8)-rm:删除文件或文件夹
[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -rm /test/a.txt

9)-rmdir:删除空目录

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -mkdir /test1
[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -rmdir /test2

10)-du统计文件夹的大小信息

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -du -s -h /user/wangxin/test
2.7 K  /user/wangxin/test[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -du  -h /user/wangxin/test
1.3 K  /user/wangxin/test/README.txt
15     /user/wangxin/test/hello.txt
1.4 K  /user/wangxin/test/world.txt

11)-setrep:设置HDFS中文件的副本数量

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -setrep 10 /test/b.txt

这里设置的副本数只是记录在NameNode的元数据中,是否真的会有这么多副本,还得看DataNode的数量。因为目前只有3台设备,最多也就3个副本,只有节点数的增加到10台时,副本数才能达到10。

5.3 HDFS客户端操作

5.3.1 准备Windows关于Hadoop的开发环境

1)找到下下载好的Hadoop的Windows依赖目录,打开:

选择Hadoop-3.1.0,拷贝到其他地方(比如D盘)。

2)配置HADOOP_HOME环境变量。

3)配置Path环境变量。然后重启电脑

4)打开Intellij, 创建一个Maven工程HdfsClientDemo,并导入相应的依赖坐标+日志添加

<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.12.0</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>3.1.3</version></dependency>
</dependencies>

在项目的src/main/resources目录下,新建一个文件,命名为“log4j2.xml”,在文件中填入

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error" strict="true" name="XMLConfig"><Appenders><!-- 类型名为Console,名称为必须属性 --><Appender type="Console" name="STDOUT"><!-- 布局为PatternLayout的方式,输出样式为[INFO] [2018-01-22 17:34:01][org.test.Console]I'm here --><Layout type="PatternLayout"pattern="[%p] [%d{yyyy-MM-dd HH:mm:ss}][%c{10}]%m%n" /></Appender></Appenders><Loggers><!-- 可加性为false --><Logger name="test" level="info" additivity="false"><AppenderRef ref="STDOUT" /></Logger><!-- root loggerConfig设置 --><Root level="info"><AppenderRef ref="STDOUT" /></Root></Loggers>
</Configuration>

5)创建包名:com.wangxin.hdfs

6)创建HdfsClient类

public class HdfsClient{ @Testpublic void testMkdirs() throws IOException, InterruptedException, URISyntaxException{// 1 获取文件系统Configuration configuration = new Configuration();// 配置在集群上运行// configuration.set("fs.defaultFS", "hdfs://hadoop102:9820");// FileSystem fs = FileSystem.get(configuration);FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9820"), configuration, "wangxin");// 2 创建目录fs.mkdirs(new Path("/test/hadoop-api"));// 3 关闭资源fs.close();}
}

7)执行程序
运行时需要配置用户名称

客户端去操作HDFS时,是有一个用户身份的。默认情况下,HDFS客户端API会从JVM中获取一个参数来作为自己的用户身份:-DHADOOP_USER_NAME=wangxin,wangxin为用户名称。

5.3.2 HDFS的API操作

HDFS文件上传(测试参数优先级)
1)编写源代码

@Test
public void testCopyFromLocalFile() throws IOException, InterruptedException, URISyntaxException {// 1 获取文件系统Configuration configuration = new Configuration();configuration.set("dfs.replication", "2");FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:8020"), configuration, "wangxin");// 2 上传文件fs.copyFromLocalFile(new Path("E:/hello.txt"), new Path("/hello.txt"));// 3 关闭资源fs.close();System.out.println("over");
}

2)将hdfs-site.xml拷贝到项目的根目录下

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?><configuration><property><name>dfs.replication</name><value>1</value></property>
</configuration>

3)参数优先级
参数优先级排序:(1)客户端代码中设置的值 >(2)ClassPath下的用户自定义配置文件 >(3)然后是服务器的自定义配置(xxx-site.xml) >(4)服务器的默认配置(xxx-default.xml)

HDFS文件下载

@Test
public void testCopyToLocalFile() throws IOException, InterruptedException, URISyntaxException{// 1 获取文件系统Configuration configuration = new Configuration();FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9820"), configuration, "wangxin");// 2 执行下载操作// boolean delSrc 指是否将原文件删除// Path src 指要下载的文件路径// Path dst 指将文件下载到的路径// boolean useRawLocalFileSystem 是否开启文件校验fs.copyToLocalFile(false, new Path("/hello.txt"), new Path("e:/helloworld.txt"), true);// 3 关闭资源fs.close();
}

HDFS删除文件和目录

@Test
public void testDelete() throws IOException, InterruptedException, URISyntaxException{// 1 获取文件系统Configuration configuration = new Configuration();FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9820"), configuration, "wangxin");// 2 执行删除fs.delete(new Path("/test1/"), true);// 3 关闭资源fs.close();
}

HDFS文件更名和移动

@Test
public void testRename() throws IOException, InterruptedException, URISyntaxException{// 1 获取文件系统Configuration configuration = new Configuration();FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9820"), configuration, "wangxin"); // 2 修改文件名称fs.rename(new Path("/hello.txt"), new Path("/test.txt"));// 3 关闭资源fs.close();
}

HDFS文件详情查看
查看文件名称、权限、长度、块信息

@Test
public void testListFiles() throws IOException, InterruptedException, URISyntaxException{// 1获取文件系统Configuration configuration = new Configuration();FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9820"), configuration, "wangxin"); // 2 获取文件详情RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);while(listFiles.hasNext()){LocatedFileStatus status = listFiles.next();// 输出详情// 文件名称System.out.println(status.getPath().getName());// 长度System.out.println(status.getLen());// 权限System.out.println(status.getPermission());// 分组System.out.println(status.getGroup());// 获取存储的块信息BlockLocation[] blockLocations = status.getBlockLocations();for (BlockLocation blockLocation : blockLocations) {// 获取块存储的主机节点String[] hosts = blockLocation.getHosts();for (String host : hosts) {System.out.println(host);}}System.out.println("-----------班长的分割线----------");}// 3 关闭资源
fs.close();
}

HDFS文件和文件夹判断

@Test
public void testListStatus() throws IOException, InterruptedException, URISyntaxException{// 1 获取文件配置信息Configuration configuration = new Configuration();FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9820"), configuration, "wangxin");// 2 判断是文件还是文件夹FileStatus[] listStatus = fs.listStatus(new Path("/"));for (FileStatus fileStatus : listStatus) {// 如果是文件if (fileStatus.isFile()) {System.out.println("f:"+fileStatus.getPath().getName());}else {System.out.println("d:"+fileStatus.getPath().getName());}}// 3 关闭资源fs.close();
}

5.4 HDFS的数据流

5.4.1 HDFS写数据流程


(1)客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。
(2)NameNode返回是否可以上传。
(3)客户端请求第一个 Block上传到哪几个DataNode服务器上。
(4)NameNode返回3个DataNode节点,分别为dn1、dn2、dn3。
(5)客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。
(6)dn1、dn2、dn3逐级应答客户端。
(7)客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答。
(8)当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。(重复执行3-7步)。

5.4.2 网络拓扑-节点距离计算

在HDFS写数据的过程中,NameNode会选择距离待上传数据最近距离的DataNode接收数据。那么这个最近距离怎么计算呢?
节点距离:两个节点到达最近的共同祖先的距离总和。

5.4.3 机架感知(副本存储节点选择)

1)官方IP地址
机架感知说明
http://hadoop.apache.org/docs/r3.1.3/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html#Data_Replication

For the common case, when the replication factor is three, HDFS’s placement policy is to put one replica on the local machine if the writer is on a datanode, otherwise on a random datanode, another replica on a node in a different (remote) rack, and the last on a different node in the same remote rack. This policy cuts the inter-rack write traffic which generally improves write performance. The chance of rack failure is far less than that of node failure; this policy does not impact data reliability and availability guarantees. However, it does reduce the aggregate network bandwidth used when reading data since a block is placed in only two unique racks rather than three. With this policy, the replicas of a file do not evenly distribute across the racks. One third of replicas are on one node, two thirds of replicas are on one rack, and the other third are evenly distributed across the remaining racks. This policy improves write performance without compromising data reliability or read performance.

Hadoop3.1.3副本节点选择

5.4.4 HDFS读数据流程


(1)客户端通过DistributedFileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。
(2)挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。
(3)DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。
(4)客户端以Packet为单位接收,先在本地缓存,然后写入目标文件。

5.5 NameNode和SecondaryNameNode

5.5.1 NN和2NN工作机制

NameNode中的元数据是存储在哪里的?
首先,我们做个假设,如果存储在NameNode节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,必然是效率过低。因此,元数据需要存放在内存中。但如果只存在内存中,一旦断电,元数据丢失,整个集群就无法工作了。因此产生在磁盘中备份元数据的FsImage。
这样又会带来新的问题,当在内存中的元数据更新时,如果同时更新FsImage,就会导致效率过低,但如果不更新,就会发生一致性问题,一旦NameNode节点断电,就会产生数据丢失。因此,引入Edits文件(只进行追加操作,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到Edits中。这样,一旦NameNode节点断电,可以通过FsImage和Edits的合并,合成元数据。
但是,如果长时间添加数据到Edits中,会导致该文件数据过大,效率降低,而且一旦断电,恢复元数据需要的时间过长。因此,需要定期进行FsImage和Edits的合并,如果这个操作由NameNode节点完成,又会效率过低。因此,引入一个新的节点SecondaryNamenode,专门用于FsImage和Edits的合并。

NameNode工作机制


1)第一阶段:NameNode启动
(1)第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
(2)客户端对元数据进行增删改的请求。
(3)NameNode记录操作日志,更新滚动日志。
(4)NameNode在内存中对元数据进行增删改。
2)第二阶段:Secondary NameNode工作
(1)Secondary NameNode询问NameNode是否需要CheckPoint。直接带回NameNode是否检查结果。
(2)Secondary NameNode请求执行CheckPoint。
(3)NameNode滚动正在写的Edits日志。
(4)将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode。
(5)Secondary NameNode加载编辑日志和镜像文件到内存,并合并。
(6)生成新的镜像文件fsimage.chkpoint。
(7)拷贝fsimage.chkpoint到NameNode。
(8)NameNode将fsimage.chkpoint重新命名成fsimage。

NN和2NN工作机制详解
Fsimage:NameNode内存中元数据序列化后形成的文件。
Edits:记录客户端更新元数据信息的每一步操作(可通过Edits运算出元数据)。
NameNode启动时,先滚动Edits并生成一个空的edits.inprogress,然后加载Edits和Fsimage到内存中,此时NameNode内存就持有最新的元数据信息。Client开始对NameNode发送元数据的增删改的请求,这些请求的操作首先会被记录到edits.inprogress中(查询元数据的操作不会被记录在Edits中,因为查询操作不会更改元数据信息),如果此时NameNode挂掉,重启后会从Edits中读取元数据的信息。然后,NameNode会在内存中执行元数据的增删改的操作。
由于Edits中记录的操作会越来越多,Edits文件会越来越大,导致NameNode在启动加载Edits时会很慢,所以需要对Edits和Fsimage进行合并(所谓合并,就是将Edits和Fsimage加载到内存中,照着Edits中的操作一步步执行,最终形成新的Fsimage)。SecondaryNameNode的作用就是帮助NameNode进行Edits和Fsimage的合并工作。
SecondaryNameNode首先会询问NameNode是否需要CheckPoint(触发CheckPoint需要满足两个条件中的任意一个,定时时间到和Edits中数据写满了)。直接带回NameNode是否检查结果。SecondaryNameNode执行CheckPoint操作,首先会让NameNode滚动Edits并生成一个空的edits.inprogress,滚动Edits的目的是给Edits打个标记,以后所有新的操作都写入edits.inprogress,其他未合并的Edits和Fsimage会拷贝到SecondaryNameNode的本地,然后将拷贝的Edits和Fsimage加载到内存中进行合并,生成fsimage.chkpoint,然后将fsimage.chkpoint拷贝给NameNode,重命名为Fsimage后替换掉原来的Fsimage。NameNode在启动时就只需要加载之前未合并的Edits和Fsimage即可,因为合并过的Edits中的元数据信息已经被记录在Fsimage中。

5.5.2 Fsimage和Edits解析

Fsimage和Edits概念
NameNode被格式化之后,将在/opt/module/hadoop-3.1.3/data/tmp/dfs/name/current目录中产生如下文件
(1)Fsimage文件:HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统的所有目录和文件inode的序列化信息。
(2)Edits文件:存放HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到Edits文件中。
(3)seen_txid文件保存的是一个数字,就是最后一个edits_的数字
(4)每次NameNode启动的时候都会将Fsimage文件读入内存,加载Edits里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以看成NameNode启动的时候就将Fsimage和Edits文件进行了合并。

1)oiv查看Fsimage文件
(1)查看oiv和oev命令

[wangxin@hadoop102 current]$ hdfs
oiv            apply the offline fsimage viewer to an fsimage
oev            apply the offline edits viewer to an edits file

(2)基本语法

hdfs oiv -p 文件类型 -i镜像文件 -o 转换后文件输出路径

(3)案例实操

[wangxin@hadoop102 current]$ pwd
/opt/module/hadoop-3.1.3/data/dfs/name/current[wangxin@hadoop102 current]$ hdfs oiv -p XML -i fsimage_0000000000000000025 -o /opt/module/hadoop-3.1.3/fsimage.xml[wangxin@hadoop102 current]$ cat /opt/module/hadoop-3.1.3/fsimage.xml

思考:可以看出,Fsimage中没有记录块所对应DataNode,为什么?
在集群启动后,要求DataNode上报数据块信息,并间隔一段时间后再次上报。

2)oev查看Edits文件
(1)基本语法

hdfs oev -p 文件类型 -i编辑日志 -o 转换后文件输出路径

(2)案例实操

[wangxin@hadoop102 current]$ hdfs oev -p XML -i edits_0000000000000000012-0000000000000000013 -o /opt/module/hadoop-3.1.3/edits.xml[wangxin@hadoop102 current]$ cat /opt/module/hadoop-3.1.3/edits.xml

5.5.3 CheckPoint时间设置

1)通常情况下,SecondaryNameNode每隔一小时执行一次。
[hdfs-default.xml]

<property><name>dfs.namenode.checkpoint.period</name><value>3600s</value>
</property>

2)一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次。

<property><name>dfs.namenode.checkpoint.txns</name><value>1000000</value>
<description>操作动作次数</description>
</property><property><name>dfs.namenode.checkpoint.check.period</name><value>60s</value>
<description> 1分钟检查一次操作次数</description>
</property >

5.5.4 NameNode故障处理

NameNode故障后,可以采用如下两种方法恢复数据。
1)将SecondaryNameNode中数据拷贝到NameNode存储数据的目录;
(1)kill -9 NameNode进程
(2)删除NameNode存储的数据(/opt/module/hadoop-3.1.3/data/tmp/dfs/name)

[wangxin@hadoop102 hadoop-3.1.3]$ rm -rf /opt/module/hadoop-3.1.3/data/dfs/name/*

(3)拷贝SecondaryNameNode中数据到原NameNode存储数据目录

[wangxin@hadoop102 dfs]$ scp -r wangxin@hadoop104:/opt/module/hadoop-3.1.3/data/dfs/namesecondary/* ./name/

(4)重新启动NameNode

[wangxin@hadoop102 hadoop-3.1.3]$ hdfs --daemon start namenode

2)使用-importCheckpoint选项启动NameNode守护进程,从而将SecondaryNameNode中数据拷贝到NameNode目录中。
(1)修改hdfs-site.xml中的

<property><name>dfs.namenode.checkpoint.period</name><value>120</value>
</property><property><name>dfs.namenode.name.dir</name><value>/opt/module/hadoop-3.1.3/data/dfs/name</value>
</property>

(2)kill -9 NameNode进程
(3)删除NameNode存储的数据(/opt/module/hadoop-3.1.3/data/dfs/name)

[wangxin@hadoop102 hadoop-3.1.3]$ rm -rf /opt/module/hadoop-3.1.3/data/dfs/name/*

(4)如果SecondaryNameNode不和NameNode在一个主机节点上,需要将SecondaryNameNode存储数据的目录拷贝到NameNode存储数据的平级目录,并删除in_use.lock文件

[wangxin@hadoop102 dfs]$ scp -r wangxin@hadoop104:/opt/module/hadoop-3.1.3/data/dfs/namesecondary ./[wangxin@hadoop102 namesecondary]$ rm -rf in_use.lock[wangxin@hadoop102 dfs]$ pwd
/opt/module/hadoop-3.1.3/data/dfs[wangxin@hadoop102 dfs]$ ls
data  name  namesecondary

(5)导入检查点数据(等待一会ctrl+c结束掉)

[wangxin@hadoop102 hadoop-3.1.3]$ bin/hdfs namenode -importCheckpoint

(6)启动NameNode

[wangxin@hadoop102 hadoop-3.1.3]$ hdfs --daemon start namenode

5.5.5 集群安全模式

1、NameNode启动
NameNode启动时,首先将镜像文件(Fsimage)载入内存,并执行编辑日志(Edits)中的各项操作。一旦在内存中成功建立文件系统元数据的映像,则创建一个空的编辑日志。此时,NameNode开始监听DataNode请求。这个过程期间,NameNode一直运行在安全模式,即NameNode的文件系统对于客户端来说是只读的。

2、DataNode启动
系统中的数据块的位置并不是由NameNode维护的,而是以块列表的形式存储在DataNode中。在系统的正常操作期间,NameNode会在内存中保留所有块位置的映射信息。在安全模式下,各个DataNode会向NameNode发送最新的块列表信息,NameNode了解到足够多的块位置信息之后,即可高效运行文件系统。

3、安全模式退出判断
如果满足“最小副本条件”,NameNode会在30秒钟之后就退出安全模式。所谓的最小副本条件指的是在整个文件系统中99.9%的块满足最小副本级别(默认值:dfs.replication.min=1)。在启动一个刚刚格式化的HDFS集群时,因为系统中还没有任何块,所以NameNode不会进入安全模式。

1)基本语法
集群处于安全模式,不能执行重要操作(写操作)。集群启动完成后,自动退出安全模式。

(1)bin/hdfs dfsadmin -safemode get     (功能描述:查看安全模式状态)
(2)bin/hdfs dfsadmin -safemode enter      (功能描述:进入安全模式状态)
(3)bin/hdfs dfsadmin -safemode leave  (功能描述:离开安全模式状态)
(4)bin/hdfs dfsadmin -safemode wait   (功能描述:等待安全模式状态)

2)案例
模拟等待安全模式
3)查看当前模式

[wangxin@hadoop102 hadoop-3.1.3]$ hdfs dfsadmin -safemode get
Safe mode is OFF

4)先进入安全模式

[wangxin@hadoop102 hadoop-3.1.3]$ bin/hdfs dfsadmin -safemode enter

5.5.6 NameNode多目录配置

1)NameNode的本地目录可以配置成多个,且每个目录存放内容相同,增加了可靠性
2)具体配置如下
(1)在hdfs-site.xml文件中添加如下内容

<property>
<name>dfs.namenode.name.dir</name>
<value>file://${hadoop.tmp.dir}/dfs/name1,file://${hadoop.tmp.dir}/dfs/name2</value>
</property>

(2)停止集群,删除三台节点的data和logs中所有数据。

[wangxin@hadoop102 hadoop-3.1.3]$ rm -rf data/ logs/
[wangxin@hadoop103 hadoop-3.1.3]$ rm -rf data/ logs/
[wangxin@hadoop104 hadoop-3.1.3]$ rm -rf data/ logs/

(3)格式化集群并启动。

[wangxin@hadoop102 hadoop-3.1.3]$ bin/hdfs namenode –format
[wangxin@hadoop102 hadoop-3.1.3]$ sbin/start-dfs.sh

(4)查看结果

[wangxin@hadoop102 dfs]$ ll
总用量 12
drwx------. 3 wangxin wangxin 4096 12月 11 08:03 data
drwxrwxr-x. 3 wangxin wangxin 4096 12月 11 08:03 name1
drwxrwxr-x. 3 wangxin wangxin 4096 12月 11 08:03 name2

5.6 DataNode

5.6.1 DataNode工作机制


(1)一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
(2)DataNode启动后向NameNode注册,通过后,周期性(1小时)的向NameNode上报所有的块信息。
(3)心跳是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个DataNode的心跳,则认为该节点不可用。
(4)集群运行中可以安全加入和退出一些机器。

5.6.2 数据完整性

如果电脑磁盘里面存储的数据是控制高铁信号灯的红灯信号(1)和绿灯信号(0),但是存储该数据的磁盘坏了,一直显示是绿灯,是否很危险?同理DataNode节点上的数据损坏了,却没有发现,是否也很危险,那么如何解决呢?
如下是DataNode节点保证数据完整性的方法。
(1)当DataNode读取Block的时候,它会计算CheckSum。
(2)如果计算后的CheckSum,与Block创建时值不一样,说明Block已经损坏。
(3)Client读取其他DataNode上的Block。
(4)常见的校验算法 crc(32),md5(128),sha1(160)
(5)DataNode在其文件创建后周期验证CheckSum。

5.6.3 掉线时限参数设置

DataNode掉线时限参数设置
1、DataNode进程死亡或者网络故障造成DataNode无法与NameNode通信
2、NameNode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。
3、HDFS默认的超时时长为10分钟+30秒。
4、如果定义超时时间为TimeOut,则超时时长的计算公式为:
TimeOut = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval
而默认的dfs.namenode.heartbeat.recheck-interval 大小为5分钟,dfs.heartbeat.interval默认为3秒

需要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的单位为毫秒,dfs.heartbeat.interval的单位为

<property><name>dfs.namenode.heartbeat.recheck-interval</name><value>300000</value>
</property>
<property><name>dfs.heartbeat.interval</name><value>3</value>
</property>

5.6.4 服役新数据节点

随着业务的增长,数据量越来越大,原有的数据节点的容量已经不能满足存储数据的需求,需要在原有集群基础上动态添加新的数据节点。

环境准备
(1)在hadoop104主机上再克隆一台hadoop105主机
(2)修改IP地址和主机名称
(3)删除原来HDFS文件系统留存的文件(/opt/module/hadoop-3.1.3/data和logs)
(4)source一下配置文件

[wangxin@hadoop105 hadoop-3.1.3]$ source /etc/profile

3)服役新节点具体步骤
(1)直接启动DataNode,即可关联到集群

[wangxin@hadoop105 hadoop-3.1.3]$ hdfs --daemon start datanode
[wangxin@hadoop105 hadoop-3.1.3]$ yarn --daemon start nodemanager

(2)在hadoop105上上传文件

[wangxin@hadoop105 hadoop-3.1.3]$ hadoop fs -put /opt/module/hadoop-3.1.3/LICENSE.txt /

(3)如果数据不均衡,可以用命令实现集群的再平衡

[wangxin@hadoop102 sbin]$ ./start-balancer.sh
starting balancer, logging to /opt/module/hadoop-3.1.3/logs/hadoop-wangxin-balancer-hadoop102.out
Time Stamp               Iteration#  Bytes Already Moved  Bytes Left To Move  Bytes Being Moved

5.6.5 退役旧数据节点

添加白名单和黑名单
白名单和黑名单是hadoop管理集群主机的一种机制。
添加到白名单的主机节点,都允许访问NameNode,不在白名单的主机节点,都会被退出。添加到黑名单的主机节点,不允许访问NameNode,会在数据迁移后退出。
实际情况下,白名单用于确定允许访问NameNode的DataNode节点,内容配置一般与workers文件内容一致。 黑名单用于在集群运行过程中退役DataNode节点。

配置白名单和黑名单的具体步骤如下:
1)在NameNode节点的/opt/module/hadoop-3.1.3/etc/hadoop目录下分别创建whitelist 和blacklist文件

[wangxin@hadoop102 hadoop]$ pwd
/opt/module/hadoop-3.1.3/etc/hadoop
[wangxin@hadoop102 hadoop]$ touch whitelist
[wangxin@hadoop102 hadoop]$ touch blacklist

在whitelist中添加如下主机名称,假如集群正常工作的节点为102 103 104 105

hadoop102
hadoop103
hadoop104
hadoop105

黑名单暂时为空。

2)在hdfs-site.xml配置文件中增加dfs.hosts和 dfs.hosts.exclude配置参数

<!-- 白名单 -->
<property>
<name>dfs.hosts</name>
<value>/opt/module/hadoop-3.1.3/etc/hadoop/whitelist</value>
</property>
<!-- 黑名单 -->
<property>
<name>dfs.hosts.exclude</name>
<value>/opt/module/hadoop-3.1.3/etc/hadoop/blacklist</value>
</property>

3)分发配置文件whitelist,blacklist,hdfs-site.xml (注意:105节点也要发一份)

[wangxin@hadoop102 etc]$ xsync hadoop/
[wangxin@hadoop102 etc]$ rsync -av hadoop/ wangxin@hadoop105:/opt/module/hadoop-3.1.3/etc/hadoop/

4)重新启动集群(注意:105节点没有添加到workers,因此要单独起停)

[wangxin@hadoop102 hadoop-3.1.3]$ stop-dfs.sh
[wangxin@hadoop102 hadoop-3.1.3]$ start-dfs.sh
[wangxin@hadoop105 hadoop-3.1.3]$ hdfs –daemon start datanode

5)在web浏览器上查看目前正常工作的DN节点

黑名单退役
1)编辑/opt/module/hadoop-3.1.3/etc/hadoop目录下的blacklist文件

[wangxin@hadoop102 hadoop] vim blacklist

添加如下主机名称(要退役的节点)
hadoop105

2)分发blacklist到所有节点

[wangxin@hadoop102 etc]$ xsync hadoop/
[wangxin@hadoop102 etc]$ rsync -av hadoop/ wangxin@hadoop105:/opt/module/hadoop-3.1.3/etc/hadoop/

3)刷新NameNode、刷新ResourceManager

[wangxin@hadoop102 hadoop-3.1.3]$ hdfs dfsadmin -refreshNodes
Refresh nodes successful[wangxin@hadoop102 hadoop-3.1.3]$ yarn rmadmin -refreshNodes
17/06/24 14:55:56 INFO client.RMProxy: Connecting to ResourceManager at hadoop103/192.168.1.103:8033

4)检查Web浏览器,退役节点的状态为decommission in progress(退役中),说明数据节点正在复制块到其他节点

5)等待退役节点状态为decommissioned(所有块已经复制完成),停止该节点及节点资源管理器。注意:如果副本数是3,服役的节点小于等于3,是不能退役成功的,需要修改副本数后才能退役

[wangxin@hadoop105 hadoop-3.1.3]$ hdfs --daemon stop datanode
stopping datanode
[wangxin@hadoop105 hadoop-3.1.3]$ yarn --daemon stop nodemanager
stopping nodemanager

6)如果数据不均衡,可以用命令实现集群的再平衡

[wangxin@hadoop102 hadoop-3.1.3]$ sbin/start-balancer.sh
starting balancer, logging to /opt/module/hadoop-3.1.3/logs/hadoop-wangxin-balancer-hadoop102.out
Time Stamp               Iteration#  Bytes Already Moved  Bytes Left To Move  Bytes Being Moved

注意:不允许白名单和黑名单中同时出现同一个主机名称,既然使用了黑名单blacklist成功退役了hadoop105节点,因此要将白名单whitelist里面的hadoop105去掉

5.6.5 DataNode多目录配置

1)DataNode可以配置成多个目录,每个目录存储的数据不一样。即:数据不是副本

2)具体配置如下
(1)在hdfs-site.xml文件中添加如下内容

<property><name>dfs.datanode.data.dir</name>
<value>file://${hadoop.tmp.dir}/dfs/data1,file://${hadoop.tmp.dir}/dfs/data2</value>
</property>

(2)停止集群,删除三台节点的data和logs中所有数据。

[wangxin@hadoop102 hadoop-3.1.3]$ rm -rf data/ logs/
[wangxin@hadoop103 hadoop-3.1.3]$ rm -rf data/ logs/
[wangxin@hadoop104 hadoop-3.1.3]$ rm -rf data/ logs/

(3)格式化集群并启动。

[wangxin@hadoop102 hadoop-3.1.3]$ bin/hdfs namenode –format
[wangxin@hadoop102 hadoop-3.1.3]$ sbin/start-dfs.sh

(4)查看结果

[wangxin@hadoop102 dfs]$ ll
总用量 12
drwx------. 3 wangxin wangxin 4096 4月   4 14:22 data1
drwx------. 3 wangxin wangxin 4096 4月   4 14:22 data2
drwxrwxr-x. 3 wangxin wangxin 4096 12月 11 08:03 name1
drwxrwxr-x. 3 wangxin wangxin 4096 12月 11 08:03 name2

6. MapReduce

6.1 MapReduce概述

6.1.1 MapReduce定义

MapReduce是一个分布式运算程序的编程框架,是用户开发“基于Hadoop的数据分析应用”的核心框架。
MapReduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并行运行在一个Hadoop集群上。

6.1.2 MapReduce优缺点

优点:
1)MapReduce 易于编程
它简单的实现一些接口,就可以完成一个分布式程序,这个分布式程序可以分布到大量廉价的PC机器上运行。也就是说你写一个分布式程序,跟写一个简单的串行程序是一模一样的。就是因为这个特点使得MapReduce编程变得非常流行。
2)良好的扩展性
当你的计算资源不能得到满足的时候,你可以通过简单的增加机器来扩展它的计算能力。
3)高容错性
MapReduce设计的初衷就是使程序能够部署在廉价的PC机器上,这就要求它具有很高的容错性。比如其中一台机器挂了,它可以把上面的计算任务转移到另外一个节点上运行,不至于这个任务运行失败,而且这个过程不需要人工参与,而完全是由Hadoop内部完成的。
4)适合PB级以上海量数据的离线处理
可以实现上千台服务器集群并发工作,提供数据处理能力。

缺点:
1)不擅长实时计算
MapReduce无法像MySQL一样,在毫秒或者秒级内返回结果。
2)不擅长流式计算
流式计算的输入数据是动态的,而MapReduce的输入数据集是静态的,不能动态变化。这是因为MapReduce自身的设计特点决定了数据源必须是静态的。
3)不擅长DAG(有向无环图)计算
多个应用程序存在依赖关系,后一个应用程序的输入为前一个的输出。在这种情况下,MapReduce并不是不能做,而是使用后,每个MapReduce作业的输出结果都会写入到磁盘,会造成大量的磁盘IO,导致性能非常的低下。

6.1.3 MapReduce核心思想


(1)分布式的运算程序往往需要分成至少2个阶段。
(2)第一个阶段的MapTask并发实例,完全并行运行,互不相干。
(3)第二个阶段的ReduceTask并发实例互不相干,但是他们的数据依赖于上一个阶段的所有MapTask并发实例的输出。
(4)MapReduce编程模型只能包含一个Map阶段和一个Reduce阶段,如果用户的业务逻辑非常复杂,那就只能多个MapReduce程序,串行运行。
总结:分析WordCount数据流走向深入理解MapReduce核心思想。

6.1.4 MapReduce进程

一个完整的MapReduce程序在分布式运行时有三类实例进程:
(1)MrAppMaster:负责整个程序的过程调度及状态协调。
(2)MapTask:负责Map阶段的整个数据处理流程。
(3)ReduceTask:负责Reduce阶段的整个数据处理流程。

6.1.5 官方WordCount源码

采用反编译工具反编译源码,发现WordCount案例有Map类、Reduce类和驱动类。且数据的类型是Hadoop自身封装的序列化类型。

6.1.6 常用数据序列化类型

6.1.7 MapReduce编程规范

用户编写的程序分成三个部分:Mapper、Reducer和Driver。
1.Mapper阶段
(1)用户自定义的Mapper要继承自己的父类
(2)Mapper的输入数据是KV对的形式(KV的类型可自定义)
(3)Mapper中的业务逻辑写在map()方法中
(4)Mapper的输出数据是KV对的形式(KV的类型可自定义)
(5)map()方法(MapTask进程)对每一个<K,V>调用一次

2.Reducer阶段
(1)用户自定义的Reducer要继承自己的父类
(2)Reducer的输入数据类型对应Mapper的输出数据类型,也是KV
(3)Reducer的业务逻辑写在reduce()方法中
(4)ReduceTask进程对每一组相同k的<k,v>组调用一次reduce()方法

3.Driver阶段
相当于YARN集群的客户端,用于提交我们整个程序到YARN集群,提交的是封装了MapReduce程序相关运行参数的job对象

6.1.8 WordCount案例

需求:在给定的文本文件中统计输出每一个单词出现的总次数

1)环境准备
(1)打开Intellij, 创建maven工程
(2)在pom.xml文件中添加如下依赖

<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.12.0</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>3.1.3</version></dependency>
</dependencies>

(2)在项目的src/main/resources目录下,新建一个文件,命名为“log4j2.xml”,在文件中填入。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error" strict="true" name="XMLConfig"><Appenders><!-- 类型名为Console,名称为必须属性 --><Appender type="Console" name="STDOUT"><!-- 布局为PatternLayout的方式,输出样式为[INFO] [2018-01-22 17:34:01][org.test.Console]I'm here --><Layout type="PatternLayout"pattern="[%p] [%d{yyyy-MM-dd HH:mm:ss}][%c{10}]%m%n" /></Appender></Appenders><Loggers><!-- 可加性为false --><Logger name="test" level="info" additivity="false"><AppenderRef ref="STDOUT" /></Logger><!-- root loggerConfig设置 --><Root level="info"><AppenderRef ref="STDOUT" /></Root></Loggers></Configuration>

2)编写程序
(1)编写Mapper类

import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;public class WordcountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{Text k = new Text();IntWritable v = new IntWritable(1);@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {// 1 获取一行String line = value.toString();// 2 切割String[] words = line.split(" ");// 3 输出for (String word : words) {k.set(word);context.write(k, v);}}
}

(2)编写Reducer类

import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;public class WordcountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{int sum;
IntWritable v = new IntWritable();@Overrideprotected void reduce(Text key, Iterable<IntWritable> values,Context context) throws IOException, InterruptedException {// 1 累加求和sum = 0;for (IntWritable count : values) {sum += count.get();}// 2 输出v.set(sum);context.write(key,v);}
}

(3)编写Driver驱动类

import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;public class WordcountDriver {public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {// 1 获取配置信息以及获取job对象Configuration configuration = new Configuration();Job job = Job.getInstance(configuration);// 2 关联本Driver程序的jarjob.setJarByClass(WordcountDriver.class);// 3 关联Mapper和Reducer的jarjob.setMapperClass(WordcountMapper.class);job.setReducerClass(WordcountReducer.class);// 4 设置Mapper输出的kv类型job.setMapOutputKeyClass(Text.class);job.setMapOutputValueClass(IntWritable.class);// 5 设置最终输出kv类型job.setOutputKeyClass(Text.class);job.setOutputValueClass(IntWritable.class);// 6 设置输入和输出路径FileInputFormat.setInputPaths(job, new Path(args[0]));FileOutputFormat.setOutputPath(job, new Path(args[1]));// 7 提交jobboolean result = job.waitForCompletion(true);System.exit(result ? 0 : 1);}
}

3)本地测试
(1)需要首先配置好HADOOP_HOME变量以及Windows运行依赖
(2)在IDEA/Eclipse上运行程序

4)集群上测试
(0)用maven打jar包,需要添加的打包插件依赖

 <build><plugins><plugin><artifactId>maven-compiler-plugin</artifactId><version>3.6.1</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin><plugin><artifactId>maven-assembly-plugin</artifactId><configuration><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs></configuration><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin></plugins></build>

注意:如果工程上显示红叉。在项目上右键->maven->Reimport即可。
(1)将程序打成jar包,然后拷贝到Hadoop集群中
步骤详情:右键->Run as->maven install。等待编译完成就会在项目的target文件夹中生成jar包。如果看不到。在项目上右键->Refresh,即可看到。修改不带依赖的jar包名称为wc.jar,并拷贝该jar包到Hadoop集群。
(2)启动Hadoop集群
(3)执行WordCount程序

[wangxin@hadoop102 software]$ hadoop jar  wc.jarcom.wangxin.wordcount.WordcountDriver /user/wangxin/input /user/wangxin/output

5)在Windows上向集群提交任务
(1)添加必要配置信息

public class WordcountDriver {public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {// 1 获取配置信息以及封装任务Configuration configuration = new Configuration();//设置HDFS NameNode的地址configuration.set("fs.defaultFS", "hdfs://hadoop102:9820");// 指定MapReduce运行在Yarn上configuration.set("mapreduce.framework.name","yarn");// 指定mapreduce可以在远程集群运行configuration.set("mapreduce.app-submission.cross-platform","true");//指定Yarn resourcemanager的位置configuration.set("yarn.resourcemanager.hostname","hadoop103");Job job = Job.getInstance(configuration);// 2 设置jar加载路径job.setJar("F:\\idea_project\\MapReduce\\target\\MapReduce-1.0-SNAPSHOT.jar");// 3 设置map和reduce类job.setMapperClass(WordcountMapper.class);job.setReducerClass(WordcountReducer.class);// 4 设置map输出job.setMapOutputKeyClass(Text.class);job.setMapOutputValueClass(IntWritable.class);// 5 设置最终输出kv类型job.setOutputKeyClass(Text.class);job.setOutputValueClass(IntWritable.class);// 6 设置输入和输出路径FileInputFormat.setInputPaths(job, new Path(args[0]));FileOutputFormat.setOutputPath(job, new Path(args[1]));// 7 提交boolean result = job.waitForCompletion(true);System.exit(result ? 0 : 1);}
}

(2)编辑任务配置
1)检查第一个参数Main class是不是我们要运行的类的全类名,如果不是的话一定要修改!
2)在VM options后面加上 :-DHADOOP_USER_NAME=wangxin
3)在Program arguments后面加上两个参数分别代表输入输出路径,两个参数之间用空格隔开。如:hdfs://hadoop102:9820/input hdfs://hadoop102:9820/output

(3)打包,并将Jar包设置到Driver中

public class WordcountDriver {public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {// 1 获取配置信息以及封装任务Configuration configuration = new Configuration();configuration.set("fs.defaultFS", "hdfs://hadoop102:9820");configuration.set("mapreduce.framework.name","yarn");configuration.set("mapreduce.app-submission.cross-platform","true");configuration.set("yarn.resourcemanager.hostname","hadoop103");Job job = Job.getInstance(configuration);// 2 设置jar加载路径
//job.setJarByClass(WordCountDriver.class);job.setJar("D:\IdeaProjects\mapreduce\target\mapreduce-1.0-SNAPSHOT.jar");// 3 设置map和reduce类job.setMapperClass(WordcountMapper.class);job.setReducerClass(WordcountReducer.class);// 4 设置map输出job.setMapOutputKeyClass(Text.class);job.setMapOutputValueClass(IntWritable.class);// 5 设置最终输出kv类型job.setOutputKeyClass(Text.class);job.setOutputValueClass(IntWritable.class);// 6 设置输入和输出路径FileInputFormat.setInputPaths(job, new Path(args[0]));FileOutputFormat.setOutputPath(job, new Path(args[1]));// 7 提交boolean result = job.waitForCompletion(true);System.exit(result ? 0 : 1);}
}

(4)提交并查看结果

6.2 Hadoop序列化

6.2.1 序列化概述

序列化就是把内存中的对象,转换成字节序列(或其他数据传输协议)以便于存储到磁盘(持久化)和网络传输。

反序列化就是将收到字节序列(或其他数据传输协议)或者是磁盘的持久化数据,转换成内存中的对象。

一般来说,“活的”对象只生存在内存里,关机断电就没有了。而且“活的”对象只能由本地的进程使用,不能被发送到网络上的另外一台计算机。 然而序列化可以存储“活的”对象,可以将“活的”对象发送到远程计算机。

Java的序列化是一个重量级序列化框架(Serializable),一个对象被序列化后,会附带很多额外的信息(各种校验信息,Header,继承体系等),不便于在网络中高效传输。所以,Hadoop自己开发了一套序列化机制(Writable)。

Hadoop序列化特点:(1)紧凑 :高效使用存储空间。(2)快速:读写数据的额外开销小。(3)可扩展:随着通信协议的升级而可升级(4)互操作:支持多语言的交互

在企业开发中往往常用的基本序列化类型不能满足所有需求,比如在Hadoop框架内部传递一个bean对象,那么该对象就需要实现序列化接口。
具体实现bean对象序列化步骤如下7步。(以下代码是示例代码,自己需根据实际情况编写)
(1)必须实现Writable接口
(2)反序列化时,需要反射调用空参构造函数,所以必须有空参构造

public FlowBean() {super();
}

(3)重写序列化方法

@Override
public void write(DataOutput out) throws IOException {out.writeLong(upFlow);out.writeLong(downFlow);out.writeLong(sumFlow);
}

(4)重写反序列化方法

@Override
public void readFields(DataInput in) throws IOException {upFlow = in.readLong();downFlow = in.readLong();sumFlow = in.readLong();
}

(5)注意反序列化的顺序和序列化的顺序完全一致
(6)要想把结果显示在文件中,需要重写toString(),可用”\t”分开,方便后续用。
(7)如果需要将自定义的bean放在key中传输,则还需要实现Comparable接口,因为MapReduce框中的Shuffle过程要求对key必须能排序。

@Override
public int compareTo(FlowBean o) {// 倒序排列,从大到小return this.sumFlow > o.getSumFlow() ? -1 : 1;
}

6.3 MapReduce框架原理

6.3.1 InputFormat数据输入

切片与MapTask并行度决定机制

1)问题引出
MapTask的并行度决定Map阶段的任务处理并发度,进而影响到整个Job的处理速度。
思考:1G的数据,启动8个MapTask,可以提高集群的并发处理能力。那么1K的数据,也启动8个MapTask,会提高集群性能吗?MapTask并行任务是否越多越好呢?哪些因素影响了MapTask并行度?

2)MapTask并行度决定机制
数据块:Block是HDFS物理上把数据分成一块一块。数据块是HDFS存储数据单位。
数据切片:数据切片只是在逻辑上对输入进行分片,并不会在磁盘上将其切分成片进行存储。数据切片是MapReduce程序计算输入数据的单位,一个切片会对应启动一个MapTask。

Job提交流程源码详解

waitForCompletion()submit();// 1建立连接connect();   // 1)创建提交Job的代理new Cluster(getConfiguration());// (1)判断是本地运行环境还是yarn集群运行环境initialize(jobTrackAddr, conf); // 2 提交job
submitter.submitJobInternal(Job.this, cluster)// 1)创建给集群提交数据的Stag路径Path jobStagingArea = JobSubmissionFiles.getStagingDir(cluster, conf);// 2)获取jobid ,并创建Job路径JobID jobId = submitClient.getNewJobID();// 3)拷贝jar包到集群
copyAndConfigureFiles(job, submitJobDir);   rUploader.uploadFiles(job, jobSubmitDir);// 4)计算切片,生成切片规划文件
writeSplits(job, submitJobDir);maps = writeNewSplits(job, jobSubmitDir);input.getSplits(job);// 5)向Stag路径写XML配置文件
writeConf(conf, submitJobFile);conf.writeXml(out);// 6)提交Job,返回提交状态
status = submitClient.submitJob(jobId, submitJobDir.toString(), job.getCredentials());


FileInputFormat切片源码解析

FileInputFormat切片机制

(1)简单地按照文件的内容长度进行切片
(2)切片大小,默认等于Block大小
(3)切片时不考虑数据集整体,而是逐个针对每一个文件单独切片

TextInputFormat

在运行MapReduce程序时,输入的文件格式包括:基于行的日志文件、二进制格式文件、数据库表等。那么,针对不同的数据类型,MapReduce是如何读取这些数据的呢?

FileInputFormat常见的接口实现类包括:TextInputFormat、KeyValueTextInputFormat、NLineInputFormat、CombineTextInputFormat和自定义InputFormat等。

TextInputFormat是默认的FileInputFormat实现类。按行读取每条记录。键是存储该行在整个文件中的起始字节偏移量, LongWritable类型。值是这行的内容,不包括任何行终止符(换行符和回车符),Text类型。

CombineTextInputFormat切片机制

框架默认的TextInputFormat切片机制是对任务按文件规划切片,不管文件多小,都会是一个单独的切片,都会交给一个MapTask,这样如果有大量小文件,就会产生大量的MapTask,处理效率极其低下
1)应用场景:
CombineTextInputFormat用于小文件过多的场景,它可以将多个小文件从逻辑上规划到一个切片中,这样,多个小文件就可以交给一个MapTask处理。

2)虚拟存储切片最大值设置
CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);// 4m
注意:虚拟存储切片最大值设置最好根据实际的小文件大小情况来设置具体的值。

3)切片机制
生成切片过程包括:虚拟存储过程和切片过程二部分。

6.3.2 MapReduce工作流程



上面的流程是整个MapReduce最全工作流程,但是Shuffle过程只是从第7步开始到第16步结束,具体Shuffle过程详解,如下:
(1)MapTask收集我们的map()方法输出的kv对,放到内存缓冲区中
(2)从内存缓冲区不断溢出本地磁盘文件,可能会溢出多个文件
(3)多个溢出文件会被合并成大的溢出文件
(4)在溢出过程及合并的过程中,都要调用Partitioner进行分区和针对key进行排序
(5)ReduceTask根据自己的分区号,去各个MapTask机器上取相应的结果分区数据
(6)ReduceTask会抓取到同一个分区的来自不同MapTask的结果文件,ReduceTask会将这些文件再进行合并(归并排序)
(7)合并成大文件后,Shuffle的过程也就结束了,后面进入ReduceTask的逻辑运算过程(从文件中取出一个一个的键值对Group,调用用户自定义的reduce()方法)
注意:
(1)Shuffle中的缓冲区大小会影响到MapReduce程序的执行效率,原则上说,缓冲区越大,磁盘io的次数越少,执行速度就越快。
(2)缓冲区的大小可以通过参数调整,参数:mapreduce.task.io.sort.mb默认100M

6.3.3 Shuffle机制

Map方法之后,Reduce方法之前的数据处理过程称之为Shuffle。

shuffle是MR执行过程中很重要,也是必不可少的一个过程。当MapTask执行完map() 方法后通过context对象写数据的时候开始执行shuffle过程。首先数据先从Map端写入到环形缓冲区内,写出的数据会根据分区规则进入到指定的分区,并且同时在内存中进行区内排序。环形缓冲区默认大小为100M,当数据的写入的容量达到缓冲区大小的80%,数据开始向磁盘溢写,如果数据很多的情况下 可能发生N次溢写,这样在磁盘上就会产生多个溢写文件,并且保证每个溢写文件中区内数据是有序的,接下来在磁盘中会把多次溢写的文件归并到一起形成一个文件,这归并的过程中会根据相同的分区进行归并排序,保证归并完的文件区内是有序的,到此shuffle过程在Map端就完成了。 接着Map端输出的数据会作为Reduce端的输入数据再次进行汇总操作,此时ReduceTask任务会把每一个MapTask中计算完的相同的分区的数据拷贝到ReduceTask的内存中,如果内存放不下,开始写入磁盘,再接着就是对数据进行归并排序,排完序还要根据相同key进行分组,将来一组相同的key对应的values调用一次reduce方法。如果有多个分区就会产生多个ReduceTask来处理,处理的逻辑都一样。

Partition分区

要求将统计结果按照条件输出到不同文件中(分区)。比如:将统计结果按照手机归属地不同省份输出到不同文件中(分区)

默认Partitioner分区-HashPartition

public class HashPartitioner<K, V> extends Partitioner<K, V> {public int getPartition(K key, V value, int numReduceTasks) {return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;}
}

默认分区是根据key的hashCode对ReduceTasks个数取模得到的。用户没法控制哪个key存储到哪个分区

我们也可以编写自定义分区,自定义Partitioner步骤:
(1)自定义类继承Partitioner,重写getPartition()方法

public class CustomPartitioner extends Partitioner<Text, FlowBean> {@Overridepublic int getPartition(Text key, FlowBean value, int numPartitions) {// 控制分区代码逻辑… …return partition;}
}

(2)在Job驱动中,设置自定义Partitioner
job.setPartitionerClass(CustomPartitioner.class);

(3)自定义Partition后,要根据自定义Partitioner的逻辑设置相应数量的ReduceTask
job.setNumReduceTasks(5);

分区总结
(1)如果ReduceTask的数量 > getPartition的结果数,则会多产生几个空的输出文件part-r-000xx;
(2)如果1 < ReduceTask的数量 < getPartition的结果数,则有一部分分区数据无处安放,会Exception;
(3)如果ReduceTask的数量=1,则不管MapTask端输出多少个分区文件,最终结果都交给这一个ReduceTask,最终也就只会产生一个结果文件 part-r-00000;
(4)分区号必须从零开始,逐一累加。

例如:假设自定义分区数为5,则
(1)job.setNumReduceTasks(1); 会正常运行,只不过会产生一个输出文件

(2)job.setNumReduceTasks(2); 会报错

(3)job.setNumReduceTasks(6); 大于5,程序会正常运行,会产生空文件

WritableComparable排序

排序是MapReduce框架中最重要的操作之一。MapTask和ReduceTask均会对数据按照key进行排序。该操作属于Hadoop的默认行为。任何应用程序中的数据均会被排序,而不管逻辑上是否需要。

默认排序是按照字典顺序排序,且实现该排序的方法是快速排序

对于MapTask,它会将处理的结果暂时放到环形缓冲区中,当环形缓冲区使用率达到一定阈值后,再对缓冲区中的数据进行一次快速排序,并将这些有序数据溢写到磁盘上,而当数据处理完毕后,它会对磁盘上所有文件进行归并排序。

对于ReduceTask,它从每个MapTask上远程拷贝相应的数据文件,如果文件大小超过一定阈值,则溢写磁盘上,否则存储在内存中。如果磁盘上文件数目达到一定阈值,则进行一次归并排序以生成一个更大文件;如果内存中文件大小或者数目超过一定阈值,则进行一次合并后将数据溢写到磁盘上。当所有数据拷贝完毕后,ReduceTask统一对内存和磁盘上的所有数据进行一次归并排序。

排序分类
(1)部分排序
MapReduce根据输入记录的键对数据集排序。保证输出的每个文件内部有序。

(2)全排序
最终输出结果只有一个文件,且文件内部有序。实现方式是只设置一个ReduceTask。但该方法在处理大型文件时效率极低,因为一台机器处理所有文件,完全丧失了MapReduce所提供的并行架构。

(3)辅助排序:(GroupingComparator分组)
在Reduce端对key进行分组。应用于:在接收的key为bean对象时,想让一个或几个字段相同(全部字段比较不相同)的key进入到同一个reduce方法时,可以采用分组排序。

(4)二次排序
在自定义排序过程中,如果compareTo中的判断条件为两个即为二次排序。

自定义排序WritableComparable原理分析
bean对象做为key传输,需要实现WritableComparable接口重写compareTo方法,就可以实现排序。

Combiner合并

(1)Combiner是MR程序中Mapper和Reducer之外的一种组件。
(2)Combiner组件的父类就是Reducer。
(3)Combiner和Reducer的区别在于运行的位置
Combiner是在每一个MapTask所在的节点运行;
Reducer是接收全局所有Mapper的输出结果;
(4)Combiner的意义就是对每一个MapTask的输出进行局部汇总,以减小网络传输量。
(5)Combiner能够应用的前提是不能影响最终的业务逻辑,而且,Combiner的输出kv应该跟Reducer的输入kv类型要对应起来。

6.3.4 MapTask工作机制


(1)Read阶段:MapTask通过InputFormat获得的RecordReader,从输入InputSplit中解析出一个个key/value。

(2)Map阶段:该节点主要是将解析出的key/value交给用户编写map()函数处理,并产生一系列新的key/value。

(3)Collect收集阶段:在用户编写map()函数中,当数据处理完成后,一般会调用OutputCollector.collect()输出结果。在该函数内部,它会将生成的key/value分区(调用Partitioner),并写入一个环形内存缓冲区中。

(4)Spill阶段:即“溢写”,当环形缓冲区满后,MapReduce会将数据写到本地磁盘上,生成一个临时文件。需要注意的是,将数据写入本地磁盘之前,先要对数据进行一次本地排序,并在必要时对数据进行合并、压缩等操作。
溢写阶段详情:
步骤1:利用快速排序算法对缓存区内的数据进行排序,排序方式是,先按照分区编号Partition进行排序,然后按照key进行排序。这样,经过排序后,数据以分区为单位聚集在一起,且同一分区内所有数据按照key有序。
步骤2:按照分区编号由小到大依次将每个分区中的数据写入任务工作目录下的临时文件output/spillN.out(N表示当前溢写次数)中。如果用户设置了Combiner,则写入文件之前,对每个分区中的数据进行一次聚集操作。
步骤3:将分区数据的元信息写到内存索引数据结构SpillRecord中,其中每个分区的元信息包括在临时文件中的偏移量、压缩前数据大小和压缩后数据大小。如果当前内存索引大小超过1MB,则将内存索引写到文件output/spillN.out.index中。

(5)Merge阶段:当所有数据处理完成后,MapTask对所有临时文件进行一次合并,以确保最终只会生成一个数据文件。
当所有数据处理完后,MapTask会将所有临时文件合并成一个大文件,并保存到文件output/file.out中,同时生成相应的索引文件output/file.out.index。
在进行文件合并过程中,MapTask以分区为单位进行合并。对于某个分区,它将采用多轮递归合并的方式。每轮合并mapreduce.task.io.sort.factor(默认10)个文件,并将产生的文件重新加入待合并列表中,对文件排序后,重复以上过程,直到最终得到一个大文件。
让每个MapTask最终只生成一个数据文件,可避免同时打开大量文件和同时读取大量小文件产生的随机读取带来的开销。

6.3.5 ReduceTask工作机制


(1)Copy阶段:ReduceTask从各个MapTask上远程拷贝一片数据,并针对某一片数据,如果其大小超过一定阈值,则写到磁盘上,否则直接放到内存中。
(2)Merge阶段:在远程拷贝数据的同时,ReduceTask启动了两个后台线程对内存和磁盘上的文件进行合并,以防止内存使用过多或磁盘上文件过多。
(3)Sort阶段:按照MapReduce语义,用户编写reduce()函数输入数据是按key进行聚集的一组数据。为了将key相同的数据聚在一起,Hadoop采用了基于排序的策略。由于各个MapTask已经实现对自己的处理结果进行了局部排序,因此,ReduceTask只需对所有数据进行一次归并排序即可。
(4)Reduce阶段:reduce()函数将计算结果写到HDFS上。

6.3.6 OutputFormat数据输出

OutputFormat是MapReduce输出的基类,所有实现MapReduce输出都实现了 OutputFormat接口。下面是几种常见的OutputFormat实现类。

1.文本输出TextOutputFormat
默认的输出格式是TextOutputFormat,它把每条记录写为文本行。它的键和值可以是任意类型,因为TextOutputFormat调用toString()方法把它们转换为字符串。

2.SequenceFileOutputFormat
将SequenceFileOutputFormat输出作为后续 MapReduce任务的输入,这便是一种好的输出格式,因为它的格式紧凑,很容易被压缩。

3.自定义OutputFormat
根据用户需求,自定义实现输出。
使用场景:为了实现控制最终文件的输出路径和输出格式,可以自定义OutputFormat。
自定义OutputFormat步骤:
(1)自定义一个类继承FileOutputFormat。
(2)改写RecordWriter,具体改写输出数据的方法write()。

6.3.7 Join多种应用

Reduce Join工作原理

Map端的主要工作:为来自不同表或文件的key/value对,打标签以区别不同来源的记录。然后用连接字段作为key,其余部分和新加的标志作为value,最后进行输出。

Reduce端的主要工作:在Reduce端以连接字段作为key的分组已经完成,我们只需要在每一个分组当中将那些来源于不同文件的记录(在Map阶段已经打标志)分开,最后进行合并就ok了。

Map Join
1)使用场景
Map Join适用于一张表十分小、一张表很大的场景。

2)优点
思考:在Reduce端处理过多的表,非常容易产生数据倾斜。怎么办?
在Map端缓存多张表,提前处理业务逻辑,这样增加Map端业务,减少Reduce端数据的压力,尽可能的减少数据倾斜。

3)具体办法:采用DistributedCache
(1)在Mapper的setup阶段,将文件读取到缓存集合中。
(2)在Driver驱动类中加载缓存。
//缓存普通文件到Task运行节点。
job.addCacheFile(new URI(“file:///e:/cache/pd.txt”));
//如果是集群运行,需要设置HDFS路径
job.addCacheFile(new URI(“hdfs://hadoop102:9820/cache/pd.txt”));

6.3.8 计数器应用

Hadoop为每个作业维护若干内置计数器,以描述多项指标。例如,某些计数器记录已处理的字节数和记录数,使用户可监控已处理的输入数据量和已产生的输出数据量。

1.计数器API

(1)采用枚举的方式统计计数

enum MyCounter{MALFORORMED,NORMAL}
//对枚举定义的自定义计数器加1
context.getCounter(MyCounter.MALFORORMED).increment(1);

(2)采用计数器组、计数器名称的方式统计

context.getCounter("counterGroup", "counter").increment(1);

组名和计数器名称随便起,但最好有意义

(3)计数结果在程序运行后的控制台上查看。

7. Yarn资源调度器

Yarn是一个资源调度平台,负责为运算程序提供服务器运算资源,相当于一个分布式的操作系统平台,而MapReduce等运算程序则相当于运行于操作系统之上的应用程序。

7.1 Yarn基本架构

YARN主要由ResourceManager、NodeManager、ApplicationMaster和Container等组件构成。

7.2 Yarn工作机制


(1)MR程序提交到客户端所在的节点。
(2)YarnRunner向ResourceManager申请一个Application。
(3)RM将该应用程序的资源路径返回给YarnRunner。
(4)该程序将运行所需资源提交到HDFS上。
(5)程序资源提交完毕后,申请运行mrAppMaster。
(6)RM将用户的请求初始化成一个Task。
(7)其中一个NodeManager领取到Task任务。
(8)该NodeManager创建容器Container,并产生MRAppmaster。
(9)Container从HDFS上拷贝资源到本地。
(10)MRAppmaster向RM 申请运行MapTask资源。
(11)RM将运行MapTask任务分配给另外两个NodeManager,另两个NodeManager分别领取任务并创建容器。
(12)MR向两个接收到任务的NodeManager发送程序启动脚本,这两个NodeManager分别启动MapTask,MapTask对数据分区排序。
(13)MrAppMaster等待所有MapTask运行完毕后,向RM申请容器,运行ReduceTask。
(14)ReduceTask向MapTask获取相应分区的数据。
(15)程序运行完毕后,MR会向RM申请注销自己。

7.3 资源调度器

目前,Hadoop作业调度器主要有三种:FIFO、Capacity Scheduler和Fair Scheduler。Hadoop3.1.3默认的资源调度器是Capacity Scheduler。
具体设置详见:yarn-default.xml文件

<property><description>The class to use as the resource scheduler.</description><name>yarn.resourcemanager.scheduler.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler</value>
</property>

1)先进先出调度器(FIFO)

Hadoop最初设计目的是支持大数据批处理作业,如日志挖掘、Web索引等作业,
为此,Hadoop仅提供了一个非常简单的调度机制:FIFO,即先来先服务,在该调度机制下,所有作业被统一提交到一个队列中,Hadoop按照提交顺序依次运行这些作业。
但随着Hadoop的普及,单个Hadoop集群的用户量越来越大,不同用户提交的应用程序往往具有不同的服务质量要求,典型的应用有以下几种:
批处理作业:这种作业往往耗时较长,对时间完成一般没有严格要求,如数据挖掘、机器学习等方面的应用程序。
交互式作业:这种作业期望能及时返回结果,如SQL查询(Hive)等。
生产性作业:这种作业要求有一定量的资源保证,如统计值计算、垃圾数据分析等。
此外,这些应用程序对硬件资源需求量也是不同的,如过滤、统计类作业一般为CPU密集型作业,而数据挖掘、机器学习作业一般为I/O密集型作业。因此,简单的FIFO调度策略不仅不能满足多样化需求,也不能充分利用硬件资源。

2)容量调度器(Capacity Scheduler)

Capacity Scheduler Capacity Scheduler 是Yahoo开发的多用户调度器,它以队列为单位划分资源,每个队列可设定一定比例的资源最低保证和使用上限,同时,每个用户也可设定一定的资源使用上限以防止资源滥用。而当一个队列的资源有剩余时,可暂时将剩余资源共享给其他队列。
总之,Capacity Scheduler 主要有以下几个特点:
①容量保证。管理员可为每个队列设置资源最低保证和资源使用上限,而所有提交到该队列的应用程序共享这些资源。
②灵活性,如果一个队列中的资源有剩余,可以暂时共享给那些需要资源的队列,而一旦该队列有新的应用程序提交,则其他队列借调的资源会归还给该队列。这种资源灵活分配的方式可明显提高资源利用率。
③多重租赁。支持多用户共享集群和多应用程序同时运行。为防止单个应用程序、用户或者队列独占集群中的资源,管理员可为之增加多重约束(比如单个应用程序同时运行的任务数等)。
④安全保证。每个队列有严格的ACL列表规定它的访问用户,每个用户可指定哪些用户允许查看自己应用程序的运行状态或者控制应用程序(比如杀死应用程序)。此外,管理员可指定队列管理员和集群系统管理员。
⑤动态更新配置文件。管理员可根据需要动态修改各种配置参数,以实现在线集群管理。

3)公平调度器(Fair Scheduler)

Fair Scheduler Fair Schedulere是Facebook开发的多用户调度器。
公平调度器的目的是让所有的作业随着时间的推移,都能平均地获取等同的共享资源。当有作业提交上来,系统会将空闲的资源分配给新的作业,每个任务大致上会获取平等数量的资源。和传统的调度策略不同的是它会让小的任务在合理的时间完成,同时不会让需要长时间运行的耗费大量资源的任务挨饿!
同Capacity Scheduler类似,它以队列为单位划分资源,每个队列可设定一定比例的资源最低保证和使用上限,同时,每个用户也可设定一定的资源使用上限以防止资源滥用;当一个队列的资源有剩余时,可暂时将剩余资源共享给其他队列。

7.4 容量调度器多队列提交案例

Yarn默认的容量调度器是一条单队列的调度器,在实际使用中会出现单个任务阻塞整个队列的情况。同时,随着业务的增长,公司需要分业务限制集群使用率。这就需要我们按照业务种类配置多条任务队列。

默认Yarn的配置下,容量调度器只有一条Default队列。在capacity-scheduler.xml中可以配置多条队列,并降低default队列资源占比:

<!-- 指定多队列,增加hive队列 -->
<property><name>yarn.scheduler.capacity.root.queues</name><value>default,hive</value><description>The queues at the this level (root is the root queue).</description>
</property><!-- 降低default队列资源额定容量为40%,默认100% -->
<property><name>yarn.scheduler.capacity.root.default.capacity</name><value>40</value>
</property><!-- 降低default队列资源最大容量为60%,默认100% -->
<property><name>yarn.scheduler.capacity.root.default.maximum-capacity</name><value>60</value>
</property>

同时为新加队列添加必要属性:

<!-- 指定hive队列的资源额定容量 -->
<property><name>yarn.scheduler.capacity.root.hive.capacity</name><value>60</value>
</property><property><name>yarn.scheduler.capacity.root.hive.user-limit-factor</name><value>1</value>
</property><!-- 指定hive队列的资源最大容量 -->
<property><name>yarn.scheduler.capacity.root.hive.maximum-capacity</name><value></value>
</property><property><name>yarn.scheduler.capacity.root.hive.state</name><value>RUNNING</value>
</property><property><name>yarn.scheduler.capacity.root.hive.acl_submit_applications</name><value>*</value>
</property><property><name>yarn.scheduler.capacity.root.hive.acl_administer_queue</name><value>*</value>
</property><property><name>yarn.scheduler.capacity.root.hive.acl_application_max_priority</name><value>*</value>
</property><property><name>yarn.scheduler.capacity.root.hive.maximum-application-lifetime</name><value>-1</value>
</property><property><name>yarn.scheduler.capacity.root.hive.default-application-lifetime</name><value>-1</value>
</property>

在配置完成后,重启Yarn或者执行yarn rmadmin -refreshQueues刷新队列,就可以看到两条队列:

默认的任务提交都是提交到default队列的。如果希望向其他队列提交任务,需要在Driver中声明:configuration.set(“mapreduce.job.queuename”,“hive”);

这样,这个任务在集群提交时,就会提交到hive队列

8. Hadoop数据压缩

8.1 概述

压缩技术能够有效减少底层存储系统(HDFS)读写字节数。压缩提高了网络带宽和磁盘空间的效率。在运行MR程序时,I/O操作、网络数据传输、 Shuffle和Merge要花大量的时间,尤其是数据规模很大和工作负载密集的情况下,因此,使用数据压缩显得非常重要。

鉴于磁盘I/O和网络带宽是Hadoop的宝贵资源,数据压缩对于节省资源、最小化磁盘I/O和网络传输非常有帮助。可以在任意MapReduce阶段启用压缩。不过,尽管压缩与解压操作的CPU开销不高,其性能的提升和资源的节省并非没有代价。

压缩策略和原则

压缩是提高Hadoop运行效率的一种优化策略。
通过对Mapper、Reducer运行过程的数据进行压缩,以减少磁盘IO,提高MR程序运行速度。
注意:采用压缩技术减少了磁盘IO,但同时增加了CPU运算负担。所以,压缩特性运用得当能提高性能,但运用不当也可能降低性能。

压缩基本原则:
(1)运算密集型的job,少用压缩
(2)IO密集型的job,多用压缩

MR支持的压缩编码


为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器,如下表所示。

压缩性能的比较

8.2 压缩方式选择

Gzip压缩
优点:压缩率比较高,而且压缩/解压速度也比较快;Hadoop本身支持,在应用中处理Gzip格式的文件就和直接处理文本一样;大部分Linux系统都自带Gzip命令,使用方便。

缺点:不支持Split。

应用场景:当每个文件压缩之后在130M以内的(1个块大小内),都可以考虑用Gzip压缩格式。例如说一天或者一个小时的日志压缩成一个Gzip文件

Bzip2压缩
优点:支持Split;具有很高的压缩率,比Gzip压缩率都高;Hadoop本身自带,使用方便。

缺点:压缩/解压速度慢。

应用场景:适合对速度要求不高,但需要较高的压缩率的时候;或者输出之后的数据比较大,处理之后的数据需要压缩存档减少磁盘空间并且以后数据用得比较少的情况;或者对单个很大的文本文件想压缩减少存储空间,同时又需要支持Split,而且兼容之前的应用程序的情况。

Lzo压缩
优点:压缩/解压速度也比较快,合理的压缩率;支持Split,是Hadoop中最流行的压缩格式;可以在Linux系统下安装lzop命令,使用方便。

缺点:压缩率比Gzip要低一些;Hadoop本身不支持,需要安装;在应用中对Lzo格式的文件需要做一些特殊处理(为了支持Split需要建索引,还需要指定InputFormat为Lzo格式)。

应用场景:一个很大的文本文件,压缩之后还大于200M以上的可以考虑,而且单个文件越大,Lzo优点越越明显。

Snappy压缩
优点:高速压缩速度和合理的压缩率。

缺点:不支持Split;压缩率比Gzip要低;Hadoop本身不支持,需要安装。

应用场景:当MapReduce作业的Map输出的数据比较大的时候,作为Map到Reduce的中间数据的压缩格式;或者作为一个MapReduce作业的输出和另外一个MapReduce作业的输入。

8.3 压缩位置选择

压缩可以在MapReduce作用的任意阶段启用。

8.4 压缩参数配置

要在Hadoop中启用压缩,可以配置如下参数:

9. Hadoop优化

9.1 MapReduce 跑的慢的原因

MapReduce 程序效率的瓶颈在于两点:
1.计算机性能
CPU、内存、磁盘健康、网络

2.I/O 操作优化
(1)数据倾斜
(2)Map和Reduce数设置不合理
(3)Map运行时间太长,导致Reduce等待过久
(4)小文件过多
(5)大量的不可切片的超大压缩文件
(6)Spill次数过多
(7)Merge次数过多等。

9.2 MapReduce优化方法

MapReduce优化方法主要从六个方面考虑:数据输入、Map阶段、Reduce阶段、IO传输、数据倾斜问题和常用的调优参数。

数据输入
(1)合并小文件:在执行MR任务前将小文件进行合并,大量的小文件会产生大量的Map任务,增大Map任务装载次数,而任务的装载比较耗时,从而导致MR运行较慢。
(2)采用CombineTextInputFormat来作为输入,解决输入端大量小文件场景。

Map阶段

(1)减少溢写(Spill)次数:通过调整mapreduce.task.io.sort.mb及mapreduce.map.sort.spill.percent参数值,增大触发Spill的内存上限,减少Spill次数,从而减少磁盘IO。

(2)减少合并(Merge)次数:通过调整mapreduce.task.io.sort.factor参数,增大Merge的文件数目,减少Merge的次数,从而缩短MR处理时间。

(3)在Map之后,不影响业务逻辑前提下,先进行Combine处理,减少 I/O。

Reduce阶段
(1)合理设置Map和Reduce数:两个都不能设置太少,也不能设置太多。太少,会导致Task等待,延长处理时间;太多,会导致Map、Reduce任务间竞争资源,造成处理超时等错误。

(2)设置Map、Reduce共存:
调整mapreduce.job.reduce.slowstart.completedmaps参数,使Map运行到一定程度后,Reduce也开始运行,减少Reduce的等待时间。

(3)规避使用Reduce:因为Reduce在用于连接数据集的时候将会产生大量的网络消耗。

(4)合理设置Reduce端的Buffer:默认情况下,数据达到一个阈值的时候,Buffer中的数据就会写入磁盘,然后Reduce会从磁盘中获得所有的数据。也就是说,Buffer和Reduce是没有直接关联的,中间多次写磁盘->读磁盘的过程,既然有这个弊端,那么就可以通过参数来配置,使得Buffer中的一部分数据可以直接输送到Reduce,从而减少IO开销:mapreduce.reduce.input.buffer.percent,默认为0.0。当值大于0的时候,会保留指定比例的内存读Buffer中的数据直接拿给Reduce使用。这样一来,设置Buffer需要内存,读取数据需要内存,Reduce计算也要内存,所以要根据作业的运行情况进行调整。

IO传输

1)采用数据压缩的方式,减少网络IO的的时间。安装Snappy和LZO压缩编码器。

2)使用SequenceFile二进制文件。

数据倾斜问题
1.数据倾斜现象
数据频率倾斜——某一个区域的数据量要远远大于其他区域。
数据大小倾斜——部分记录的大小远远大于平均值。

2.减少数据倾斜的方法
方法1:抽样和范围分区
可以通过对原始数据进行抽样得到的结果集来预设分区边界值。

方法2:自定义分区
基于输出键的背景知识进行自定义分区。例如,如果Map输出键的单词来源于一本书。且其中某几个专业词汇较多。那么就可以自定义分区将这这些专业词汇发送给固定的一部分Reduce实例。而将其他的都发送给剩余的Reduce实例

方法3:Combiner
使用Combiner可以大量地减小数据倾斜。在可能的情况下,Combine的目的就是聚合并精简数据。

方法4:采用Map Join,尽量避免Reduce Join

9.3 Hadoop小文件优化方法

Hadoop小文件弊端

HDFS上每个文件都要在NameNode上创建对应的元数据,这个元数据的大小约为150byte,这样当小文件比较多的时候,就会产生很多的元数据文件,一方面会大量占用NameNode的内存空间,另一方面就是元数据文件过多,使得寻址索引速度变慢。
小文件过多,在进行MR计算时,会生成过多切片,需要启动过多的MapTask。每个MapTask处理的数据量小,导致MapTask的处理时间比启动时间还小,白白消耗资源。

Hadoop小文件解决方案

  1. 小文件优化的方向:
    (1)在数据采集的时候,就将小文件或小批数据合成大文件再上传HDFS。
    (2)在业务处理之前,在HDFS上使用MapReduce程序对小文件进行合并。
    (3)在MapReduce处理时,可采用CombineTextInputFormat提高效率。
    (4)开启uber模式,实现jvm重用

  2. Hadoop Archive
    是一个高效的将小文件放入HDFS块中的文件存档工具,能够将多个小文件打包成一个HAR文件,从而达到减少NameNode的内存使用

  3. SequenceFile
    SequenceFile是由一系列的二进制k/v组成,如果为key为文件名,value为文件内容,可将大批小文件合并成一个大文件

  4. CombineTextInputFormat
    CombineTextInputFormat用于将多个小文件在切片过程中生成一个单独的切片或者少量的切片。

  5. 开启uber模式,实现jvm重用。默认情况下,每个Task任务都需要启动一个jvm来运行,如果Task任务计算的数据量很小,我们可以让同一个Job的多个Task运行在一个Jvm中,不必为每个Task都开启一个Jvm.
    开启uber模式,在mapred-site.xml中添加如下配置

<!--  开启uber模式 -->
<property><name>mapreduce.job.ubertask.enable</name><value>true</value>
</property><!-- uber模式中最大的mapTask数量,可向下修改  -->
<property><name>mapreduce.job.ubertask.maxmaps</name><value>9</value>
</property>
<!-- uber模式中最大的reduce数量,可向下修改 -->
<property><name>mapreduce.job.ubertask.maxreduces</name><value>1</value>
</property>
<!-- uber模式中最大的输入数据量,默认使用dfs.blocksize 的值,可向下修改 -->
<property><name>mapreduce.job.ubertask.maxbytes</name><value></value>
</property>

10. Hadoop新特性

10.1 Hadoop2.x新特性

集群间数据拷贝

1)scp实现两个远程主机之间的文件复制

scp -r hello.txt root@hadoop103:/user/wangxin/hello.txt     // 推 push
scp -r root@hadoop103:/user/wangxin/hello.txt  hello.txt       // 拉 pull
scp -r root@hadoop103:/user/wangxin/hello.txt root@hadoop104:/user/wangxin   //是

通过本地主机中转实现两个远程主机的文件复制;如果在两个远程主机之间ssh没有配置的情况下可以使用该方式。

2)采用distcp命令实现两个Hadoop集群之间的递归数据复制

[wangxin@hadoop102 hadoop-3.1.3]$  bin/hadoop distcp hdfs://hadoop102:9820/user/wangxin/hello.txt hdfs://hadoop105:9820/user/wangxin/hello.txt

小文件存档

HDFS存储小文件弊端: 每个文件均按块存储,每个块的元数据存储在NameNode的内存中,因此HDFS存储小文件会非常低效。因为大量的小文件会耗尽NameNode中的大部分内存。但注意,存储小文件所需要的磁盘容量和数据块的大小无关。例如,一个1MB的文件设置为128MB的块存储,实际使用的是1MB的磁盘空间,而不是128MB。

解决存储小文件办法之一: HDFS存档文件或HAR文件,是一个更高效的文件存档工具,它将文件存入HDFS块,在减少NameNode内存使用的同时,允许对文件进行透明的访问。具体说来,HDFS存档文件对内还是一个一个独立文件,对NameNode而言却是一个整体,减少了NameNode的内存。

回收站

开启回收站功能,可以将删除的文件在不超时的情况下,恢复原数据,起到防止误删除、备份等作用。
1)回收站参数设置及工作机制

2)启用回收站
修改core-site.xml,配置垃圾回收时间为1分钟。

<property><name>fs.trash.interval</name>
<value>1</value>
</property>
<property>
<name>fs.trash.checkpoint.interval</name>
<value>1</value>
</property>

3)查看回收站
回收站目录在hdfs集群中的路径:/user/wangxin/.Trash/….

4)通过程序删除的文件不会经过回收站,需要调用moveToTrash()才进入回收站

Trash trash = New Trash(conf);
trash.moveToTrash(path);

5)通过网页上直接删除的文件也不会走回收站。

6)只有在命令行利用hadoop fs -rm命令删除的文件才会走回收站。

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -rm -r /user/wangxin/input

7)恢复回收站数据

[wangxin@hadoop102 hadoop-3.1.3]$ hadoop fs -mv
/user/wangxin/.Trash/Current/user/wangxin/input    /user/wangxin/input

10.2 Hadoop3.x新特性

多NN的HA架构

HDFS NameNode高可用性的初始实现为单个活动NameNode和单个备用NameNode,将edits复制到三个JournalNode。该体系结构能够容忍系统中一个NN或一个JN的故障。
但是,某些部署需要更高程度的容错能力。Hadoop3.x允许用户运行多个备用NameNode。例如,通过配置三个NameNode和五个JournalNode,群集能够容忍两个节点而不是一个节点的故障。

纠删码

HDFS中的默认3副本方案在存储空间和其他资源(例如,网络带宽)中具有200%的开销。但是,对于I / O活动相对较低暖和冷数据集,在正常操作期间很少访问其他块副本,但仍会消耗与第一个副本相同的资源量。

纠删码(Erasure Coding)能够在不到50% 的数据冗余情况下提供和3副本相同的容错能力,因此,使用纠删码作为副本机制的改进是自然而然的。
查看集群支持的纠删码策略:hdfs ec -listPolicies

11. Hadoop HA高可用

11.1 HA概述

(1)所谓HA(High Availablity),即高可用(7*24小时不中断服务)。

(2)实现高可用最关键的策略是消除单点故障。HA严格来说应该分成各个组件的HA机制:HDFS的HA和YARN的HA。

(3)Hadoop2.0之前,在HDFS集群中NameNode存在单点故障(SPOF)。

(4)NameNode主要在以下两个方面影响HDFS集群
NameNode机器发生意外,如宕机,集群将无法使用,直到管理员重启
NameNode机器需要升级,包括软件、硬件升级,此时集群也将无法使用
HDFS HA功能通过配置Active/Standby两个NameNodes实现在集群中对NameNode的热备来解决上述问题。如果出现故障,如机器崩溃或机器需要升级维护,这时可通过此种方式将NameNode很快的切换到另外一台机器。

11.2 HDFS-HA工作机制

通过多个NameNode消除单点故障
HDFS-HA工作要点
1)元数据管理方式需要改变
内存中各自保存一份元数据;
Edits日志只有Active状态的NameNode节点可以做写操作;
所有的NameNode都可以读取Edits;
共享的Edits放在一个共享存储中管理(qjournal和NFS两个主流实现);

2)需要一个状态管理功能模块
实现了一个zkfailover,常驻在每一个namenode所在的节点,每一个zkfailover负责监控自己所在NameNode节点,利用zk进行状态标识,当需要进行状态切换时,由zkfailover来负责切换,切换时需要防止brain split现象的发生。

3)必须保证两个NameNode之间能够ssh无密码登录

4)隔离(Fence),即同一时刻仅仅有一个NameNode对外提供服务

HDFS-HA自动故障转移工作机制
自动故障转移为HDFS部署增加了两个新组件:ZooKeeper和ZKFailoverController(ZKFC)进程,如图3-20所示。ZooKeeper是维护少量协调数据,通知客户端这些数据的改变和监视客户端故障的高可用服务。HA的自动故障转移依赖于ZooKeeper的以下功能:
1.故障检测
集群中的每个NameNode在ZooKeeper中维护了一个会话,如果机器崩溃,ZooKeeper中的会话将终止,ZooKeeper通知另一个NameNode需要触发故障转移。

2.现役NameNode选择
ZooKeeper提供了一个简单的机制用于唯一的选择一个节点为active状态。如果目前现役NameNode崩溃,另一个节点可能从ZooKeeper获得特殊的排外锁以表明它应该成为现役NameNode。

ZKFC是自动故障转移中的另一个新组件,是ZooKeeper的客户端,也监视和管理NameNode的状态。每个运行NameNode的主机也运行了一个ZKFC进程,ZKFC负责:
1)健康监测
ZKFC使用一个健康检查命令定期地ping与之在相同主机的NameNode,只要该NameNode及时地回复健康状态,ZKFC认为该节点是健康的。如果该节点崩溃,冻结或进入不健康状态,健康监测器标识该节点为非健康的。
2)ZooKeeper会话管理
当本地NameNode是健康的,ZKFC保持一个在ZooKeeper中打开的会话。如果本地NameNode处于active状态,ZKFC也保持一个特殊的znode锁,该锁使用了ZooKeeper对短暂节点的支持,如果会话终止,锁节点将自动删除。
3)基于ZooKeeper的选择
如果本地NameNode是健康的,且ZKFC发现没有其它的节点当前持有znode锁,它将为自己获取该锁。如果成功,则它已经赢得了选择,并负责运行故障转移进程以使它的本地NameNode为Active。

11.3 YARN-HA工作机制

1)官方文档:
http://hadoop.apache.org/docs/r3.1.3/hadoop-yarn/hadoop-yarn-site/ResourceManagerHA.html

2)YARN-HA工作机制

11.4 HDFS Federation架构设计

NameNode架构的局限性
1)Namespace(命名空间)的限制
由于NameNode在内存中存储所有的元数据(metadata),因此单个NameNode所能存储的对象(文件+块)数目受到NameNode所在JVM的heap size的限制。50G的heap能够存储20亿(200million)个对象,这20亿个对象支持4000个DataNode,12PB的存储(假设文件平均大小为40MB)。随着数据的飞速增长,存储的需求也随之增长。单个DataNode从4T增长到36T,集群的尺寸增长到8000个DataNode。存储的需求从12PB增长到大于100PB。

2)隔离问题
由于HDFS仅有一个NameNode,无法隔离各个程序,因此HDFS上的一个实验程序就很有可能影响整个HDFS上运行的程序。

3)性能的瓶颈
由于是单个NameNode的HDFS架构,因此整个HDFS文件系统的吞吐量受限于单个NameNode的吞吐量。

HDFS Federation架构设计
能不能有多个NameNode
NameNode NameNode NameNode
元数据 元数据 元数据
Log machine 电商数据/话单数据

HDFS Federation应用思考
不同应用可以使用不同NameNode进行数据管理图片业务、爬虫业务、日志审计业务。Hadoop生态系统中,不同的框架使用不同的NameNode进行管理NameSpace。(隔离性)

大数据学习之路-Hadoop相关推荐

  1. My Plan——大数据学习之路

    大数据学习之路 本文简介 相关书籍 计算机基础 数据结构与算法 计算机组成原理 操作系统 计算机网络 数据库 JAVA Python Linux 大数据 其他 本科专业课程安排 学习计划 计划 总结 ...

  2. 大数据学习之路(转载)

    #大数据学习之路(转载) 博文地址https://blog.csdn.net/zys_1997/article/details/78358992 看到一个博主写的大数据学习路线,看了比较心动,想着自己 ...

  3. 【大数据学习之路之hive】

    大数据学习之路之hive hive安装 mysql安装 前言 安装步骤 1.解压文件 2.安装依赖库 3.安装结束后,配置mysql 4.设置开机自启动 5.添加环境变量 6.初始化mysql 7.开 ...

  4. hdp对应hadoop的版本_好程序员大数据学习路线分享hadoop的知识总结

    大数据学习路线分享hadoop的知识总结,Hadoop的背景:原生公司是apache, cdh的cloudar公司,hortworks公司提供hdp. 其中apache的发行版本大致有1.x ,2.x ...

  5. 大数据学习系列之八----- Hadoop、Spark、HBase、Hive搭建环境遇到的错误以及解决方法

    大数据学习系列之八----- Hadoop.Spark.HBase.Hive搭建环境遇到的错误以及解决方法 参考文章: (1)大数据学习系列之八----- Hadoop.Spark.HBase.Hiv ...

  6. 大数据学习之路 JUC篇

    大数据学习之路 JUC篇(1) 前提说明 本人是一名学生,茫茫it行业的一名卑微的小白,这是我第一次写博客.其原因是学着学着知识发现回顾的时候差不多全忘记了!!为了总结.复习自己以往学到过的有关大数据 ...

  7. 大数据学习之路(电脑配置)

    大数据学习之路 第一天:大数据环境搭建(电脑配置) 一想到大数据,我们可能想到的是大数据可视化平台,展示的有多么的炫酷,可是你可能没有想到的是大数据中数据的存储,数据的计算(mapreduce)会是有 ...

  8. 大数据学习系列之七 ----- Hadoop+Spark+Zookeeper+HBase+Hive集群搭建 图文详解

    引言 在之前的大数据学习系列中,搭建了Hadoop+Spark+HBase+Hive 环境以及一些测试.其实要说的话,我开始学习大数据的时候,搭建的就是集群,并不是单机模式和伪分布式.至于为什么先写单 ...

  9. 大数据学习资料_2020大数据学习之路必备

    介绍 大数据领域相当广阔,对于任何开始学习大数据及其相关技术的人来说,这都是一项非常艰巨的任务.大数据技术数不胜数,决定从哪里开始可能是迷茫的. 这就是我想写这篇文章的原因.本文为您提供了一条引导您开 ...

最新文章

  1. AI一分钟 | 英伟达发布最强核弹—无人车AI芯片DRIVE Xavier;百度硅谷首次开放无人车试乘:上车前要先签免责书
  2. R语言使用fs包的file_info函数查看文件元信息(属性信息)、使用file_chmod函数修改文件的权限、使用file_chown函数修改文件的所有者
  3. getElementsByclassName
  4. 写给师弟师妹的一封信-论在校程序员的学习方向
  5. Android 笔记之 R 文件
  6. 解析word template返回使用的webservice WSDL和Operation
  7. Struts2请求处理的内部流程说明(版本二)
  8. 【Python】Python列表基本操作
  9. centos7安装docker笔记
  10. error C2065等:******未声明的标识符错误
  11. 一位BAT大牛推荐的程序员必装10款神器软件
  12. 《大数据大创新:阿里巴巴云上数据中台之道》:解密阿里数据中台建设
  13. 给小朋友讲故事——科学课,地球,太阳和月亮
  14. 教你快速批量查询顺丰快递物流的两种方法
  15. Matlab——彩色图像的拼接与裁剪
  16. 基于52840 S340协议栈USB flash U盘实现
  17. linux系统中shell脚本最全详解二shell条件判断语法介绍函数分析
  18. 计算机视觉 目标分割
  19. Verilog中的parameter
  20. 互斥事件的概念和公式_互斥事件

热门文章

  1. android 换行符 编码_android中的常见的占位符及转义字符
  2. IoTSharp 已支持国产松果时序数据库PinusDB
  3. 图片压缩怎么在线处理?如何压缩图片大小kb?
  4. 血族服务器暂时无法登录,天之炼狱归来服务端7.01架设教程问题解答
  5. 老毛桃制作U盘-linux
  6. 孟岩老师:Linux之父话糙理不糙
  7. Caused by: java.lang.ClassNotFoundException: org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWo
  8. 小米4可以刷入linux,小米4刷入SailfishOS系统图文教程(附工具)
  9. javaScript关系运算符总结
  10. windows8 下载