Apache Hadoop

一、大数据(Big Data)

引言

1.什么是大数据

体量很大的数据,起步存储当量为TB级或者日均数据增长GB级。
在海量数据下,可以进行分析,挖掘,进而发现数据内在的规律,从而为企业或者国家创造价值。

2.大数据的特点(4v特性)

(1) Volume:体量大
(2)Variety:样式多 数据种类多
1.1 结构化数据
1.2.半结构化数据:json、xml
1.3.非结构化数据:图片、音频、视频
(3) Velocity:速度快
(4) Value:低价值密度的数据,挖掘出高价值。

3.大数据处理的核心数据类型-文本数据

4.大数据的数据来源

  1. 自己公司系统运行产生的 日志 (Nginx,Log4j[埋点日志],数据库中的数据)
  2. 爬虫
  3. 行业大数据 电信 医疗 政府 金融
  4. 大数据交易 (贵州) 脱敏

5.分布式及其产生背景

分布式:服务间出现跨机器、跨进程通信同一称为分布式

  • 存储:
    1.单机存储-瓶颈:容量限制、扩展性差、数据灾备问题
    2.分布式存储:使用存储的集群实现对海量数据的并行化的读写,提升系统写的吞吐能力。目前针对传统业务领域的分布式文件存储方案有:FastDFS/GlusterFS/GridFS、大文本日志存储解决方案:HDFS
  • 分析:
    1.单机分析-计算:慢,受限于单机存储的内存、CPU、网络限制。
    2.分布式计算:将计算任务交给专门的计算集群负责任务的计算。打破单机计算的瓶颈,实现并行计算,模拟多核CPU的计算能力。可以实现在一定的时间内达到对数据的有效分析。

6.大数据处理技术的起源

2003-2004年,Google公布了部分GFS和MapReduce思想的细节,受此启发的Doug Cutting等人用2年的业余时间实现了DFS和MapReduce机制,使Nutch性能飙升。然后Yahoo招安Doug Gutting及其项目。
2005年:Hadoop作为Lucene的子项目Nutch的一部分正式引入Apache基金会。
2006年2月:yahoo加入Nutch工程尝试将Nutch存储和计算分离出来,成为一套完整独立的软件并起名为Hadoop 。

人称Hadoop之父的Doug Cutting,Apache软件基金会主席,是Lucene、Nutch 、Hadoop等项目的发起人。最开始Hadoop只是Apache Lucene的子项目Nutch的一部分。Lucene 是全球第一个开源的全文检索引擎工具包, Nutch基于Lucene,并具有网页抓取和解析的功能,可以实现一个搜索引擎的开发,但是如果投入使用的话就必须在极短时间内做出反应,并且能够实现短时间内对亿级数量的网页进行分析处理,这就需要考虑分布式任务处理、故障恢复、负载均衡这些问题。后来Doug Cutting 借鉴谷歌的Google File System和MapReduce:Simplified Data Processing On Large Clusters两篇论文,移植了其中的技术,并将其命名为:Hadoop。

HDFS:Hadoop 分布式文件存储系统,解决海量数据的存储问题(非常重要)
Map Reduce:Hadoop项目分布式计算框架(老),已经成为大数据计算的标杆。是早期分布式计算解决方案。期间该方案在2010年又被Yahoo团队做了一次升级,主要解决的是MapReduce在大规模计算集群的扩展性问题,但是并没有本质改变MapReduce计算本质。因为MapReduce计算的是通过对数据做磁盘迭代计算。导致计算速度不算太快。2013年下半年出现了Spark是一款基于内存的分布式计算框架,用于替代Hadoop的MapReduce,被人们称为第二代大数据计算引擎。

二、Hadoop框架

(一)引言

1.起源

Doug Cutting是Lucene(全文搜索技术 Solr ES)、Nutch作者,后续设计开发了Hadoop体系。
Hadoop1.x<---------------------------------------------Google
HDFS(Hadoop Distributed File System) <------GFS
MapReduce<-------------------------------------------MapReduce
HBase <-------------------------------------------------BigTable
apache组织正式开源Hadoop,并把Hadoop作为了顶级项目。

2.Hadoop的生态圈

  1. Hadoop Core (HDFS,MR-MapReduce)
  2. Hadoop生态工具 (Hive,HBase)
  3. Hadoop辅助工具 (Flume,Sqoop,Oozie,Hue)

3.Hadoop的核心技术

  1. HDFS 文件系统 (IO) 存数据 取数据
  2. MapReduce 编程,数据的计算 原有的 Java开发 区别
  3. Hive 学SQL (HQL Hive Query Lanuage) 类似SQL 95%和SQL语法一致
  4. Hbase (NoSQL) 类比 Redis 存 取数据

(二)HDFS

1.基本概念

全称Hadoop Distributed File System,是Hadoop一个基于分布式存储通用的文件系统,该系统特点容易部署、对系统硬件要求低,搭建成本可控。可以使得数据存储大小和集群过程呈现一种线性关系 (目前最大已知规模2000台左右规模,实际在生产环境下集群规模一般在10~100台左右)。HDFS文件系统的架构图:
在这里插入图片描述
NameNode:使用内存存储集群中的元数据(文件名、权限、位置、大小、创建时间、副本信息、块信息、实际存储数据的datanode信息)

DataNode:HDFS中专门用于存储数据的服务器,负责响应客户端对数据块的读写请求,向NameNode汇报自身状态信息,同时负责对块数据的冗余保存以及存储块数据加密后的校验和。

Block:是HDFS切分文件的尺度,默认是128MB,一个文件最多只有 一个不足128MB块

副本因子:HDFS为了防止DataNode宕机导致块的丢失,允许一个块又多个备份,默认备份是3

  • 思考:为什么HDFS不擅长存储小文件?
    例:
案例NameNodeDataNode
1文件128MB1条数据块映射元数据128MB磁盘存储*(副本因子)
1000文件总计128MB1000*1条数据块映射元数据128MB磁盘存储*(副本因子)

因为Namenode使用单机的内存存储,因此由于小文件会占用更多的内存空间,导致了Namenode内存浪费。

2.Hadoop的伪分布式搭建

  • 安装虚拟器并且安装CentOS-6.5 64位 (参考[CentOS 64安装.wmv](./CentOS 64安装.wmv))

  • 安装jdk-8u171-linux-x64.rpm配置JAVA_HOME环境变量(~/.bashrc)

[root@CentOS ~]# rpm -ivh jdk-8u171-linux-x64.rpm 
[root@CentOS ~]# ls -l /usr/java/
total 4
lrwxrwxrwx. 1 root root   16 Mar 26 00:56 default -> /usr/java/latest
drwxr-xr-x. 9 root root 4096 Mar 26 00:56 jdk1.8.0_171-amd64
lrwxrwxrwx. 1 root root   28 Mar 26 00:56 latest -> /usr/java/jdk1.8.0_171-amd64
[root@CentOS ~]# vi .bashrc 
JAVA_HOME=/usr/java/latest
PATH=$PATH:$JAVA_HOME/bin
CLASSPATH=.
export JAVA_HOME
export PATH
export CLASSPATH

[root@CentOS ~]# source ~/.bashrc # 加载环境变量

  • 配置主机名和IP映射关系

[root@CentOS ~]# vi /etc/hosts # 一定是自己的IP

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.40.128 CentOS          
  • 配置ssh免密登录
[root@CentOS ~]# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
4b:29:93:1c:7f:06:93:67:fc:c5:ed:27:9b:83:26:c0 root@CentOS
The key's randomart image is:
+--[ RSA 2048]----+
|                 |
|         o   . . |
|      . + +   o .|
|     . = * . . . |
|      = E o . . o|
|       + =   . +.|
|        . . o +  |
|           o   . |
|                 |
+-----------------+
[root@CentOS ~]# ssh-copy-id CentOS
The authenticity of host 'centos (192.168.40.128)' can't be established.
RSA key fingerprint is 3f:86:41:46:f2:05:33:31:5d:b6:11:45:9c:64:12:8e.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'centos,192.168.40.128' (RSA) to the list of known hosts.
root@centos's password: 
Now try logging into the machine, with "ssh 'CentOS'", and check in:

  .ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting.
[root@CentOS ~]# ssh root@CentOS
Last login: Tue Mar 26 01:03:52 2019 from 192.168.40.1
[root@CentOS ~]# exit
logout
Connection to CentOS closed.
  • 关闭防火墙
# 临时关闭服务
[root@CentOS ~]# service iptables stop
iptables: Setting chains to policy ACCEPT: filter [  OK  ]
iptables: Flushing firewall rules: [  OK  ]
iptables: Unloading modules: [  OK  ]
[root@CentOS ~]# service iptables status
iptables: Firewall is not running.
# 关闭开机自动启动
[root@CentOS ~]# chkconfig iptables off
[root@CentOS ~]# chkconfig --list | grep iptables
iptables        0:off   1:off   2:off   3:off   4:off   5:off   6:off
  • 安装配置Hadoop
    解压并配置环境变量
[root@CentOS ~]# tar -zxf hadoop-2.6.0_x64.tar.gz -C /usr/
[root@CentOS ~]# ls /usr/hadoop-2.6.0/
bin  etc  include  lib  libexec  LICENSE.txt  NOTICE.txt  README.txt  sbin  share
[root@CentOS ~]# vi ~/.bashrc 
HADOOP_HOME=/usr/hadoop-2.6.0
JAVA_HOME=/usr/java/latest
PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
CLASSPATH=.
export JAVA_HOME
export PATH
export CLASSPATH
export HADOOP_HOME
[root@CentOS ~]# source  ~/.bashrc 
[root@CentOS ~]# hadoop version
Hadoop 2.6.0
Subversion Unknown -r Unknown
Compiled by root on 2016-08-01T20:48Z
Compiled with protoc 2.5.0
From source with checksum 18e43357c8f927c0695f1e9522859d6a
This command was run using /usr/hadoop-2.6.0/share/hadoop/common/hadoop-common-2.6.0.jar
  • 配置hadoop配置文件etc/hadoop/{core-site.xml|hdfs-site.xml|slaves}

core-site.xml(配置的是NameNode访问入口,以及服务存储的根目录)


[root@CentOS ~]# vi /usr/hadoop-2.6.0/etc/hadoop/core-site.xml 
<!--nn访问入口-->
<property>
    <name>fs.defaultFS</name>
    <value>hdfs://CentOS:9000</value>
</property>
<!--hdfs工作基础目录-->
<property>
    <name>hadoop.tmp.dir</name>
    <value>/usr/hadoop-2.6.0/hadoop-${user.name}</value>
</property>
[root@CentOS ~]# vi /usr/hadoop-2.6.0/etc/hadoop/hdfs-site.xml 
<!--block副本因子-->
<property>
    <name>dfs.replication</name>
    <value>1</value>
</property>
<!--配置Sencondary namenode所在物理主机-->
<property>
    <name>dfs.namenode.secondary.http-address</name>
    <value>CentOS:50090</value>
</property>
<!--关闭HDFS权限管理-->
<property>
	<name>dfs.permissions.enabled</name>
    <value>false</value>
</property>
[root@CentOS ~]# vi /usr/hadoop-2.6.0/etc/hadoop/slaves 
CentOS
  • HDFS初始化

如果是第一次初始化启动HDFS服务,需要创建一个空的fsimage文件,以便Namenode在启动的时候加载

[root@CentOS ~]# hdfs namenode -format # 创建初始化所需的fsimage文件
...
19/03/26 01:31:09 INFO namenode.NNConf: Maximum size of an xattr: 16384
19/03/26 01:31:09 INFO namenode.FSImage: Allocated new BlockPoolId: BP-1143348175-192.168.40.128-1553535069443
19/03/26 01:31:09 INFO common.Storage: Storage directory `/usr/hadoop-2.6.0/hadoop-root/dfs/name has been successfully formatted.`
19/03/26 01:31:09 INFO namenode.NNStorageRetentionManager: Going to retain 1 images with txid >= 0
  • 启动HDFS的服务
[root@CentOS ~]# start-dfs.sh 
Starting namenodes on [CentOS]
CentOS: starting namenode, logging to /usr/hadoop-2.6.0/logs/hadoop-root-namenode-CentOS.out
CentOS: starting datanode, logging to /usr/hadoop-2.6.0/logs/hadoop-root-datanode-CentOS.out
Starting secondary namenodes [CentOS]
CentOS: starting secondarynamenode, logging to /usr/hadoop-2.6.0/logs/hadoop-root-secondarynamenode-CentOS.out
[root@CentOS ~]# jps
2097 SecondaryNameNode
2280 Jps
1993 DataNode
1918 NameNode

#或者访问:http://[IP]:50070/

3.HDFS 垃圾回收站配置

用户可以通过配置core-site.xml,开启NameNode的垃圾回收。NameNode会根据fs.trash.interval配置配置垃圾回收的频率,默认单位是分钟。表示1分钟内,如果用户不处理删除文件,系统会自动删除回收战的内容。该种机制就是为了防止用户的误操作。

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

4.Client对HDFS的访问

(1)Shell方式

HDFS Shell(脚本)

[root@CentOS ~]# hdfs dfs -help
Usage: hadoop fs [generic options]
        [-appendToFile <localsrc> ... <dst>]
        [-cat [-ignoreCrc] <src> ...]
        [-checksum <src> ...]
        [-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
        [-copyFromLocal [-f] [-p] [-l] <localsrc> ... <dst>]
        [-copyToLocal [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
        [-cp [-f] [-p | -p[topax]] <src> ... <dst>]
        [-get [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
        [-help [cmd ...]]
        [-ls [-d] [-h] [-R] [<path> ...]]
        [-mkdir [-p] <path> ...]
        [-moveFromLocal <localsrc> ... <dst>]
        [-moveToLocal <src> <localdst>]
        [-mv <src> ... <dst>]
        [-put [-f] [-p] [-l] <localsrc> ... <dst>]
        [-rm [-f] [-r|-R] [-skipTrash] <src> ...]
        [-tail [-f] <file>]
        [-text [-ignoreCrc] <src> ...]
        [-touchz <path> ...]

(2)Java代码方式
  • 配置Windows开发环境

①解压hadoop的安装包
②将winutil.exe和hadoop.dll文件拷贝到hadoop安装目录下的bin目录
③在Windows上配置CentOS的主机名和IP的映射关系

192.168.40.128 CentOS

④配置HADOOP_HOME环境变量
⑤重启IDEA开发工具,否则IDAE无法识别HADOOP_HOME,因为windows执行代码程序需要通过HADOOP_HOME定位winutil.exe和hadoop.dll文件。

  • 引入Maven依赖
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-common</artifactId>
    <version>2.6.0</version>
</dependency>
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-hdfs</artifactId>
    <version>2.6.0</version>
</dependency>
  • HDFS访问过程中核心的API
1. Configuration 配置类,进行core-site.xml hdfs-site.xml 配置信息
的读取,操作
2. FileSystem 代表的就是 HDFS分布式文件系统
3. IOUtils IO操作的工具类
  • 示例代码
public class TestHDFS {
	//从HDFS中读取文件在控制台输出
	@Test
	public void test1() throws Exception{
		Configuration conf = new Configuration();
		conf.set("fs.defaultFS","hdfs://CentOS:8020");
		FileSystem fileSystem = FileSystem.get(conf);
		FSDataInputStream fsDataInputStream = fileSystem.open(new
		Path("/liuh/xiaohei/data"));
		IOUtils.copyBytes(fsDataInputStream, System.out, 1024, true);
	}
	
	
	//添加获取FileSystem对象的工具方法,在以下测试中使用
	private FileSystem getFileSystem() throws Exception{
	Configuration conf = new Configuration();
	conf.set("fs.defaultFS","hdfs://hadoop2.baizhiedu.com:8020");
	FileSystem fileSystem = FileSystem.get(conf);
	return fileSystem;
	}
	//从HDFS中读取文件在控制台输出
	@Test
	public void test2() throws Exception {
		FileSystem fileSystem = getFileSystem();
		FSDataInputStream fsDataInputStream = fileSystem.open(new
		Path("/liuh/xiaohei/data"));
		IOUtils.copyBytes(fsDataInputStream,System.out,1024,true);
	}
	//加载本地配置文件core-site.xml替代伪分布式中配置。从HDFS中读取文件在控制台输出
	@Test
	public void test3()throws Exception {
		Configuration conf = new Configuration();
		conf.addResource(new
	Path("C:\\Users\\Administrator\\IdeaProjects\\hadoop_code\\hadoop-hdfsbaizhiedu\\src\\main\\resources\\core-site.xml"));
		FileSystem fileSystem = FileSystem.get(conf);
		FSDataInputStream fsDataInputStream = fileSystem.open(new
		Path("/liuh/xiaohei/data"));
	IOUtils.copyBytes(fsDataInputStream, System.out, 1024, true);
	}
	//从HDFS中读取文件,输出为文件
	@Test
	public void test4()throws Exception{
		FileSystem fileSystem = getFileSystem();
		FSDataInputStream fsDataInputStream = fileSystem.open(new
		Path("/liuh/xiaohei/data"));
		
		FileOutputStream fileOutputStream = new
		FileOutputStream("f://laolei.txt");
		IOUtils.copyBytes(fsDataInputStream,fileOutputStream,1024,true);
	}
	//从本地文件读取内容,写出到HDFS文件中
	@Test
	public void test5()throws Exception{
		FileInputStream fileInputStream = new
		FileInputStream("f://xiaojr.txt");
		
		FileSystem fileSystem = getFileSystem();
		FSDataOutputStream fsDataOutputStream = fileSystem.create(new
		Path("/liuh/xiaohei/data1"));
		
		IOUtils.copyBytes(fileInputStream,fsDataOutputStream,1024,true);
	}
	//创建删除HDFS目录
	@Test
	public void test6()throws Exception{
		FileSystem fileSystem = getFileSystem();
		boolean isOk = fileSystem.mkdirs(new Path("/xiaojr"));
		System.out.println("创建目录 "+isOk);
		//fileSystem.delete(new Path(""),true);
	}
	
}

5.知识补充

  • (1)NameNode的安全模式

是对HDFS的一种保护机制,1)正常情况下当系统在加载fsimage的初期会自动进入安全模式,在该模式下系统不接受外界的任何请求,当加载完数据检查系统完毕,系统会自动离开安全模式。2)如果当DataNode/NameNode使用空间不足时,系统会自动进入安全模式。3).当系统维护时,管理员也可手动的将NameNode切换成安全模式,维护结束再离开。

[root@CentOS ~]# hdfs dfsadmin -safemode get
Safe mode is OFF
[root@CentOS ~]# hdfs dfsadmin -safemode enter
Safe mode is ON
[root@CentOS ~]# hdfs dfs -put /root/install.log /
put: Cannot create file/install.log._COPYING_. Name node is in safe mode.
[root@CentOS ~]# hdfs dfsadmin -safemode leave
Safe mode is OFF
[root@CentOS ~]# hdfs dfs -put /root/install.log /
  • (2)Hadoop体系下配置文件优先级(由低到高)
1. *-default.xml share jar
core-default.xml HDFS整体设置 设置NameNode入口,namenode持久化,存储位置
hdfs-default.xml 设置与HDFS相关信息 副本数量 块大小 hdfs访问权限
yarn-default.xml 与yarn相关
mapred-default.xml 与mapred相关
2. *-site.xml etc/hadoop
# 如果site.xml对default对应的key进行了覆盖,那么就按照site的设置,进行处理,如果没有覆盖,则按照
default处理
core-site.xml HDFS整体设置 设置NameNode入口,namenode持久化,存储位置
hdfs-site.xml 设置与HDFS相关信息 副本数量 块大小 hdfs访问权限
yarn-site.xml 与yarn相关
mapred-site.xml 与mapred相关
3. 代码 *-site.xml 配置
4. 程序中
Configration.set()
  • (3)ssh免密登录

原理
在这里插入图片描述
操作

#1. 如何生成公私钥对
[root@CentOS ~]# ssh-keygen -t rsa
#2.把client机的公钥,发送给远端主机
[root@CentOS ~]# ssh-copy-id CentOS
#3.测试连接
[root@CentOS ~]# ssh root@CentOS
#4.退出测试连接
[root@CentOS ~]# exit
  • (4)NameNode的持久化persistent

NameNode在运行时,把重要的元数据放置在内存中,如果内存出现问题,则元数据丢失,为了保证元数据安全,NameNode有对应的持久化机制,把元数据持久化到硬盘存储。
持久化工作原理
在这里插入图片描述
fsimage:存储在Namenode服务所在物理主机磁盘上的一个二进制文本文件。记录了元数据信息

edits:存储在Namenode服务所在物理主机磁盘上的一个二进制文本文件,记录了对元数据修改操作。

#fsImage默认存储位置 /opt/install/hadoop-2.5.2/data/tmp/dfs/name
dfs.namenode.name.dir
#editslog默认存储位置
dfs.namenode.edits.dir

#定制FSImage和EditsLog的存储位置hdfs-site.xml
<property>
	<name>dfs.namenode.name.dir</name>
	<value>file:///xxx/xxxx</value>
</property>
<property>
	<name>dfs.namenode.edits.dir</name>
	<value>file:///xxx/xxxx</value>
</property>

HDFS集群启动经历过程

进入安全模式
1.整合 FSImage和EditsLog 生成新的EditsLog 和 FSImage,由新EditsLog接收用户写操作命令
2.DataNode都需NameNode主动汇报健康情况(心跳)3秒
3.汇报块列表 通过校验和 检查块是否可用,并定期1小时汇报。
  • (5)Secondary NameNode

当第一次启动Namenode服务的时候,系统会加载fsimage和edits文件进行合并得到最新元数据信息,并且更新fsimage和edits,一旦服务启动成功后,在服务允许期间不再更新fsimage,只是将操作记录在edits中。导致namenode在长期运行之后重启导致namenode启动时间过长,还可能导致edits文件过大。因此Hadoop HDFS引入Secondary Namenode 辅助Namenode在运行期间完成对元数据的备份和整理。
Secondary NameNode工作原理
在这里插入图片描述

自定义SecondaryNameNode 拉取数据的周期
hdfs-site.xml
	dfs.namenode.checkpoint.period 3600秒
	dfs.namenode.checkpoint.txns 1000000
	
secondaryNameNode启动方式:sbin/start-dfs.sh
sbin/hadoop-daemon.sh start secondarynamenode

定制secondaryNameNode 启动的节点
hdfs-site.xml
	dfs.namenode.secondary.http-address 0.0.0.0:50090
	dfs.namenode.secondary.https-address 0.0.0.0:50091

6. HDFS分布式集群搭建【简单版】

(1)机器的选型
1. NameNode选择 内存大
2. DataNode选择 硬盘大
# namenode节点同时可以充当datanode,充分利用硬盘资源
(2) 各个节点配置
  • 准备3个节点,修改下列信息
ip地址 防火墙 selinux 主机名 主机映射 jdk ssh免密登陆
ssh免密登录:
	1. 生成公私钥对
	ssh-keygen -t rsa 最终放置到 ~/.ssh目录
	2. 如何把client机的公钥,发送给远端主机
   	ssh-copy-id root@ip
  • 配置文件及分布式搭建
1. Hadoop 每个节点都要安装hadoop,并且保证配置文件一致
   注意:老机器化 删除 hadoop_home/data/tmp 内容
2. 按照分布式集群的要求,书写配置文件,同步集群的每一个节点
   hadoop-env.sh
		export JAVA_HOME=/usr/java/jdk1.7.0_71
   core-site.xml
       <!--用于设置namenode并且作为Java程序的访问入口-->
        <property>		
           <name>fs.defaultFS</name>
           <value>hdfs://CentOSA:8020</value>
        </property>
       <!--存储NameNode持久化的数据,DataNode块数据-->
       <!--手工创建$HADOOP_HOME/data/tmp-->
        <property>
	       <name>hadoop.tmp.dir</name>
	       <value>/opt/install/hadoop-2.5.2/data/tmp</value>
         </property>
   hdfs-site.xml
         <!--可选择保留-->
         <property>
               <name>dfs.permissions.enabled</name>
                   <value>false</value>
          </property>
   yarn-site.xml
		<property>
               <name>yarn.nodemanager.aux-services</name>
               <value>mapreduce_shuffle</value>
      	 </property>	
   mapred-site.xml
	<!--yarn 与 MR相关-->
           <property>	 	        		
              <name>mapreduce.framework.name</name>
              <value>yarn</value>
           </property>
   slaves 
       CentOSA
       CentOSB
       CentOSC
4. 格式化【namenode】
   bin/hdfs namenode -format
5. 启动集群【namenode】
   start-dfs.sh
   stop-dfs.sh
   
#shell命令 执行在 namenode所在节点

7.HANameNode集群

(1)原理分析

在这里插入图片描述
在这里插入图片描述

(2)集群搭建(3个节点)
  • zookeeper集群
   1.1 解压缩
       tar -zxvf zookeeper-3.4.5.tar.gz -C /opt/install
   1.2 创建数据文件夹
       mdkir  zookeeper安装目录/data
   1.3 conf目录修改zookeeper的配置文件
       修改zoo_sample.cfg 为 zoo.cfg
       		mv zoo_sample.cfg zoo.cfg
       编辑内容 vim zoo.cfg
       dataDir=/opt/install/zookeeper-3.4.5/data

       server.0=CentOSA:2888:3888
       server.1=CentOSB:2888:3888
       server.2=CentOSC:2888:3888
   1.4 在每个节点zookeeper安装目录/data目录下创建myid文件(touch myid),并分别修改vim myid
       CentOSA节点改为0
       CentOSB节点改为1
      CentOSC节点改为2
       可用scp -r 命令 同步集群中所有节点 并 修改对应的myid文件
   1.5 主节点 ssh 其他节点
   	   ssh CentOSA
   	   ssh CentOSB
   	   ssh CentOSC
   	   需要输入yes的节点需要再次ssh
   	   每次ssh完毕后需要exit
   1.6 启动zk服务
       bin/zkServer.sh start | stop | restart
       bin/zkServer.sh status 查看集群状态 【必须集群完整启动完成】
       
       bin/zkCli.sh [leader]
  • HA-HDFS集群
 ☆☆☆删除 data/tmp 
2.1 core-site.xml
<!-- 设置访问hdfs集群的虚拟地址 -->
<property>		
	<name>fs.defaultFS</name>
	<value>hdfs://ns</value>
</property>
<!-- 设置NameNode持久化数据、DataNode块数据的保存目录  -->
<property>
	<name>hadoop.tmp.dir</name>
	<value>/opt/install/hadoop-2.5.2/data/tmp</value>
</property>
<!-- 让HDFS集群能够认识zookeeper集群(值为zookeeper集群各个几点信息 ) -->
<property>
	<name>ha.zookeeper.quorum</name>
	<value>CentOSA:2181,CentOSB:2181, CentOSC:2181</value>
</property>
2.2 hdfs-site.xml 
<property>
	<name>dfs.permissions.enabled</name>
	<value>false</value>
</property>

<!--指定hdfs的nameservice为ns,需要和core-site.xml中的保持一致 -->
<property>
	<name>dfs.nameservices</name>
	<value>ns</value>
</property>
<!-- ns下面有两个NameNode,分别是nn1,nn2 -->
<property>
	<name>dfs.ha.namenodes.ns</name>
	<value>nn1,nn2</value>
</property>
<!-- nn1的RPC通信地址 -->
<property>
	<name>dfs.namenode.rpc-address.ns.nn1</name>
	<value>CentOSA:8020</value>
</property>
<!-- nn1的http通信地址 -->
<property>
	<name>dfs.namenode.http-address.ns.nn1</name>
	<value>CentOSA:50070</value>
</property>
<!-- nn2的RPC通信地址 -->
<property>
	<name>dfs.namenode.rpc-address.ns.nn2</name>
	<value>CentOSB:8020</value>
</property>
<!-- nn2的http通信地址 -->
<property>
	<name>dfs.namenode.http-address.ns.nn2</name>
	<value>CentOSB:50070</value>
</property>

<!-- 指定NameNode的元数据在JournalNode上的存放位置 -->
<property>
	<name>dfs.namenode.shared.edits.dir</name>
	<value>qjournal://CentOSA:8485;CentOSB:8485;CentOSC:8485/ns</value>
</property>
<!-- 指定JournalNode在本地磁盘存放数据的位置 -->
<property>
	<name>dfs.journalnode.edits.dir</name>
	<value>/opt/install/hadoop-2.5.2/journal</value>
</property>
<!-- 开启NameNode故障时自动切换 -->
<property>
	<name>dfs.ha.automatic-failover.enabled</name>
	<value>true</value>
</property>
<!-- 配置失败自动切换实现方式 -->
<property>
<name>dfs.client.failover.proxy.provider.ns</name>
	<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<!-- 配置隔离机制,如果ssh是默认22端口,value直接写sshfence即可 -->
<!-- 隔离机制指Active的NameNode如果 遇到网络 延时等问题时不能像zookeeper集群发送心跳了,
并不是真的宕机了,zookeeper集群会启动StandBy的NameNode。为避免原Active的NameNode复活而
造成的“脑裂”问题,zookeeper集群会将原Active的NameNode进行隔离-杀死 -->
<property>
	<name>dfs.ha.fencing.methods</name>
	<value>sshfence</value>
</property>
<!-- 使用隔离机制时需要ssh免登陆 -->
<property>
	<name>dfs.ha.fencing.ssh.private-key-files</name>
	<value>/root/.ssh/id_rsa</value>
</property>

2.3 yarn-env.sh添加如下内容

export JAVA_HOME=/usr/java/jdk1.7.0_71

2.4启动命令

首先启动各个节点的Zookeeper,在各个节点上执行以下命令:(进程名 QuorumPeerMain-zookeeper集群进程)
bin/zkServer.sh start

在某一个namenode节点执行如下命令,创建命名空间
bin/hdfs zkfc -formatZK

在每个journalnode节点用如下命令启动journalnode(进程名JournalNode-同步EditsLog文件进程)
sbin/hadoop-daemon.sh start journalnode

在主namenode节点格式化namenode和journalnode目录
bin/hdfs namenode -format ns

在主namenode节点启动namenode进程(进程名NameNode)
sbin/hadoop-daemon.sh start namenode

在备namenode节点执行第一行命令,这个是把备namenode节点的目录格式化并把元数据从主namenode节点copy过来,并且这个命令不会把journalnode目录再格式化了!然后用第二个命令启动备namenode进程!

bin/hdfs namenode -bootstrapStandby
sbin/hadoop-daemon.sh start namenode(进程名NameNode)

在两个namenode节点都执行以下命令(进程名 DFSZKFailoverController-失败隔离控制进程 )
sbin/hadoop-daemon.sh start zkfc

在所有datanode节点都执行以下命令启动datanode(进程名 DataNode)
sbin/hadoop-daemon.sh start datanode

日常启停命令
sbin/start-dfs.sh
sbin/stop-dfs.sh

8.Hadoop源码编译

apache官方网站上提供的二进制文件,是基于32为操作系统进行编译的,不适合与64位操作系统,需要自己编译

(1)编译过程
1. hadoop源码
2. maven linux版本
3. 安装相关依赖软件
	1. jdk
	2. maven 并设置 环境变量 (apache-maven-3.0.5-bin.tar.gz)
	/etc/profile
	MAVEN_HOME
	M2_HOME
	PATH
3.linux相关的软件
	yum install wget
	yum install autoconf automake libtool cmake
	yum install ncurses-devel
	yum install openssl-devel
	yum install lzo-devel zlib-devel gcc gcc-c++
4. 安装protobuf
解压:
	tar -zxvf protobuf-2.5.0.tar.gz
编译安装:
进入安装目录,进行配置,执行命令:
	./configure
分别执行安装命令:
	make
	make check
	make install
5.安装findbugs
下载: findbugs-1.3.9.tar.gz
解压:
tar –zxvf findbugs-1.3.9.tar.gz
设置环境变量(/etc/profile):
	export FINDBUGS_HOME=/opt/modules/findbugs-1.3.9
	export PATH=$PATH:$ FINDBUGS_HOME/bin
执行命令:source /etc/profile
验证:findbugs -version
4. Hadoop源码编译
export MAVEN_OPTS="-Xms256m -Xmx512m"
mvn package -DskipTests -Pdist,native -Dtar 执行在Hadoop2.5.0的源码包中
5. 编译成功 hadoop_src_home/hadoop-dist/target
(2)可能出现的问题
1. maven版本过高
2. 错误
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-antrun-plugin:1.7:run
(dist) on project hadoop-hdfs-httpfs: An Ant BuildException has occured: exec
returned: 2
[ERROR] around Ant part ...<exec dir="/home/pory/workplace/hadoop-2.4.1-src/hadoophdfs-project/hadoop-hdfs-httpfs/target" executable="sh" failοnerrοr="true">... @
10:134 in /home/pory/workplace/hadoop-2.4.1-src/hadoop-hdfs-project/hadoop-hdfshttpfs/target/antrun/build-main.xml
[ERROR] -> [Help 1]
这是因为/home/pory/workplace/hadoop-2.4.1-src/hadoop-hdfs-project/hadoop-hdfshttpfs/downloads目录下的文件没有下载完全,可以手动下一份匹配版本的文件放在下面,在
http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.36/bin/
然后重新执行命令
(3)编译后如何使用
需要应用64为的hadoop替换32位hadoop /opt/install/hadoop-2.5.2/lib/native 的内容
# 替换一定在linux系统中直接替换。

(三)MapReduce

1.概述

Map Reduce是一个 Hadoop 的并行计算框架,借鉴了函数式编程(Scala 编程应用在Spark)思想和矢量编程(任务做阶段化拆分,每个阶段都可以设定并行度)。Hadoop 中是充分利用了存储节点(Data Node)运行所在主机的计算资源(CPU、内存、网络、少许磁盘-存储计算中间结果)完成对任务的并行计算。Map Reduce框架会在所有的DataNode所在的物理主机启动一个计算资源管理者-Node Manager用于管理本地的计算资源,默认系统会将计算资源均分8个等份,每个等份抽象成一个Container。还会再找一些其他的主机启动一个资源管理中心-Resource Manager,用于管理集群的计算资源。

当用户提交一个计算任务给MapReduce框架,框架会将任务拆分成Map阶段和Reduce阶段(矢量编程思想将任务拆分成两个阶段),框架会根据Map/Reduce阶段的任务并行度.在任务提交初期会启动一个任务管理者(每个任务都有自己的任务管理者)-MRAppMaster(该进程会浪费掉1个计算资源)用于管理Map阶段和Reduce阶段任务执行。在任务执行时期,每个阶段会根据阶段任务的并行度分配计算资源(每个计算资源启动一个Yarn Child),由MRAppMaster完成对阶段任务的检测管理。
MapReduce的构建思想
在这里插入图片描述
MapReduce的执行过程

在这里插入图片描述
ResourceManager:负责任务资源的统一调度,管理NodeManager资源,启动MRAppMaster

NodeManager:用于管理本机上的计算资源,默认会将本机的计算资源拆分为8个等份,每个等份抽象成Container

MRAppMaster:任何一个执行的任务都会有一个MRAppMaster负责YarnChild任务的执行和监测。

YarnChild:是具体执行的MapTask或者是ReduceTask的统称。

任务执行期间系统会启动MRAppmaster和YarnChild负责任务的执行,一旦任务执行结束MRAppMaster和YarnChild会自动退出。

Job作业过程
在这里插入图片描述

2.集群准备-启动yarn

1. 配置相关的配置文件 etc/hadoop
yarn-site.xml mapred-site.xml
2. 启动yarn
2.1 伪分布式
	sbin/yarn-daemon.sh start resourcemanager
	sbin/yarn-daemon.sh start nodemanager
2.2 集群方式
mapred-site.xml
<property>
	<name>mapreduce.framework.name</name>
	<value>yarn</value>
</property>
yarn-site.xml
<property>
	<name>yarn.nodemanager.aux-services</name>
	<value>mapreduce_shuffle</value>
</property>
<!--指定resourcemanager所对应的节点【分布式环境新加】--> 
<property>
	<name>yarn.resourcemanager.hostname</name>
	<value>CentOSB.baizhiedu.com</value>
</property>
slaves
	datanode同时又是nodemanager
同步集群的每一个节点
正常启动hdfs
	namenode格式化
	sbin/start-dfs.sh
集群方式的yarn启动
	建议 namenode 不要和 resourcemanager放置在同一个点
	# ssh相关的机器,避免yes
	在集群环境下,yarn启动的命令,需要在resourcemanager所在的节点执行
		sbin/start-yarn.sh
		sbin/stop-yarn.sh
验证:
	jps看进程
	http://CentOSB:8088

3.入门案例

  • 依赖
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-mapreduce-client-jobclient</artifactId>
    <version>2.6.0</version>
</dependency>

<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-mapreduce-client-core</artifactId>
    <version>2.6.0</version>
</dependency>
  • 日志文件格式如下(1TB):
日志级别 URL 用户ID 日期
INFO /product 001 2019-03-26 10:00:00
INFO /cart 003 2019-03-26 10:00:00
INFO /product 001 2019-03-26 10:00:00
INFO /cart 002 2019-03-26 10:00:00
INFO /order 004 2019-03-26 10:00:00

1.按照URL统计每个板块访问的次数,并且使用柱状图显示?

商品板块 2

购物车 2

  • 订单 1
create table t_click(
   level varchar(32),
   url varchar(128),
   uid varchar(32),
   click_time timestamp 
)
select url,sum(1) from t_click group by url
      reduce(key,values)        map(key,value)
      reduce(url,[1,1,1,...])    map(url,1)
  • Map
public class ClickMappper  extends Mapper<LongWritable, Text,Text, IntWritable> {
    //INFO /product 001 2019-03-26 10:00:00
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        String[] tokens = value.toString().split(" ");
        context.write(new Text(tokens[1]),new IntWritable(1));
    }
}
  • Reduce
public class ClickReducer extends Reducer<Text, IntWritable,Text,IntWritable> {
    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
        int total=0;
        for (IntWritable value : values) {
            total=value.get();
        }
        context.write(key,new IntWritable(total));
    }
}
  • Job任务
public class CustomJobSubmitter extends Configured implements Tool {
    public int run(String[] strings) throws Exception {
        //1.封装Job对象
        Job job=Job.getInstance(getConf());
        //2.设置任务的读取、写出数据格式
        job.setInputFormatClass(TextInputFormat.class);
        job.setOutputFormatClass(TextOutputFormat.class);
        //3.设置数据读入和写出路径
        Path src = new Path("/demo/click");
        TextInputFormat.addInputPath(job,src);
        Path dst = new Path("/demo/result");//必须不存在,否则任务提交失败
        TextOutputFormat.setOutputPath(job,dst);
        //4.设置数据处理逻辑代码片段
        job.setMapperClass(ClickMappper.class);
        job.setReducerClass(ClickReducer.class);
        //5.设置Mapper和Reducer输出key-value类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);

        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        //6.任务提交
        //job.submit();
        job.waitForCompletion(true);
        return 0;
    }
    public static void main(String[] args) throws Exception {
        ToolRunner.run(new CustomJobSubmitter(),args );
    }
}
  • 发布任务

远程jar发布

job.setJarByClass(CustomJobSubmitter.class);

hadoop jar xxxxx.jar com.baizhi.CustomJobSubmitter

  • 基于Maven构建
<!--jar(main函数)   上传yarn 远程执行 bin/yarn jar xxx.jar -->
 <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jar-plugin</artifactId>
         <version>2.3.2</version>
         <configuration>
           <outputDirectory>${basedir}</outputDirectory>
           <archive>
             <manifest>
               <mainClass>${baizhi-mainClass}</mainClass>
             </manifest>
           </archive>
         </configuration>
  </plugin>

 <extensions>
      <extension>
        <groupId>org.apache.maven.wagon</groupId>
        <artifactId>wagon-ssh</artifactId>
        <version>2.8</version>
      </extension>
 </extensions>

 <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>wagon-maven-plugin</artifactId>
         <version>1.0</version>
         <configuration>
           <fromFile>${project.build.finalName}.jar</fromFile>
           <url>scp://root:123456@${target-host}${target-position}</url>
           <commands>
             <command>pkill -f ${project.build.finalName}.jar</command>
             <command>nohup /opt/install/hadoop-2.5.2/bin/yarn jar ${target-position}/${project.build.finalName}.jar > /root/nohup.out 2>&amp;1 &amp;</command>
           </commands>
           <!-- 显示运行命令的输出结果 -->
           <displayCommandOutputs>true</displayCommandOutputs>
         </configuration>
 </plugin>

jar:jar wagon:upload wagon:sshexec
  • 本地测试
    https://img-blog.csdnimg.cn/20190417151041880.png
    解决方案
    覆盖NativeIO类,修改access实现,将该方法的实现短路。
public static boolean access(String path, NativeIO.Windows.AccessRight desiredAccess) throws IOException {
    return true;
    //return access0(path, desiredAccess.accessRight());
}

  • 跨平台提交
    项目添加配置文件(从Linux中Hadoop的配置文件中导出)
    在这里插入图片描述
    提交代码需要添加如下
//设置配置信息
conf.addResource("core-site.xml");
conf.addResource("hdfs-site.xml");
conf.addResource("yarn-site.xml");
conf.addResource("mapred-site.xml");
conf.set("mapreduce.job.jar","file:///jar包路径");

  • Maven自定义骨架

程序员根据自己的需求,定义Maven Archetype(骨架),后续选择自定义的骨架,就可以把我们需要的pom,其他配置文件,代码的骨架,自动生成,简化开发与测试

  1. 创建一个模板module
  1. 引入相关jar的坐标
  2. 创建Java代码
  
  在本项目的根下:mvn --settings F:\apache-maven-3.3.9\conf\settings.xml archetype:create-from-project

在这里插入图片描述

  1. 复制骨架的坐标(便于后续的安装)
  <groupId>com.baizhiedu</groupId>
   <artifactId>hadoop-test-archetype</artifactId>
   <version>1.0-SNAPSHOT</version>
  1. 安装骨架
cd target\generated-sources\archetype
 mvn clean install
  1. 创建项目并引入骨架
     需要指定骨架的坐标,来源第二步。
  • MapReduce程序的调试
  1. 建议MR代码中通过Log4进行调试
Logger logger = Logger(xxx.class);
logger.info()

通过上述操作 输出的结果,只能查看job的信息,而Map,Reduce的信息看不到。
需要开启Yarn 历史日志 ,日志归档
  1. yarn集群中如何开启历史日志,日志归档
1. 配置文件
   mapred-site.xml 历史服务
    <property>
        <name>mapreduce.jobhistory.address</name>
       <value>hadoop12.baizhiedu.com:10020</value>
    </property>
     <property>
            <name>mapreduce.jobhistory.webapp.address</name>
            <value>hadoop12.baizhiedu.com:19888</value>
     </property>
   yarn-site.xml 日志聚合
    <property>
        <name>yarn.log-aggregation-enable</name>
        <value>true</value>
    </property>
     <!--秒-->
     <property> 
         <name>yarn.log-aggregation.retain-seconds</name>
         <value>604800</value>
     </property>
2. 启动进程
 sbin/mr-jobhistory-daemon.sh start historyserver
 sbin/mr-jobhistory-daemon.sh stop historyserver
  1. 实战
    应用shell脚本 解决

  2. 关闭日志聚合

  3. etc/hadoop/yarn-env.sh

    export YARN_LOG_DIR=~/logs/yarn
    export YARN_PID_DIR=~/data/yarn
    
  4. 创建脚本

    if [ $# -le 0 ]
    then
        echo 缺少参数
        exit 1
    fi
    
    logtype=out
    
    if [ $# -ge 1 ]
    then
        logtype=${2}
    fi 
    
    for n in `cat /opt/install/hadoop-2.5.2/etc/hadoop/slaves`
    do
        echo ===========查看节点 $n============
        ssh $n "cat ~/logs/yarn/userlogs/${1}/container_*/*${logtype}|grep com.baizhiedu"
    done
    
  5. 运行脚本

    1. 修改脚本权限
    2. ./scanMRLog.sh application_1558968514803_0001
    
  ~~~

4.In/OutputFormat

(1)Split&Record Reader

在这里插入图片描述

(2)In/OutputFormat实战

对接文件系统-(读取):

  • TextInputFormat: (必须掌握)

切片计算 :以文件为单位,对一个文件按照SplitSize计算切片大小(0~140.8 MB)
Key-Value : 行字节偏移量LongWritable | 当前文本行 ,确定Mapper<LongWritable,Text,X,X>

  • NLineInputFormat

切片计算 :以文件为单位,对一个文件按照行切割,默认是1行一个切片
Key-Value : 行字节偏移量LongWritable | 当前文本行 ,确定Mapper<LongWritable,Text,X,X>
mapreduce.input.lineinputformat.linespermap = 10000

  • KeyValueTextInputFormat

切片计算 :以文件为单位,对一个文件按照SplitSize计算切片大小(0~140.8 MB)
Key-Value : Text \t Text ,确定Mapper<Text,Text,X,X>
mapreduce.input.keyvaluelinerecordreader.key.value.separator=|

  • CombineTextInputFormat(小文件计算优化)

切片计算 :对N个文件按照SplitSize计算切片大小(0~140.8 MB),多个文件对应一个切片
Key-Value :行字节偏移量LongWritable | 当前文本行 ,确定Mapper<LongWritable,Text,X,X>

  • MultipleInputs 实现 Join

1、在Map端分别对不同格式的数据定制Mapper和InputFormat
2、所有的Mapper输出KEY-VALUE必须保证一致
3、所有Map输出的KEY必须是 join 字段
4、针对不同的Mapper输出,通过对值做标记,这样才可以在Reduce端区分数据

  • DBOutputFormat(重点)
//1.配置数据链接参数
DBConfiguration.configureDB(conf,
             "driver",
             "url",
             "username",
             "password"
             );
//2.设置任务的写出数据格式
job.setOutputFormatClass(DBOutputFormat.class);
//3.设置数据写出路径
DBOutputFormat.setOutput(job,"t_user_order","id","name","age","items","price");
//4.Reduce端输出的Key类型必须实现DBWritable接口
job.setOutputKeyClass(Class<? extends DBWritable>);

Writable和DBWritable用法

Writable:当自定义Map端输出Value类型,必须实现Writable接口,因为框架将会对Map的输出做本地磁盘的序列化。如果用户需要自定义Map端输出key类型,和值类型相比较多个排序的需求因此如果用户需要自定map端的输出key类型,必须实现WritableComparable接口。

DBWriteable:当用户使用DBOutputFormat时候,强制要求Reducer端的输出key类型必须实现DBWriteable接口,此时需要用户实现write方法给?赋值。通过使用DBOutputFormat可以获知,Reducer端输出的Key-Value类型所限与用户使用的OutputFormat。因此Reduce端的输出key-value类型和Writable接口没有任何关系。

5.Jar包依赖问题

  • 运行时依赖(Yarn Child依赖)

方案1

要求用户将依赖的jar包拷贝给所有的计算节点(NodeManager运行所在主机)

[root@CentOS ~]# hadoop jar xxx.jar 入口类 -libjars 依赖jar包1,依赖jar包2,…
1

方案2

[root@CentOS ~]# hdfs dfs -mkdir /libs
[root@CentOS ~]# hdfs dfs -put mysql-connector-java-5.1.46.jar /libs

conf.setStrings(“tmpjars”,"/libs/xxx1.jar,/libs/xxx2.jar,…");

  • 提交时依赖(client node)

需要用户配置HADOOP_CLASSPATH环境变量(/root/.bashrc),通常这种依赖发生在切片计算阶段。

HADOOP_CLASSPATH=/root/mysql-connector-java-5.1.46.jar
export HADOOP_CLASSPATH
[root@CentOS ~]# source .bashrc 
[root@CentOS ~]# hadoop classpath #查看hadoop的类路径
/usr/hadoop-2.6.0/etc/hadoop:/usr/hadoop-2.6.0/share/hadoop/common/lib/*:/usr/hadoop-2.6.0/share/hadoop/common/*:/usr/hadoop-2.6.0/share/hadoop/hdfs:/usr/hadoop-2.6.0/share/hadoop/hdfs/lib/*:/usr/hadoop-2.6.0/share/hadoop/hdfs/*:/usr/hadoop-2.6.0/share/hadoop/yarn/lib/*:/usr/hadoop-2.6.0/share/hadoop/yarn/*:/usr/hadoop-2.6.0/share/hadoop/mapreduce/lib/*:/usr/hadoop-2.6.0/share/hadoop/mapreduce/*:`/root/mysql-connector-java-5.1.46.jar`:/usr/hadoop-2.6.0/contrib/capacity-scheduler/*.jar

案例参考 DBInputFormat案例。

6.任务提交源码追踪

在这里插入图片描述

job.waitForCompletion(true);
    submit
    	final JobSubmitter submitter =  getJobSubmitter(fs, yarn);
		submitter.submitJobInternal(Job.this, cluster);
				 checkSpecs(job);//检查输出目录是否为null
 				 JobID jobId = submitClient.getNewJobID();//获取jobid
				 copyAndConfigureFiles(job, submitJobDir);//拷贝代码片段以及依赖jars
 				 int maps = writeSplits(job, submitJobDir);//计算切片
  				 writeConf(conf, submitJobFile);//生成job.xml
				 submitClient.submitJob(jobId, submitJobDir,...);
					 ApplicationSubmissionContext appContext =
      createApplicationSubmissionContext(conf, jobSubmitDir, ts);//构建MR AP所需信息
			         resMgrDelegate.submitApplication(appContext);//任务提交

7.OutputFormat(Redis)-自定义输出类型

  • RedisOutpoutFormat
public class RedisOutpoutFormat extends OutputFormat<String,String> {
    public RecordWriter<String, String> getRecordWriter(TaskAttemptContext context) throws IOException, InterruptedException {
        Configuration conf = context.getConfiguration();
        RedisConfiguration redisConf = new RedisConfiguration(conf);
        return new RedisHashRecordWriter(redisConf.getHost(),redisConf.getPort(),redisConf.getDescriptKey());
    }

    public void checkOutputSpecs(JobContext context) throws IOException, InterruptedException { }

    public OutputCommitter getOutputCommitter(TaskAttemptContext context) throws IOException, InterruptedException {
        return new FileOutputCommitter(FileOutputFormat.getOutputPath(context),
                context);
    }
}
  • RedisHashRecordWriter
public class RedisHashRecordWriter extends RecordWriter<String,String> {
    private Jedis jedis;
    private String descriptKey;
    private Pipeline pipeline;

    public RedisHashRecordWriter(String host,int port,String descriptKey) {
        this.jedis = new Jedis(host,port);
        pipeline=jedis.pipelined();
        this.descriptKey=descriptKey;
    }

    public void write(String key, String value) throws IOException, InterruptedException {
        //启用Redis的批处理
        pipeline.hset(descriptKey,key,value);
    }

    public void close(TaskAttemptContext context) throws IOException, InterruptedException {
        pipeline.sync();//批量提交
        jedis.close();//关闭链接
    }
}
  • RedisConfiguration
public class RedisConfiguration {
    private Configuration conf;

    public RedisConfiguration(Configuration conf) {
        this.conf = conf;
    }

    public static final String REDIS_HOST="redis.host";
    public static final String REDIS_PORT="redis.port";
    public static final String REDIS_DESCRIPT_KEY="redis.descriptKey";

    public static void configRedis(Configuration conf,String host,int port,String descriptKey){
        conf.set(REDIS_HOST,host);
        conf.setInt(REDIS_PORT,port);
        conf.set(REDIS_DESCRIPT_KEY,descriptKey);
    }

    public String getHost(){
        return conf.get(REDIS_HOST);
    }
    public int getPort(){
        return conf.getInt(REDIS_PORT,6379);
    }
    public String getDescriptKey(){
        return conf.get(REDIS_DESCRIPT_KEY);
    }
}
  • 代码中使用如下
public class CustomJobSubmitter extends Configured implements Tool {
    public int run(String[] strings) throws Exception {
        //1.封装Job对象\
        Configuration conf = getConf();
        RedisConfiguration.configRedis(conf,
                                       "CentOS",
                                       6379,
                                       "url_click");
        Job job=Job.getInstance(conf);
        //2.设置任务的读取、写出数据格式
        job.setInputFormatClass(TextInputFormat.class);
        job.setOutputFormatClass(RedisOutpoutFormat.class);
        //3.设置数据读入和写出路径
        Path src = new Path("file:///D:/demo/click");
        TextInputFormat.addInputPath(job,src);
        //4.设置数据处理逻辑代码片段
        job.setMapperClass(ClickMappper.class);
        job.setReducerClass(ClickReducer.class);
        //5.设置Mapper和Reducer输出key-value类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);

        job.setOutputKeyClass(String.class);
        job.setOutputValueClass(String.class);
        //6.任务提交
        //job.submit();
        job.waitForCompletion(true);
        return 0;
    }
    public static void main(String[] args) throws Exception {
        ToolRunner.run(new CustomJobSubmitter(),args );
    }
}

8.Shuffle&任务调优

NumReduceTask = 0

在这里插入图片描述

public class CustomJobSubmitter extends Configured implements Tool {
    public int run(String[] strings) throws Exception {
        //1.封装Job对象
        Job job=Job.getInstance(getConf());

        //2.设置任务的读取、写出数据格式
        job.setInputFormatClass(TextInputFormat.class);
        job.setOutputFormatClass(TextOutputFormat.class);
        //3.设置数据读入和写出路径
        Path src = new Path("file:///D:/demo/click");
        TextInputFormat.addInputPath(job,src);

        Path dst = new Path("file:///D:/demo/result");//必须不存在,否则任务提交失败
        TextOutputFormat.setOutputPath(job,dst);
        //4.设置数据处理逻辑代码片段
        job.setMapperClass(ClickMappper.class);
        //5.设置Mapper和Reducer输出key-value类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(Text.class);

        job.setNumReduceTasks(0);//设置NumReducecTask 0
        //6.任务提交
        //job.submit();
        job.waitForCompletion(true);
        return 0;
    }
    public static void main(String[] args) throws Exception {
        ToolRunner.run(new CustomJobSubmitter(),args );
    }
}
NumReduceTask = 3

在这里插入图片描述

  • 如何干预MapReduce分区策略?

job.setPartitionerClass(…)

  • MapReduce输出特点是什么?

分区内部有序,默认按照Map端输出key的升序

  • 什么是Mapreduce数据倾斜?

是因为选取的Key不合理,到时分区数据分布不均匀。在任务计算第二阶段Reduce计算带来压力。

  • Reduce并行度是靠什么决定的?和Map端计算区别是什么?

Map端并行度是通过计算任务切片决定的,Reduce端是通过job.setNumReduceTask(n)

  • MapReduce调优策略

1.避免小文件计算,适当线下合并
2.调整环装缓冲区的参数,减少Map任务的IO操作
3.开启Map段压缩

conf.setBoolean("mapreduce.map.output.compress",true);
conf.setClass("mapreduce.map.output.compress.codec", GzipCodec.class, CompressionCodec.class);

4.如果条件允许,可以考虑在Map端预执行Reduce逻辑-Map端的Combiner

是一种针对Mapshuffle的优化,主要是通过在Map端本地支持局部Reduce操作,该操作可以极大减轻网络IO占用,减少key的排序量,但是并不是所有的操作都支持Combiner:

  • Combiner默认不会开启,需要程序员编码设置
  • 要求Combiner不可以改变Map端最终的输出key-value类型(Combiner输入和输出类型一致)
  • 必须满足计算支持迭代,例如:求和、最大值、最小值 ,但是 平均值就不适用
    job.setCombinerClass(ClickCombiner.class);
public class ClickCombiner extends Reducer<Text, IntWritable,Text,IntWritable> {
       @Override
       protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
           System.out.println("--ClickCombiner---");
           int total=0;
           for (IntWritable value : values) {
               total += value.get() ;
           }
           context.write(key,new IntWritable(total));
       }
}

5.适当调整NodeManager管理Container的个数和内存大小

yarn.nodemanager.resource.cpu-vcores = 8
yarn.nodemanager.resource.memory-mb = 8192 

9.Map Reduce 使用场景

  • 网络日志清洗数据 ETL (Extract Transfer Load),一般这种操作不需要Reduce即可完成

  • 基于大数据数据统计和报表 求最大、求最小、求平均 使用柱状图、饼状图展示。

  • 画像生成-为后续AI学习提供计算所需数据模型 特征向量 线性回归|逻辑回归

  • 个性化推荐 通过MapReduce 生成算法所需数据样本
    基于用户的协同推荐算法
    基于物品协同过滤算法(比较多)
    数据格式(MapReduce ETL或者统计得来)

userid/itemid/score

1,101,5.0
1,102,3.0
1,103,2.5
2,101,2.0
2,102,2.5
2,103,5.0
2,104,2.0
3,101,2.5
3,104,4.0
3,105,4.5
3,107,5.0
4,101,5.0
4,103,3.0
4,104,4.5
4,106,4.0
5,101,4.0
5,102,3.0
5,103,2.0
5,104,4.0
5,105,3.5
5,106,4.0
  • 安装Mahout(下载Mahout算法库)
[root@CentOS ~]# tar -zxf apache-mahout-distribution-0.13.0.tar.gz -C /usr/
  • 将准备好的数据存储到/recomand
  • 调用Mahout的推荐算法(MapReduce任务实现的算法,该算法分为4个阶段,共计9个MapReduce任务)
[root@CentOS ~]# hadoop jar /usr/apache-mahout-distribution-0.13.0/mahout-mr-0.13.0-job.jar org.apache.mahout.cf.taste.hadoop.item.RecommenderJob --input /recomand --output /recomand-out -s SIMILARITY_LOGLIKELIHOOD
1	[104:2.8088317,106:2.5915816,105:2.5748677]
2	[105:3.5743618,106:3.3991857]
3	[103:4.336442,106:4.0915813,102:4.0915813]
4	[102:3.6903737,105:3.6903737]
5	[107:3.663558]

10.Hadoop HA构建

概述
  • NameNode HA构建 存储

  • ResourceManager HA构建 计算
    在这里插入图片描述

准备工作

安装三台CentOS-6.5 64 bit操作系统(完成JDK、SSH免密码认证、IP主机名映射、关闭防火墙等工作)
主机和服务启动映射表

主机 服务
CentOSA NameNode、zkfc、DataNode、JournalNode、Zookeeper、NodeManager
CentOSB NameNode、zkfc、DataNode、JournalNode、Zookeeper、NodeManager、ResourceManager
CentOSC DataNode、JournalNode、Zookeeper、NodeManager、ResourceManager
主机信息

主机名 IP信息
CentOSA 192.168.40.129
CentOSB 192.168.40.130
CentOSC 192.168.40.131
JDK安装和配置

[root@CentOSX ~]# rpm -ivh jdk-8u171-linux-x64.rpm
[root@CentOSX ~]# vi .bashrc
JAVA_HOME=/usr/java/latest
PATH=$PATH:$JAVA_HOME/bin
CLASSPATH=.
export JAVA_HOME
export CLASSPATH
export PATH
[root@CentOSX ~]# source .bashrc

IP主机名映射

[root@CentOSX ~]# vi /etc/hosts

192.168.40.129 CentOSA
192.168.40.130 CentOSB
192.168.40.131 CentOSC

关闭防火墙

[root@CentOSX ~]# service iptables stop
iptables: Setting chains to policy ACCEPT: filter          [  OK  ]
iptables: Flushing firewall rules:                         [  OK  ]
iptables: Unloading modules:                               [  OK  ]
[root@CentOSX ~]# chkconfig iptables off

SSH免密码认证

[root@CentOSX ~]# ssh-keygen -t rsa
[root@CentOSX ~]# ssh-copy-id CentOSA
[root@CentOSX ~]# ssh-copy-id CentOSB
[root@CentOSX ~]# ssh-copy-id CentOSC

Zookeeper

[root@CentOSX ~]# tar -zxf zookeeper-3.4.6.tar.gz -C /usr/
[root@CentOSX ~]# mkdir /root/zkdata

[root@CentOSA ~]# echo 1 >> /root/zkdata/myid
[root@CentOSB ~]# echo 2 >> /root/zkdata/myid
[root@CentOSC ~]# echo 3 >> /root/zkdata/myid

[root@CentOSX ~]# touch /usr/zookeeper-3.4.6/conf/zoo.cfg
[root@CentOSX ~]# vi /usr/zookeeper-3.4.6/conf/zoo.cfg
tickTime=2000
dataDir=/root/zkdata
clientPort=2181
initLimit=5
syncLimit=2
server.1=CentOSA:2887:3887
server.2=CentOSB:2887:3887
server.3=CentOSC:2887:3887

[root@CentOSX ~]# /usr/zookeeper-3.4.6/bin/zkServer.sh start zoo.cfg
[root@CentOSX ~]# /usr/zookeeper-3.4.6/bin/zkServer.sh status zoo.cfg
JMX enabled by default
Using config: /usr/zookeeper-3.4.6/bin/../conf/zoo.cfg
Mode: `follower|leader`
[root@CentOSX ~]# jps
5879 `QuorumPeerMain`
7423 Jps
搭建Hadoop 集群(HDFS)

解压并配置HADOOP_HOME

[root@CentOSX ~]# tar -zxf hadoop-2.6.0_x64.tar.gz -C /usr/
[root@CentOSX ~]# vi .bashrc
HADOOP_HOME=/usr/hadoop-2.6.0
JAVA_HOME=/usr/java/latest
PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
CLASSPATH=.
export JAVA_HOME
export CLASSPATH
export PATH
export HADOOP_HOME
[root@CentOSX ~]# source .bashrc

配置core-site.xml

<!--配置Namenode服务ID-->
<property>		
      <name>fs.defaultFS</name>		
      <value>hdfs://mycluster</value>	
</property>
<property>		
     <name>hadoop.tmp.dir</name>		
     <value>/usr/hadoop-2.6.0/hadoop-${user.name}</value>    
</property>
<property>		
     <name>fs.trash.interval</name>		
     <value>30</value>    
</property>
<!--配置机架脚本-->
<property>		
     <name>net.topology.script.file.name</name>		
     <value>/usr/hadoop-2.6.0/etc/hadoop/rack.sh</value>    
</property>
<!--配置ZK服务信息-->
<property>   
	<name>ha.zookeeper.quorum</name>
	<value>CentOSA:2181,CentOSB:2181,CentOSC:2181</value> 
</property>
<!--配置SSH秘钥位置-->
<property>
     <name>dfs.ha.fencing.methods</name>
     <value>sshfence</value>
</property>
<property>
     <name>dfs.ha.fencing.ssh.private-key-files</name>
     <value>/root/.ssh/id_rsa</value>
</property>

配置机架脚本

[root@CentOSX ~]# touch /usr/hadoop-2.6.0/etc/hadoop/rack.sh
[root@CentOSX ~]# chmod u+x /usr/hadoop-2.6.0/etc/hadoop/rack.sh
[root@CentOSX ~]# vi /usr/hadoop-2.6.0/etc/hadoop/rack.sh
while [ $# -gt 0 ] ; do
	  nodeArg=$1
	  exec</usr/hadoop-2.6.0/etc/hadoop/topology.data
	  result="" 
	  while read line ; do
		ar=( $line ) 
		if [ "${ar[0]}" = "$nodeArg" ] ; then
		  result="${ar[1]}"
		fi
	  done 
	  shift 
	  if [ -z "$result" ] ; then
		echo -n "/default-rack"
	  else
		echo -n "$result "
	  fi
done
[root@CentOSX ~]# touch /usr/hadoop-2.6.0/etc/hadoop/topology.data
[root@CentOSX ~]# vi /usr/hadoop-2.6.0/etc/hadoop/topology.data
192.168.40.129 /rack01
192.168.40.130 /rack01
192.168.40.131 /rack03

配置hdfs-site.xml

<property>
	<name>dfs.replication</name>
	<value>3</value>
</property> 
<!--开启自动故障转移-->
<property>
	<name>dfs.ha.automatic-failover.enabled</name>
	<value>true</value>
</property>
<!--解释core-site.xml内容-->
<property>
	<name>dfs.nameservices</name>
	<value>mycluster</value>
</property>
<property>
	<name>dfs.ha.namenodes.mycluster</name>
	<value>nn1,nn2</value>
</property>
<property>
	<name>dfs.namenode.rpc-address.mycluster.nn1</name>
	<value>CentOSA:9000</value>
</property>
<property>
	 <name>dfs.namenode.rpc-address.mycluster.nn2</name>
	 <value>CentOSB:9000</value>
</property>
<!--配置日志服务器的信息-->
<property>
  <name>dfs.namenode.shared.edits.dir</name>
  <value>qjournal://CentOSA:8485;CentOSB:8485;CentOSC:8485/mycluster</value>
</property>
<!--实现故障转切换的实现类-->
<property>
	<name>dfs.client.failover.proxy.provider.mycluster</name>
	<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>

配置slaves

CentOSA
CentOSB
CentOSC

启动HDFS(集群初始化启动)

[root@CentOSX ~]# hadoop-daemon.sh start journalnode (等待10s钟)
[root@CentOSA ~]# hdfs namenode -format
[root@CentOSA ~]# hadoop-daemon.sh start namenode
[root@CentOSB ~]# hdfs namenode -bootstrapStandby
[root@CentOSB ~]# hadoop-daemon.sh start namenode
#注册Namenode信息到zookeeper中,只需要在CentOSA或者B上任意一台执行一下指令
[root@CentOSA|B ~]# hdfs zkfc -formatZK
[root@CentOSA ~]# hadoop-daemon.sh start zkfc
[root@CentOSB ~]# hadoop-daemon.sh start zkfc
[root@CentOSX ~]# hadoop-daemon.sh start datanode

查看机架信息

[root@CentOSB ~]# hdfs dfsadmin -printTopology
Rack: /rack01
   192.168.40.129:50010 (CentOSA)
   192.168.40.130:50010 (CentOSB)

Rack: /rack03
   192.168.40.131:50010 (CentOSC)
Resource Manager搭建

yarn-site.xml

<property>
    <name>yarn.nodemanager.aux-services</name>
    <value>mapreduce_shuffle</value>
</property>
<property>
    <name>yarn.resourcemanager.ha.enabled</name>
    <value>true</value>
</property>
<property>
    <name>yarn.resourcemanager.cluster-id</name>
    <value>cluster</value>
</property>
<property>
    <name>yarn.resourcemanager.ha.rm-ids</name>
    <value>rm1,rm2</value>
</property>
<property>
    <name>yarn.resourcemanager.hostname.rm1</name>
    <value>CentOSB</value>
</property>
<property>
    <name>yarn.resourcemanager.hostname.rm2</name>
    <value>CentOSC</value>
</property>
<property>
    <name>yarn.resourcemanager.zk-address</name>
    <value>CentOSA:2181,CentOSB:2181,CentOSC:2181</value>
</property>

mapred-site.xml

<property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
</property>

启动|关闭Yarn服务

[root@CentOSB ~]# yarn-daemon.sh start|stop resourcemanager
[root@CentOSC ~]# yarn-daemon.sh start|stop resourcemanager
[root@CentOSX ~]# yarn-daemon.sh start|stop nodemanger
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值